<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>npry</title>
    <link rel="self" type="application/atom+xml" href="https://blog.npry.dev/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://blog.npry.dev"/>
    <updated>2026-02-04T00:00:00+00:00</updated>
    <id>https://blog.npry.dev/atom.xml</id>
    
    <entry xml:lang="en">
        <title>self-signing librewolf</title>
        <published>2026-02-04T00:00:00+00:00</published>
        <updated>2026-02-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/1pass-codesign/"/>
        <id>https://blog.npry.dev/1pass-codesign/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/1pass-codesign/">&lt;p&gt;I use &lt;a href=&quot;https:&#x2F;&#x2F;librewolf.net&quot;&gt;LibreWolf&lt;&#x2F;a&gt; as my daily driver web browser and
&lt;a href=&quot;https:&#x2F;&#x2F;1password.com&quot;&gt;1Password&lt;&#x2F;a&gt; as my password manager. Notionally,
1Password supports integration between the browser extension and the desktop
app via native messaging, but this traditionally didn&#x27;t work for non-blessed
browsers (Chrome, Firefox, Safari, eventually Brave and Arc).&lt;&#x2F;p&gt;
&lt;p&gt;This is to protect against anything else on your computer pretending to &lt;em&gt;be&lt;&#x2F;em&gt;
the browser and stealing all your credentials, since the pipe provided by the
native messaging host is privileged and has complete access to whatever vaults
are decrypted in the native app. The NMH checks both browser identity and code
signature validity to ensure that its parent process really is the browser it
says it is.&lt;&#x2F;p&gt;
&lt;p&gt;Recently, Agilebits has opened up the ability for end users to add entries to
their local browser whitelist -- they did this on Linux and macOS first, but
the change was also recently rolled out to Windows, which is my
lowest-potential-energy OS platform. I was excited to finally not have
to sign into the browser extension every 10 minutes, but unfortunately, LibreWolf
&lt;a href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;librewolf&#x2F;issues&#x2F;issues&#x2F;2664&quot;&gt;doesn&#x27;t yet provide code-signed executables&lt;&#x2F;a&gt;,
though they&#x27;re working with &lt;a href=&quot;https:&#x2F;&#x2F;ossign.org&quot;&gt;OSSign&lt;&#x2F;a&gt; to remedy this (who appear
to be swamped with requests for certs). In the meantime, the 1Password browser
integration doesn&#x27;t work because the code signature check fails.&lt;&#x2F;p&gt;
&lt;p&gt;I resolved this by creating a local self-signed cert, adding it as a root CA,
and signing the executable myself. Evidently, 1Password doesn&#x27;t embed its
own CA trust bundle, because this works fine.&lt;&#x2F;p&gt;
&lt;p&gt;In an admin PowerShell session:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-comment z-line z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;#&lt;&#x2F;span&gt; create cert&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-redirection z-powershell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;New-SelfSignedCertificate&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;DnsName you&lt;span class=&quot;z-variable z-other z-readwrite z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-powershell&quot;&gt;@&lt;&#x2F;span&gt;name&lt;span class=&quot;z-variable z-other z-member z-powershell&quot;&gt;.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Type CodeSigning &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;CertStoreLocation cert:\CurrentUser\My
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-comment z-line z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;#&lt;&#x2F;span&gt; reimport the cert as a trusted publisher and root ca&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-redirection z-powershell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Export-Certificate&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Cert &lt;span class=&quot;z-punctuation z-section z-group z-begin z-powershell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-interpolated z-simple z-source z-powershell&quot;&gt;&lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Get-ChildItem&lt;&#x2F;span&gt; Cert:\CurrentUser\My &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;CodeSigningCert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-powershell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-bracket z-begin z-powershell&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-powershell&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-bracket z-end z-powershell&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;FilePath codesigning.crt
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-redirection z-powershell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Import-Certificate&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;FilePath codesigning.crt &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Cert Cert:\CurrentUser\TrustedPublisher
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-redirection z-powershell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Import-Certificate&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;FilePath codesigning.crt &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Cert Cert:\CurrentUser\Root
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-comment z-line z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;#&lt;&#x2F;span&gt; sign librewolf executable&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-redirection z-powershell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; signtool sign &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;a &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;fd SHA256 &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;tr http:&lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-powershell&quot;&gt;timestamp.digicert.com&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;td SHA256 &lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;C:\Program Files\LibreWolf\librewolf.exe&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Obviously, be careful with the self-signed cert, since your system now trusts
any software and TLS connections signed with it. You&#x27;ll need &lt;code&gt;signtool&lt;&#x2F;code&gt; as well
this, which is part of the Windows SDK, but &lt;a href=&quot;&#x2F;signtool.exe&quot;&gt;here&#x27;s mine&lt;&#x2F;a&gt;
(Microsoft code signature intact) -- it seems to work fine standalone.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>site defense</title>
        <published>2025-10-24T00:00:00+00:00</published>
        <updated>2025-10-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/site-defense/"/>
        <id>https://blog.npry.dev/site-defense/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/site-defense/">&lt;p&gt;Long story short: I blacklisted most of the world from accessing the HTML
render of my nixpkgs fork on &lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&quot;&gt;pub.npry.dev&lt;&#x2F;a&gt;, since
crawlers mostly in Asia (India, China, and Singapore) wouldn&#x27;t respect my
&lt;code&gt;robots.txt&lt;&#x2F;code&gt;. They were continuously scraping the HTML pages listing the code
for &lt;code&gt;nixpkgs&lt;&#x2F;code&gt;, which is famously a very large repo. These are dynamically
rendered by pygments, which was sitting at 100% CPU (single core) syntax
highlighting thousands of large Nix derivations, which was stalling out my
browsing of my own website.&lt;&#x2F;p&gt;
&lt;p&gt;I had previously addressed this problem via an &lt;a href=&quot;..&#x2F;rdap&quot;&gt;automated rdap tool&lt;&#x2F;a&gt;,
but this only emitted logs that I later integrated into my nixpkgs config.
This required ongoing manual maintenance to keep things working, and the
problem was never really access to my sites, just this pathological scraping
behavior in large repos — I figured a geo-IP solution would work. This
was easier to do than I expected — the &lt;a href=&quot;https:&#x2F;&#x2F;maxmind.com&quot;&gt;MaxMind&lt;&#x2F;a&gt;
databases are free, and there&#x27;s a NixOS module for downloading and updating
them: &lt;code&gt;services.geoipupdate&lt;&#x2F;code&gt; — the keys are straightforward to integrate
through {sops,age}-nix.&lt;&#x2F;p&gt;
&lt;p&gt;Nginx gets:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;services&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;nginx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;additionalModules&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal z-reserved z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;nginxModules&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;geoip2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And a config like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nginx&quot; class=&quot;language-nginx z-code&quot;&gt;&lt;code class=&quot;language-nginx&quot; data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;geoip2 $PATH&#x2F;GeoLite2-Country.mmdb {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    auto_reload 5m;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    $geoip_continent_code continent code;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;map $geoip_continent_code $geo_continent_allow {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    default no;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    NA yes;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    EU yes;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    AN yes;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And you can geofilter anything:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nginx&quot; class=&quot;language-nginx z-code&quot;&gt;&lt;code class=&quot;language-nginx&quot; data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;location &#x2F;nixpkgs {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    if ($geo_continent_allow = no) {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        return 444;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>thesis: interstice</title>
        <published>2025-05-29T00:00:00+00:00</published>
        <updated>2025-05-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/thesis/"/>
        <id>https://blog.npry.dev/resenv/thesis/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/thesis/">&lt;object data=&quot;perry-npry-sm-mas-2025-thesis.pdf&quot; type=&quot;application&#x2F;pdf&quot; style=&quot;width: 100%; height: 800px&quot;&gt;
    &lt;a href=&quot;perry-npry-sm-mas-2025-thesis.pdf&quot;&gt;Thesis Manuscript (PDF)&lt;&#x2F;a&gt;
&lt;&#x2F;object&gt;
&lt;p&gt;(dspace link pending)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary-reflections&quot;&gt;summary &amp;amp; reflections&lt;&#x2F;h2&gt;
&lt;p&gt;Your newline-delimited Arduino serial data stream actually wants to be a
sequence of network frames. You don&#x27;t really care how the data gets to your
host computer, how it&#x27;s delimited, how it&#x27;s framed, how it&#x27;s buffered, what
baud rate to use, how to bridge it between neighboring nodes: your application
concerns are interpreting sensor data and sending control commands. But you&#x27;re
going to spend a lot of time and effort manually solving these problems anyway.
It sure seems like something like IP over an existing link layer would be nice,
since it solves all of this for you: these are actually core networking
problems. The thesis develops multihop point-to-point IP networks
over PPP on top of various serial links.&lt;&#x2F;p&gt;
&lt;p&gt;It partially gets there. It does what it says on the tin, but not much more
— I actually spent most of my implementation effort reading, patching,
debugging, and testing third-party embedded Rust code, which I found to be at a
much lower state of readiness than I had anticipated when starting out. I trapped
myself between &quot;it&#x27;s almost working&quot; and sunk cost fallacy for a very long time,
and so the networking results, analysis, and thesis writeup are as a whole
anemic and underdeveloped. I probably have a whole additional thesis worth of
writing about embedded Rust and considerations for designing firmware in the
language (lots of reflection about allocation strategies, dealing with
lifetimes, monomorphization vs dynamic dispatch, suggestions and sketches of
new libraries), but this discussion didn&#x27;t align with my committee or my
proposed thesis plan, so it&#x27;s largely left out from the manuscript. I will
probably come back and organize those thoughts here.&lt;&#x2F;p&gt;
&lt;p&gt;In retrospect, what the thesis (&lt;em&gt;qua&lt;&#x2F;em&gt; networking thesis) actually wanted was a
stable, battle-tested networking stack (e.g. lwIP) with an existing, bug-free
PPP implementation and a distance-vector router (probably AODV). Likely I could
have gotten things running way faster this way, and could have spent a lot more
time investigating the actual networking concerns rather than debugging someone
else&#x27;s code. I&#x27;m happy with having used Rust, but probably this would have been
more practical.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;previous-content&quot;&gt;previous content&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;resenv&#x2F;thesis&#x2F;proposal.pdf&quot;&gt;proposal&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;resenv&#x2F;thesis&#x2F;abstract&quot;&gt;submitted abstract&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;resenv&#x2F;thesis&#x2F;pitch&quot;&gt;pitch&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>embassy-sync, lock-api mutex compat</title>
        <published>2025-02-13T00:00:00+00:00</published>
        <updated>2025-02-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/embassy-rawmutex/"/>
        <id>https://blog.npry.dev/embassy-rawmutex/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/embassy-rawmutex/">&lt;p&gt;I spent a bunch of time today trying to figure out why &lt;code&gt;embassy&lt;&#x2F;code&gt; (an embedded
async runtime in Rust) forked the &lt;code&gt;RawMutex&lt;&#x2F;code&gt; and &lt;code&gt;Mutex&lt;&#x2F;code&gt; code from
&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;lock_api&#x2F;latest&#x2F;lock_api&#x2F;&quot;&gt;&lt;code&gt;lock_api&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. This makes it incompatible
with foreign types implementing &lt;code&gt;RawMutex&lt;&#x2F;code&gt;, such as &lt;code&gt;flipperzero&lt;&#x2F;code&gt;&#x27;s
&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;flipperzero&#x2F;latest&#x2F;flipperzero&#x2F;furi&#x2F;sync&#x2F;struct.FuriMutex.html&quot;&gt;&lt;code&gt;FuriMutex&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I wrote up a draft GitHub issue as I figured this out, thinking I had solved the
issue. That appears below — at the end of this post, I explain what I actually
figured out. Honestly, I&#x27;m mostly making this a blog post to preserve this issue
that I spent several hours researching.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;original-draft-post&quot;&gt;Original (draft) post&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m doing a bit of work on the Flipper Zero, the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;flipperzero-rs&#x2F;flipperzero&quot;&gt;rust
crate&lt;&#x2F;a&gt; for which provides a
&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;flipperzero&#x2F;latest&#x2F;flipperzero&#x2F;furi&#x2F;sync&#x2F;struct.FuriMutex.html&quot;&gt;&lt;code&gt;Mutex&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
that implements
&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;lock_api&#x2F;0.4.12&#x2F;lock_api&#x2F;trait.RawMutex.html&quot;&gt;&lt;code&gt;lock_api::RawMutex&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
I have some previous firmware functionality written against &lt;code&gt;embassy&lt;&#x2F;code&gt; that I&#x27;m
porting to the Flipper, and I started looking into using that &lt;code&gt;Mutex&lt;&#x2F;code&gt; type to
back an &lt;code&gt;embassy_sync::Mutex&lt;&#x2F;code&gt; for async support.&lt;&#x2F;p&gt;
&lt;p&gt;I noticed that &lt;code&gt;embassy_sync::blocking&lt;&#x2F;code&gt; is a fork of &lt;code&gt;lock_api&lt;&#x2F;code&gt; with a scoped
&lt;code&gt;lock()&lt;&#x2F;code&gt; (rather than lock + unlock). I &lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&#x2F;embassy&#x2F;commit&#x2F;?id=74bb3a305&quot;&gt;patched my embassy
fork&lt;&#x2F;a&gt; to replace this with
&lt;code&gt;lock_api&lt;&#x2F;code&gt; and haven&#x27;t noticed any adverse effects -- all the &lt;code&gt;embassy_sync&lt;&#x2F;code&gt;
tests pass and empirically, &lt;code&gt;embassy_sync::Mutex&lt;&#x2F;code&gt; works as expected.&lt;&#x2F;p&gt;
&lt;p&gt;Looking at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;embassy-rs&#x2F;embassy&#x2F;issues&#x2F;3175&quot;&gt;#3175&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;jamesmunns&#x2F;6052ba03e28d2013fc33b718a6416df0&quot;&gt;this
gist&lt;&#x2F;a&gt; that
was linked there, the problem they&#x27;re solving appears to be essentially about
reentrancy wrt. critical sections. For the sake of argument, let&#x27;s consider an
impl of &lt;code&gt;lock_api::RawMutex&lt;&#x2F;code&gt; for &lt;code&gt;CriticalSectionRawMutex&lt;&#x2F;code&gt; that disallows
reentrancy (this is essentially what I have in my patch):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;pub&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-struct z-rust&quot;&gt;struct&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;CriticalSectionRawMutex&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-rust&quot;&gt;inner&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-type z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;UnsafeCell&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Option&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;critical_section&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;RestoreState&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-impl z-rust&quot;&gt;impl&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;lock_api&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;RawMutex &lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;for&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt; &lt;span class=&quot;z-entity z-name z-impl z-rust&quot;&gt;CriticalSectionRawMutex&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; ...
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;self&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;while&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-rust&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-rust&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;try_lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;try_lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;self&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; state &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;critical_section&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;acquire&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; SAFETY: inner is only accessed within a critical section, which means single,
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; non-concurrent-access is guaranteed
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; inner &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-rust&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;inner&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;if&lt;&#x2F;span&gt; inner&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;is_some&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;            &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;critical_section&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;release&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-rust&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;&#x2F;span&gt;inner &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-constant z-language z-rust&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;unlock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;self&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;            &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; inner &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-rust&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;inner&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;            &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; state &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; inner&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;take&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;unwrap_unchecked&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;            &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;critical_section&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;release&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(Notably, this design differs from the existing &lt;code&gt;CriticalSectionRawMutex&lt;&#x2F;code&gt; in
that I&#x27;m tracking the acquire&#x2F;release state explicitly rather than using the
closure form in &lt;code&gt;critical_section::with&lt;&#x2F;code&gt;.)&lt;&#x2F;p&gt;
&lt;p&gt;As far as I can tell, this has the properties we want — a single
&lt;code&gt;CriticalSectionRawMutex&lt;&#x2F;code&gt; &lt;em&gt;isn&#x27;t&lt;&#x2F;em&gt; reentrant (i.e. we can&#x27;t re-&lt;code&gt;lock&lt;&#x2F;code&gt; the same
mutex without first unlocking it), but the &quot;global reentrancy&quot; of
&lt;code&gt;critical_section&lt;&#x2F;code&gt; is preserved (multiple mutexes can be taken at once). I.e.,
this doesn&#x27;t work (as desired):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; mutex &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;lock_api&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Mutex&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;CriticalSectionRawMutex, &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;new&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;mutex&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;mutex&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; spins forever
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But this does:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; mutex1 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;lock_api&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Mutex&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;CriticalSectionRawMutex, &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;new&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; mutex2 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;lock_api&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Mutex&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;CriticalSectionRawMutex, &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;new&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;mutex1&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;mutex2&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;resolution&quot;&gt;Resolution&lt;&#x2F;h2&gt;
&lt;p&gt;This actually doesn&#x27;t satisfy the requirements for &lt;code&gt;critical_section&lt;&#x2F;code&gt;,
specifically because it has the potential to violate nesting. While
the above example will work because the underlying &lt;code&gt;RestoreState&lt;&#x2F;code&gt;s will
be released in the correct nesting order, this is trivially violated:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; mutex1 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;lock_api&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Mutex&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;CriticalSectionRawMutex, &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;new&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; mutex2 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;lock_api&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Mutex&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;CriticalSectionRawMutex, &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;new&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;mutex1&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;mutex2&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Wrong order!
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;mutex1&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;unlock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;mutex2&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;unlock&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is the critical issue with this approach that requires
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tosc-rs&#x2F;scoped-mutex&quot;&gt;&lt;code&gt;scoped_mutex&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>schematic (pset 3)</title>
        <published>2024-10-22T00:00:00+00:00</published>
        <updated>2024-10-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/smallmfg/schematic/"/>
        <id>https://blog.npry.dev/class/smallmfg/schematic/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/smallmfg/schematic/">&lt;p&gt;@carboxyl: this page is available on my blog if you&#x27;re interested in following
any of the hyperlinks:
&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;smallmfg&#x2F;market-research&quot;&gt;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;smallmfg&#x2F;market-research&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This problem set is intended to help you move towards a final electrical design, so
PCBs can be made (if needed). Bring a hard copy to turn in during class on the due
date.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Please put together a schematic of what you intend to build, and a description of its
various subcomponents (power, charging, battery, sensing, computation, UI,
amplifiers, etc). Give rough estimates of important quantites (battery life, noise floor,
sensitivity, processing time, etc). It is okay if your project will be made of dev-
boards or other purchases subassemblies, but be sure to include how they will be
interconnected and their performance attributes.&lt;&#x2F;li&gt;
&lt;li&gt;Schedule a time to meet with me to discuss your project (~1h). We will go over
where you are currently at, and how to best proceed.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;smallmfg&#x2F;schematic&#x2F;schematic.pdf&quot;&gt;schematic pdf&lt;&#x2F;a&gt; (printed &#x2F; attached to physical turnin)&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;block.2a31979df821660d.jpg&quot;&gt;

    
    &lt;i style=&quot;margin-top: 0.5rem&quot;&gt;
        &lt;p&gt;block diagram&lt;&#x2F;p&gt;

    &lt;&#x2F;i&gt;
    
&lt;&#x2F;div&gt;
&lt;p&gt;sniffa will be designed around a fabricated PCB with the following (major)
components:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ESP32C6 microcontroller (WiFi, 802.15.4, BLE, USB, SPI, I2C, UART onboard)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;$3 in low quantities for the
&lt;a href=&quot;https:&#x2F;&#x2F;www.digikey.com&#x2F;en&#x2F;products&#x2F;detail&#x2F;espressif-systems&#x2F;ESP32-C6-WROOM-1U-N8&#x2F;20685870&quot;&gt;module&lt;&#x2F;a&gt;
with integrated flash&lt;&#x2F;li&gt;
&lt;li&gt;High (&amp;lt;= 160MHz) and low (&amp;lt;= 20MHz) power cores&lt;&#x2F;li&gt;
&lt;li&gt;7 uA deep sleep, &amp;lt;1mA light sleep, 25mA modem sleep, 40mA (HP core),
300mA WiFi tx (active), 80mA WiFi rx (active)&lt;&#x2F;li&gt;
&lt;li&gt;Full IO matrix&lt;&#x2F;li&gt;
&lt;li&gt;Event&#x2F;task matrix&lt;&#x2F;li&gt;
&lt;li&gt;21 available GPIOs&lt;&#x2F;li&gt;
&lt;li&gt;7 ADC lines&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.digikey.com&#x2F;en&#x2F;products&#x2F;detail&#x2F;texas-instruments&#x2F;BQ25185DLHR&#x2F;21769368&quot;&gt;BQ25185DLHR&lt;&#x2F;a&gt;:
1S LiPo battery regulator supporting VUSB charging with 4.5V regulated output&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;~$1 in quantity&lt;&#x2F;li&gt;
&lt;li&gt;Supports up to 3A on the VSYS output&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;3V3 buck for the regulator^ VSYS output, rated for 1A -- dedicated to internal power&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;3V3 buck and 5V boost for external power, 1A each&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;LDO as stable ADC VREF&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Optional, analog monitoring is just a nice-to-have&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;5V level shifters&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Battery (4000mAh, 1S): &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B095HD7JCR&quot;&gt;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B095HD7JCR&lt;&#x2F;a&gt;, $17 -- aiming
for at least 8h of runtime while powering a low-ish power (~ sensor node, no
major actuation) device for testing, think this could be scaled back&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Target performance is 40MHz SPI (slave + master), 1MHz I2C, 1MBaud UART with
DMA. The esp32c6 can do all of these except I2C, which is capped at 400kHz, but
it was the best tradeoff I could find (as it comes in a module and has
integrated networking).&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s 5MB&#x2F;s at full SPI rates, and I probably can&#x27;t simultaneously get that
performance out of the 2.4GHz WiFi connection, so there&#x27;s a tradeoff to be made
re: buffering that comes down to the practical distribution of traffic
throughputs in normal use for the device, compared to WiFi link speed. Most of
the usage profile I understand for a device like this is on the order of 1%
link budget utilization or less — most projects simply don&#x27;t need to read
from a bus that often, and even when they do, it&#x27;s not very much data per
transaction. I estimate that a 64kB data buffer is probably way overkill here,
and the ESP32C6 has 512kB of RAM, so there&#x27;s plenty of margin on top of that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;i-o-protection&quot;&gt;I&#x2F;O protection&lt;&#x2F;h2&gt;
&lt;p&gt;I thought about a few ways to do protection on the I&#x2F;Os — the usage model
for a device like this should really account for users accidentally plugging
arbitrary voltage into almost any exposed I&#x2F;O line whether it should be
there or not. Design limitations suggest that we should consider reasonable
voltages for electronics projects -- being tolerant to kilovolts is
unreasonable, and even mains is probably out of scope. But I think +&#x2F;- 20V
of ground is a reasonable tolerance range for small EE projects.&lt;&#x2F;p&gt;
&lt;p&gt;The easiest thing to do is slap TVS diodes on everything and call it a day. The
design I initially considered was:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text z-code&quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+ 3V3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;   |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  TVS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;   |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  SIG
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;   |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  TVS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;   |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  GND
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where each TVS is bidirectional with a breakdown at 3V3. The idea being that
they would clamp the signal to within 0V -&amp;gt; 3V3. The problem with this approach
is that I think it&#x27;s unrealistic that a user would quickly notice something
was plugged into the wrong place, and the diodes might have to sink a lot of
current and so dissipate a lot of heat. As far as I know, TVS diodes aren&#x27;t
generally designed for this -- they&#x27;re mostly meant to handle transients, so
this is maybe not an ideal approach. I&#x27;m sure I could find diodes that could
handle this, but this design feels hacky overall, so I thought about how else I
could address this problem.&lt;&#x2F;p&gt;
&lt;p&gt;One possibility is cutting output power if a signal is detected out of range,
but I don&#x27;t want to rely on that either. I see output power as a convenience in
the design, not a usage necessity.&lt;&#x2F;p&gt;
&lt;p&gt;I started thinking about a design using FETs with comparators as gate drivers,
which I think would probably work, but realized that the behavior I want is
isolation between the microcontroller side and the external ports — I think
what I&#x27;m actually looking for is an optocoupler. Looking at digikey, I&#x27;m seeing
about $1.50 per part with 4 channels (so BoM cost for me is $9 for 21 channels),
but those parts are only unidirectional. I could live with this, as I don&#x27;t really
need 21 channels for the design intent of the project, but that&#x27;s a somewhat pricy
addition to the BoM. Many of these also have frequency limits that come up against
my desired SPI rates -- I think 10MHz would be fine, but I&#x27;m seeing a lot of
isolators that will only handle up to about 1MHz.&lt;&#x2F;p&gt;
&lt;p&gt;On course, there are some from ADI that are $10&#x2F;unit and do bidirectional
translation, but that&#x27;s painfully expensive.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>mockup (pset 2)</title>
        <published>2024-10-01T00:00:00+00:00</published>
        <updated>2024-10-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/smallmfg/mockup/"/>
        <id>https://blog.npry.dev/class/smallmfg/mockup/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/smallmfg/mockup/">&lt;p&gt;@carboxyl: this page is available on my blog if you&#x27;re interested in following
any of the hyperlinks:
&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;smallmfg&#x2F;mockup&quot;&gt;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;smallmfg&#x2F;mockup&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The goal of this problem set is to help converge upon functional requirements
for your product. Build a quick mock-up of your product, and interview at
least 2 users on a few aspects of its design, functions, or uses. Be very
specific about what your aims are, and try to glean that information from the
user without biasing them in any way. Do not pick too many aspects of the
design to test on, as it may overwhelm the test subjects. Write up a short
report indicating what questions you were trying to answer, whether those were
answered, and what unexpected things you learned from your user study. Please
include a picture of your mock-up in the report, and turn in a hard copy in
class on the due date.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I 3d-printed a couple of models with different functionality for my mockup, an
&quot;A&quot; variant and a &quot;B&quot; variant.&lt;&#x2F;p&gt;
&lt;p&gt;The A variant is larger (100x100mm) and has an integrated clamp for holding a
part -- the idea behind this one is that the project is more of a
fully-integrated workstation that carries the DUT. It would be relatively easy
to add more battery capacity to this one, but the final product is likely to be
more expensive.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;unit_a.8c45c2e7adec371e.jpg&quot;&gt;

    
    &lt;i style=&quot;margin-top: 0.5rem&quot;&gt;
        &lt;p&gt;A unit (clamp disassembled)&lt;&#x2F;p&gt;

    &lt;&#x2F;i&gt;
    
&lt;&#x2F;div&gt;
&lt;p&gt;The B variant is smaller (50x50mm) and in my mind is conceptually an object
that goes &lt;em&gt;along with&lt;&#x2F;em&gt; your project (rather than holding it), or embeds into it
for testing.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;unit_b.73ff857fb621df6c.jpg&quot;&gt;

    
    &lt;i style=&quot;margin-top: 0.5rem&quot;&gt;
        &lt;p&gt;B unit&lt;&#x2F;p&gt;

    &lt;&#x2F;i&gt;
    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;smallmfg&#x2F;mockup&#x2F;drawing.pdf&quot;&gt;Drawings here&lt;&#x2F;a&gt; (attached to physical turnin)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;cad.onshape.com&#x2F;documents&#x2F;60d6bac853aef0c7e4de20ae&#x2F;w&#x2F;f80f0acec7060ca58526596b&#x2F;e&#x2F;3ea6ac7adef1c0fc56417663?renderMode=0&amp;amp;uiState=66fc00b450981262291d4761&quot;&gt;cad
(onshape)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;user-study&quot;&gt;user study&lt;&#x2F;h2&gt;
&lt;p&gt;I asked a couple of electrical engineers in my group for feedback on the
designs. The questions I was hoping to answer were:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Which size variant is preferred?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Do they want wireless functionality?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Bluetooth?&lt;&#x2F;li&gt;
&lt;li&gt;WiFi?&lt;&#x2F;li&gt;
&lt;li&gt;Does the answer change based on which variant is being considered?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;What software interfaces do people imagine by default? How do they want to
interface with it?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;user-1&quot;&gt;user 1&lt;&#x2F;h3&gt;
&lt;p&gt;This user gave a lot of unexpected feedback. The most important functionality
for her to see was basic bus sanity-checking functionality and support for
bringup, e.g. she wanted to see an i2c bus scan, indicator LEDs for the bus
being high, and a hardware switch to enable i2c bus pull-ups. She expressed a
strong preference for connectors other than DuPont because of their flakiness
and eventual degredation.&lt;&#x2F;p&gt;
&lt;p&gt;She was overall neutral on the larger unit -- once I told her what the clamp
was meant to do, she said that it didn&#x27;t feel justified without additional
functionality (e.g., bracketing the logistical difficulty of doing this, the
clamp supplying power to the board). She mentioned that it would be nice to be
able to configure pogo pins or similar to probe the board as it&#x27;s held in place.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;user-2&quot;&gt;user 2&lt;&#x2F;h3&gt;
&lt;p&gt;This user gave very different feedback from the first user. He preferred the
larger unit with the clamp and found that a very compelling feature. He
echoed my sentiment (unprimed) that it could really help him reduce clutter on
his desk during bringup by keeping all the wires in one place. He said he would
use the wireless functionality and that the battery should last about 4 hours --
he would be fine charging it during lunch, just as long as it lasted a full work
session for him. He indicated that it was annoying that there are so many
separate tools to perform EE work: workholding, analyzers, oscilloscopes, etc.
and encouraged me to make the unit physically bigger and add more functionality
to it. I asked if he would use an embedded breadboard or perfboard, and he said
he might but it would also be fine to leave the top area unpopulated as a
worksurface.&lt;&#x2F;p&gt;
&lt;p&gt;His feedback on the smaller unit was that he could make use of it best as a
communication station attached to a host computer that could talk to his
embedded projects, rather than as a bus sniffer at all -- he feels logic
analyzers serve this need sufficiently and wasn&#x27;t moved much by the wireless
functionality in this domain. Rather, he wants something that helps him solve
his problem of reinventing communications protocols. He imagined that this
smaller node could help with this.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>thesis abstract: interstice</title>
        <published>2024-10-01T00:00:00+00:00</published>
        <updated>2024-10-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/thesis/abstract/"/>
        <id>https://blog.npry.dev/resenv/thesis/abstract/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/thesis/abstract/">&lt;p&gt;Contemporary networked microcontroller-based electronics rarely embed meshing
capabilities, typically acting as leaf network nodes. When mesh-enabled (via
e.g. Thread, Bluetooth Mesh), the mesh network is limited to a single physical
interface technology (typically radio). As a result, it is difficult to deploy
embedded networks across heterogeneous physical links, commonly requiring
expert integrators to build bespoke bridges between link domains. This imposes
design constraints, disfavoring microcontrollers without radio networking
capabilities and limiting compatibility across physical links.&lt;&#x2F;p&gt;
&lt;p&gt;These limitations have significant consequences in the spaces of sensor networks,
pervasive computing, and IoT. Here, network connectivity is crucial, but data
rate requirements tend to be low. We argue that improving the status quo in
ability to integrate network connectivity, and especially &lt;em&gt;transitive&lt;&#x2F;em&gt;
connectivity via neighbors, could represent a paradigm-shifting improvement for
the field.&lt;&#x2F;p&gt;
&lt;p&gt;We observe that any graph of physical links (conductors, point-to-point radio
connections, audio or optical transceivers) in a distributed embedded system, a
communications network &lt;em&gt;could&lt;&#x2F;em&gt; be constructed that would enable any two nodes
in a connected component of that graph to communicate. This is not possible
today because embedded devices do not implement link-to-link bridges that would
enable this transitive connectivity.&lt;&#x2F;p&gt;
&lt;p&gt;This is what this thesis intends to address. We will develop and publish
open-source firmware libraries implementing packet switching (L2) and IP
routing (L3) capabilities across modular physical (L1) backends, supporting
common wired and wireless protocols. The design intent is to implement an
Ethernet network over device-to-device serial links and buses, bridged with any
WiFi, Bluetooth, or other available 802.15.4 wireless links. At least one
Ethernet PHY driver will be provided, and host computers will be able make
edge connections through USB CDC-NCM. These libraries will be provided with
Arduino-compatible C header files and precompiled library archives for common
embedded ISAs.&lt;&#x2F;p&gt;
&lt;p&gt;A demonstrator system will be developed that showcases these networking
capabilities across a multitude of microcontrollers and physical links. Link
throughput and power characterization will be performed and analyzed at several
network sizes and with different microcontrollers.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>market research (pset 1)</title>
        <published>2024-09-24T00:00:00+00:00</published>
        <updated>2024-09-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/smallmfg/market-research/"/>
        <id>https://blog.npry.dev/class/smallmfg/market-research/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/smallmfg/market-research/">&lt;p&gt;@carboxyl: this page is available on my blog if you&#x27;re interested in following
any of the hyperlinks:
&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;smallmfg&#x2F;market-research&quot;&gt;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;smallmfg&#x2F;market-research&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The goal of this problem set is to help refine your ideas, and to give you
experience doing preliminary market research.&lt;&#x2F;p&gt;
&lt;p&gt;Select at least 2 &quot;next best option&quot; products in your market, and research
their sale price, features, reviews, and estimated quantities sold per year.
Use either graphs or charts (as shown in class) to compare these options to
your idea(s), and create a functional requirements list, approximate price and
sales quantity, that place you in a unique position in the market.&lt;&#x2F;p&gt;
&lt;p&gt;Please turn in a hard copy in class of your research, describing your idea(s),
the comparison products, your charts and graphs, functional requirement list,
and a brief description of how you chose that particular set.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;cdn.betterttv.net&amp;#x2F;emote&amp;#x2F;60be7fa7f8b3f62601c3a4b2&amp;#x2F;3x.webp&quot; class=&quot;noborder&quot;&gt;

    
    &lt;i style=&quot;margin-top: 0.5rem&quot;&gt;
        &lt;p&gt;SNIFFA (bus sniffer)&lt;&#x2F;p&gt;

    &lt;&#x2F;i&gt;
    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;em&gt;SNIFFA&lt;&#x2F;em&gt; is a WiFi-enabled bus sniffer designed as a tool for debugging embedded
electronics. It is modeled after the Bus Pirate.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;functional-requirements&quot;&gt;functional requirements&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Bus support&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SPI&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I2C&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;UART&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Nice-to-haves:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CAN&lt;&#x2F;li&gt;
&lt;li&gt;Automatic bus detection &#x2F; scanning&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Connectivity&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;WiFi&lt;&#x2F;li&gt;
&lt;li&gt;USB&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Host-side control interfaces&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Programmatic control (client libraries -- Rust, Python)
&lt;ul&gt;
&lt;li&gt;Protocol specification (protobuf, msgpack?)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Textual console (like BusPirate)&lt;&#x2F;li&gt;
&lt;li&gt;Nice-to-haves:
&lt;ul&gt;
&lt;li&gt;GUI (don&#x27;t consider this critical, design is meant for engineers)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Regulated power output&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;+3V3&lt;&#x2F;li&gt;
&lt;li&gt;+5V&lt;&#x2F;li&gt;
&lt;li&gt;Design intent: not meant to power high-current devices (~100mA)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Battery lifetime &amp;gt;= 8h&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Figure mean current draw of 250mA @ 3V3 powering a DUT and the probe on
WiFI -&amp;gt; 4000mAh LiPo battery supports &amp;gt; 8h of runtime&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Small (&amp;lt; 100mm x 100mm), light (&amp;lt; 100g), easily portable&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;justification&quot;&gt;justification&lt;&#x2F;h3&gt;
&lt;p&gt;I came up with this list based on my personal knowledge of the technical
requirements for using a device like this, and by comparing features with the
Bus Pirate and Flipper Zero. Bus support matches the competition — the
design intent isn&#x27;t to do everything but provide targeted utility (this can
always be fixed in firmware later). WiFi is intended to be a differentiator,
and USB is just necessary for a device like this, for DFU, tethered operation,
charging. I give some justification in the Bus Pirate section for why good
programmatic control from a host computer is important. Size isn&#x27;t critical
— it just needs to be on-par. I went with the same supply voltages as the
Flipper — we could add more or an adjustable supply, but I think that&#x27;s
more trouble than it&#x27;s worth. Battery lifespan is meant to get you through a
working day.&lt;&#x2F;p&gt;
&lt;p&gt;I notably &lt;em&gt;didn&#x27;t&lt;&#x2F;em&gt; include SWD support because I have a feeling this would
take a substantial amount of dedicated engineering time to get right. Without
looking into this further, I could definitely be wrong, but I&#x27;m not putting it
in the featureset for a first revision for this reason. The competition &lt;em&gt;does&lt;&#x2F;em&gt;
have this, so it&#x27;s a tradeoff. However, this can probably be fixed in firmware,
depending on which microcontroller I select.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;existing-products&quot;&gt;existing products&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;bus-pirate-62-for-v5xl&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;buspirate.com&#x2F;&quot;&gt;bus pirate&lt;&#x2F;a&gt; ($62 for v5XL)&lt;&#x2F;h3&gt;
&lt;p&gt;Inspiration for this project. The Bus Pirate is a multi-IO debugging board that
you can connect to buses and GPIOs and control from a host computer over USB
serial. It provides a console-based interface with a custom command-set, and
lets you both passively listen to bus traffic and inject your own.&lt;&#x2F;p&gt;
&lt;p&gt;It has several scripting interfaces, including a Python one, but my experience
is that they are very flaky (commands fail, are timing-sensitive, etc.). I get
the sense that the console UI and user-facing commandset were designed first,
and then scripting capabilities were grafted on top. Automating bus interactions
is one of the primary reasons for me to want a device like this, but it was bad
enough on the Bus Pirate to cause me to give up and stop using it.&lt;&#x2F;p&gt;
&lt;p&gt;Reviews:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Seeing a lot of how-tos and product summaries
(&lt;a href=&quot;https:&#x2F;&#x2F;eclypsium.com&#x2F;blog&#x2F;bus-pirate-5-the-swiss-arrrmy-knife-of-hardware-hacking&#x2F;&quot;&gt;e.g.&lt;&#x2F;a&gt;),
but not many actual reviews.&lt;&#x2F;li&gt;
&lt;li&gt;Some from the Bus Pirate 3 era (early 2010s):
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;skywired.net&#x2F;blog&#x2F;2011&#x2F;11&#x2F;bus-pirate-review&#x2F;&quot;&gt;skywired&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;some complaints about features (no level shifting, gripes with
host software)&lt;&#x2F;li&gt;
&lt;li&gt;likes the brekout cables&lt;&#x2F;li&gt;
&lt;li&gt;overall likes the device, thinks it&#x27;s better than a plain MCU
with custom firmware or an expensive analyzer&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.bigmessowires.com&#x2F;2013&#x2F;11&#x2F;19&#x2F;what-is-the-bus-pirate&#x2F;&quot;&gt;big mess o wires&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;loves it for multifunctionality (bus support, jtag support)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I couldn&#x27;t find data on quantities for this specific project — the
websites don&#x27;t have published counters.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;flipper-zero-170-200-with-wifi-shield&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;flipperzero.one&quot;&gt;flipper zero&lt;&#x2F;a&gt; ($170, $200 with WiFi shield)&lt;&#x2F;h3&gt;
&lt;p&gt;Electronic hacking multitool built on STM32WB. Has a display, 2100mAh battery,
20+ GPIOs, bus interfacing capabilities, bluetooth, audio, Dallas 1-wire, two
SDRs at different bands, an infrared transciever, an LCD screen, and a bunch of
open-source support with a desktop application. Love the thing.&lt;&#x2F;p&gt;
&lt;p&gt;But:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It&#x27;s somewhat expensive — I think I can beat the price by a factor of 2&lt;&#x2F;li&gt;
&lt;li&gt;I pretty specifically want to be on WiFi — it&#x27;s important to me that you
can be out of Bluetooth range and maintain a fast link&lt;&#x2F;li&gt;
&lt;li&gt;I&#x27;m aiming to support a usage mode where you leave the sniffa integrated with
your embedded project for potentially days or weeks. It seems silly, but I think
this is emotionally harder to do for something marketed like the Flipper.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Some reviews (first few on google):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;flipperzero&#x2F;comments&#x2F;136kzd5&#x2F;flipper_review_for_some_on_the_fence&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;flipperzero&#x2F;comments&#x2F;136kzd5&#x2F;flipper_review_for_some_on_the_fence&#x2F;&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;Beginner, likes it enough to replace it if it breaks, bought the WiFi
devboard&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@papathought&#x2F;flipper-zero-an-honest-review-612118a6ba77&quot;&gt;https:&#x2F;&#x2F;medium.com&#x2F;@papathought&#x2F;flipper-zero-an-honest-review-612118a6ba77&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;Dumb-consumer mindset, wants a turnkey hack-everything device and
somewhat disappointed that it isn&#x27;t that, uses it for RFID&#x2F;NFC key
storage&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Was really looking for a review from someone who writes their own
software&#x2F;firmware or really gets into the device, but didn&#x27;t find
it quickly. Suggests that there may be a lot of people who bought it
for the &quot;hacking Tomagotchi&quot; experience it markets as without necessarily
a deep embedded background.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.kickstarter.com&#x2F;projects&#x2F;flipper-devices&#x2F;flipper-zero-tamagochi-for-hackers&quot;&gt;kickstarter&lt;&#x2F;a&gt;:
37k backers, raised ~$4.9M. Total device tally: 41,195. Hard to estimate their
current sales volume, as they&#x27;re selling through multiple distributors.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;usb-logic-analyzers&quot;&gt;USB logic analyzers&lt;&#x2F;h3&gt;
&lt;p&gt;These are somewhat orthogonal — they&#x27;re not WiFi-enabled and are in
a much higher price bracket, so I&#x27;m not doing as much resarch for them.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;analog-discovery-3-379&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;digilent.com&#x2F;reference&#x2F;test-and-measurement&#x2F;analog-discovery-3&#x2F;start&quot;&gt;analog discovery 3&lt;&#x2F;a&gt; ($379)&lt;&#x2F;h4&gt;
&lt;p&gt;Highly multipurpose: logic analyzer, oscilloscope, function generator. Has a
GUI and Python client libraries. Connects over USB.&lt;&#x2F;p&gt;
&lt;p&gt;Couldn&#x27;t find any location to estimate sales volume.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;saleae-logic-8-500&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.saleae.com&#x2F;products&#x2F;saleae-logic-8&quot;&gt;saleae logic 8&lt;&#x2F;a&gt; ($500)&lt;&#x2F;h4&gt;
&lt;p&gt;Logic analyzer, relatively high sample rate, with ADCs on each channel. Connects
over USB. The greatest utility is the desktop application, which is super easy to
use and can be modularly extended with specific protocol decoders written in Python.&lt;&#x2F;p&gt;
&lt;p&gt;No idea on sales volume, this isn&#x27;t published or exposed anywhere I could find.
No kickstarters or similar.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;hiletgo-saleae-compatible-13&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hiletgo.com&#x2F;ProductDetail&#x2F;1915369.html&quot;&gt;hiletgo (saleae-compatible)&lt;&#x2F;a&gt; ($13)&lt;&#x2F;h4&gt;
&lt;p&gt;Very cheap logic analyzer that works in Saleae&#x27;s GUI application. 8 channels,
nominally 24MHz. Connects over USB.&lt;&#x2F;p&gt;
&lt;p&gt;No idea on volume, but they&#x27;re able to sell at a very low pricepoint on Amazon, so
probably 10k+ units.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;feature-comparison-chart&quot;&gt;feature comparison chart&lt;&#x2F;h2&gt;
&lt;p&gt;Everything on the chart supports USB connectivity and decodes the buses of
interest.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;product&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;Price&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;WiFi&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;Bluetooth&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;Scripting&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;Power&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;Battery&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;GUI&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;sniffa&lt;&#x2F;td&gt;&lt;td&gt;$68&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;maybe&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;4000mAh&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;flipper zero&lt;&#x2F;td&gt;&lt;td&gt;$170&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;2100mAh&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;flipper zero (wifi devboard)&lt;&#x2F;td&gt;&lt;td&gt;$200&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;2100mAh&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;bus pirate 5XL&lt;&#x2F;td&gt;&lt;td&gt;$62&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;buggy&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;analog discovery 3&lt;&#x2F;td&gt;&lt;td&gt;$379&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;saleae logic 8&lt;&#x2F;td&gt;&lt;td&gt;$500&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;hiletgo (saleae-compatible)&lt;&#x2F;td&gt;&lt;td&gt;$13&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The Flipper and the Bus Pirate are the closest competitors. I&#x27;d be aiming to
beat the Flipper in price and size by specializing in function, and the Bus
Pirate by providing wireless functionality and battery power.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pricing-best-guess&quot;&gt;pricing (best guess)&lt;&#x2F;h2&gt;
&lt;p&gt;Aiming for a bare board to minimize cost.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;PCB w&#x2F; one-side assembly: $15 (I think this is high)&lt;&#x2F;li&gt;
&lt;li&gt;MCU (&lt;a href=&quot;https:&#x2F;&#x2F;www.digikey.com&#x2F;en&#x2F;products&#x2F;detail&#x2F;espressif-systems&#x2F;ESP32-C6FH4&#x2F;18587545&quot;&gt;esp32c6&lt;&#x2F;a&gt;): $2&lt;&#x2F;li&gt;
&lt;li&gt;Connectors and switches: $5&lt;&#x2F;li&gt;
&lt;li&gt;Passives: $2&lt;&#x2F;li&gt;
&lt;li&gt;Power regulation: $5&lt;&#x2F;li&gt;
&lt;li&gt;Battery (4000 mAh 1S LiPo): $10&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Unit cost (low volume): $40&lt;&#x2F;p&gt;
&lt;p&gt;Sale price (@ 1.7x): $68&lt;&#x2F;p&gt;
&lt;h3 id=&quot;engineer-design-time&quot;&gt;engineer &#x2F; design time&lt;&#x2F;h3&gt;
&lt;p&gt;I don&#x27;t consider amortized engineering&#x2F;design costs because I need this product
for myself and would be spending the time to make it anyway.&lt;&#x2F;p&gt;
&lt;p&gt;But to run through this for the sake of the exercise, I expect this would take
about a month of engineering time to design and build, so let&#x27;s round up to 200
hours. Pricing engineer time at $125&#x2F;hr, that&#x27;s $25k.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not sure if a typical 1.7x markup as mentioned in class is based on the
unit cost (and engineer time is counted as overhead), or if it&#x27;s common to
explicitly amortize any fixed development costs of this kind. For the sake of
argument, let&#x27;s amortize the cost. Say I want to stay at least 25% under the
Flipper Zero (with WiFi devboard) in price to remain competitive. For \(x\)
units:&lt;&#x2F;p&gt;
&lt;p&gt;\begin{align}
\notag 1.7 \cdot \left( 25000 + 40x \right) &amp;amp;= \left( 200 \cdot 0.75 \right) x \\
\notag x &amp;amp;\approx 520
\end{align}&lt;&#x2F;p&gt;
&lt;p&gt;I.e., I would have to sell 520 units to break even at a price point of $150.&lt;&#x2F;p&gt;
&lt;p&gt;But I would really want the price to stay under $100, which would look like:&lt;&#x2F;p&gt;
&lt;p&gt;\begin{align}
\notag 1.7 \cdot \left( 25000 + 40x \right) &amp;amp;= 100 x \\
\notag x &amp;amp;\approx 1325
\end{align}&lt;&#x2F;p&gt;
&lt;p&gt;At either of volumes, I would expect the BoM cost to decrease significantly, so
I&#x27;ll rerun these calculations guessing that I could cut down unit cost by a
third:&lt;&#x2F;p&gt;
&lt;p&gt;\begin{align}
\notag 1.7 \cdot \left( 25000 + \frac{2}{3} \cdot 40 x \right) &amp;amp;= \left( 200 \cdot 0.75 \right) x \\
\notag x &amp;amp;\approx 405 \\
\notag 1.7 \cdot \left( 25000 + \frac{2}{3} \cdot 40 x \right) &amp;amp;= 100 x \\
\notag x &amp;amp;\approx 775
\end{align}&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s a bit better. The up-front capital required to finance a production
run would be ~$11k (@ 405) or ~$20k (@ 775).&lt;&#x2F;p&gt;
&lt;p&gt;Pragmatically speaking, those volumes would be large to plan around for my first
time doing something like this, so this math suggests the project is impractical.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>brainstorm</title>
        <published>2024-09-17T00:00:00+00:00</published>
        <updated>2024-09-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/smallmfg/brainstorm/"/>
        <id>https://blog.npry.dev/class/smallmfg/brainstorm/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/smallmfg/brainstorm/">&lt;p&gt;I didn&#x27;t come into the course with a concept in mind, so this is somewhat an
exercise in backreasoning what will fit into its constraints.&lt;&#x2F;p&gt;
&lt;p&gt;I lean towards something supporting embedded development, as I experience a
lot of pain points that I feel are unnecessary. Considerations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Every embedded bringup inevitably results in a huge tangle of wires that
consumes my desk
&lt;ul&gt;
&lt;li&gt;Mutually exclusive with other projects&lt;&#x2F;li&gt;
&lt;li&gt;Bringup burden + switching cost&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Wired connections to power and instrumentation make debugging fragile re:
physical disturbances&lt;&#x2F;li&gt;
&lt;li&gt;I always want an SWD programmer&lt;&#x2F;li&gt;
&lt;li&gt;I always want a bus + serial sniffer (SPI, I2C, UART mostly)&lt;&#x2F;li&gt;
&lt;li&gt;I want workholding for my board&lt;&#x2F;li&gt;
&lt;li&gt;I want to probe signals on my board&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The full, simultatneous realization of these desires in a single product would
be a weighted &lt;a href=&quot;https:&#x2F;&#x2F;hakkousa.com&#x2F;omnivise-pcb-holder.html&quot;&gt;PCB clamp&lt;&#x2F;a&gt; with
attached &lt;a href=&quot;https:&#x2F;&#x2F;sensepeek.com&#x2F;&quot;&gt;PCBite&lt;&#x2F;a&gt; goosenecks, integrated scope, SWD
programmer, and logic analyzer, running on battery power, all of which you can
connect to over WiFi. Clearly, this would be overdesigned.&lt;&#x2F;p&gt;
&lt;p&gt;However, I think parts of this could make sense. A WiFi-enabled bus sniffer (à
la &lt;a href=&quot;https:&#x2F;&#x2F;www.sparkfun.com&#x2F;products&#x2F;12942&quot;&gt;BusPirate&lt;&#x2F;a&gt;) or SWD programmer
would be great. The idea is that you would plug this into a device you&#x27;re
bringing up with short leads and be able to eliminate a lot of the wires
between the device and its power&#x2F;instrumentation. Ideally, you&#x27;d be able to
move the DUT and the sniffer&#x2F;debug probe around as a single unit.&lt;&#x2F;p&gt;
&lt;p&gt;Possible features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Host-side client libraries&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;As opposed to BusPirate, which has a custom text protocol&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Host-side GUI application&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Configuration and linear log display are straightforward&lt;&#x2F;li&gt;
&lt;li&gt;Graphical timeline viewer is probably a lot of work&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Portable +3.3V and +5V for powering debugged project&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Sniffer&#x2F;probe would need a battery anyway&lt;&#x2F;li&gt;
&lt;li&gt;Does come with additional electrical design complexity
&lt;ul&gt;
&lt;li&gt;Fusing&lt;&#x2F;li&gt;
&lt;li&gt;RP, ESD protection&lt;&#x2F;li&gt;
&lt;li&gt;Increased requirements on regulators&lt;&#x2F;li&gt;
&lt;li&gt;Boost for +5V&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ADC lines for monitoring power nets&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Some way to physically couple the probe to a board &#x2F; treat them as one unit
(for the sake of desk-clearing &#x2F; context-switching). Possibilities:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Housing integrates a clamp&lt;&#x2F;li&gt;
&lt;li&gt;Housing can easily be attached to a clamp&lt;&#x2F;li&gt;
&lt;li&gt;Design housing with intent to be VHBed&lt;&#x2F;li&gt;
&lt;li&gt;Design housing with intent to be ziptied (probably not this one)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;what-exists&quot;&gt;what exists?&lt;&#x2F;h2&gt;
&lt;p&gt;(Only considering wireless-enabled devices.)&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;flipperzero.one&#x2F;&quot;&gt;Flipper Zero&lt;&#x2F;a&gt; is a potential extant alternative,
but it doesn&#x27;t have WiFi capabilities. It &lt;em&gt;can&lt;&#x2F;em&gt; speak Bluetooth and supply
portable power, but I believe WiFi specifically is important for the ability to
walk away and still access the device with decent link speed. I would also
prefer a stripped-down, small, lower-cost option that&#x27;s easier to work with.&lt;&#x2F;p&gt;
&lt;p&gt;SEGGER produces the &lt;a href=&quot;https:&#x2F;&#x2F;www.segger.com&#x2F;products&#x2F;debug-probes&#x2F;j-link&#x2F;models&#x2F;j-link-wifi&#x2F;&quot;&gt;JLink
WiFi&lt;&#x2F;a&gt;,
which performs the debug probe function, but it&#x27;s very expensive ($1280) for
what it is. A proof of concept alternative would be a
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;debugprobe&quot;&gt;picoprobe&lt;&#x2F;a&gt; made out of a Pico W
with tweaked firmware and an SLA-printed enclosure. Accounting for engineer time,
I&#x27;d estimate the cost at $1-2k. Seems on the same order of magnitude as the
JLink board for single quantities. This implies that a significant part of the
cost of the SEGGER product is software and intangibles (product support,
stability, &quot;it-just-works&quot; factor), but I believe there&#x27;s a meaningful segment
of the market that would trade this off for lower cost.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>git recitation (htm 2024)</title>
        <published>2024-09-12T00:00:00+00:00</published>
        <updated>2024-09-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/git-recitation/"/>
        <id>https://blog.npry.dev/class/htm/git-recitation/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/git-recitation/">&lt;object data=&quot;2024_09_12_git_recitation.pdf&quot; type=&quot;application&#x2F;pdf&quot; style=&quot;width: 100%; height: 500px&quot;&gt;
    &lt;a href=&quot;2024_09_12_git_recitation.pdf&quot;&gt;slides&lt;&#x2F;a&gt;
&lt;&#x2F;object&gt;
&lt;p&gt;This is documentation for the version control recitation for how to make almost
anything 2024.&lt;&#x2F;p&gt;
&lt;p&gt;Members of the class can reach me for help at my MIT email (kerb = npry) or on
the class Discord.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;references&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&quot;&gt;Git Book&lt;&#x2F;a&gt;: great cover of git in some depth&lt;&#x2F;p&gt;
&lt;p&gt;This recitation is based in part on &lt;a href=&quot;https:&#x2F;&#x2F;fab.cba.mit.edu&#x2F;classes&#x2F;863.23&#x2F;doc&#x2F;git_recitation&#x2F;index.html&quot;&gt;Camron&#x27;s version from last
year&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cheatsheet&quot;&gt;cheatsheet&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;ssh-keys-authentication-for-gitlab&quot;&gt;ssh keys (authentication for gitlab)&lt;&#x2F;h3&gt;
&lt;p&gt;If you don&#x27;t have one already:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; can leave password empty at the prompt&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ssh-keygen&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; open gitlab -&amp;gt; click on your user icon -&amp;gt; preferences -&amp;gt; ssh keys -&amp;gt; add new key&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; copy and paste the text after this command into the &amp;#39;key&amp;#39; box&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; then click &amp;#39;add key&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; on modern macos, ssh-keygen may generate a different type of key, so you may have&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; id_ed25519.pub or another variant instead; you can use that&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cat &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;id_rsa.pub&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ssh-rsa&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; AAA...(truncated&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;hostname&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; verify that your key works (don&amp;#39;t bother on windows unless you know you have&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; an ssh client)&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ssh&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;T&lt;&#x2F;span&gt; git@gitlab.cba.mit.edu&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; 846&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Welcome&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; to GitLab, @&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;username&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;!&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;install-git-cli&quot;&gt;install git cli&lt;&#x2F;h3&gt;
&lt;p&gt;You almost certainly need to do this, even if you want to use a GUI client.
Follow &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Getting-Started-Installing-Git&quot;&gt;these
instructions&lt;&#x2F;a&gt;
— let us know if you have trouble.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;git-configuration-clone&quot;&gt;git configuration, clone&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git config&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;global&lt;&#x2F;span&gt; user.name &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;My Name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; use an email associated with your gitlab account&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git config&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;global&lt;&#x2F;span&gt; user.email &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;my_email@my_doma.in&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; clone your personal repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git clone ssh:&#x2F;&#x2F;git@gitlab.cba.mit.edu:846&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;normal-commit-flow&quot;&gt;normal commit flow&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; make some edits...&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; (from repo root) add all files you&amp;#39;ve changed&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git add .&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; check what will be committed&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git status&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; commit the changes to the repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git commit&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;m&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;message&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; push new commit(s) to gitlab&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git push&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;i-want-to-change-a-commit&quot;&gt;i want to change a commit&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git add .&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; alter the _last_ commit with additional changes staged by `git add .`&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git commit&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;amend&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;m&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;message&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; it is very bad manners to do this on a shared branch -- it can break everyone&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; else&amp;#39;s repos&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git push&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For a newcomer, &lt;code&gt;--amend&lt;&#x2F;code&gt; is mildly perilous — prefer to make another
commit unless you really have to edit history (e.g. committed a huge file). In
this case, probably just reach out to me or another TA.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;i-want-an-old-version-of-a-file-or-directory&quot;&gt;i want an old version of a file or directory&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; find the commit hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git log&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;graph&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;oneline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; warning: this will overwrite any local changes you have made to the file&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git checkout &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;help-i-broke-my-repo&quot;&gt;help! i broke my repo!&lt;&#x2F;h3&gt;
&lt;p&gt;Dumb, easy fix -- just re-clone it and make the changes again:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; reclone repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git clone ssh:&#x2F;&#x2F;git@gitlab.cba.mit.edu:846&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; repo_copy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; make your changes again, commit, push&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;help-i-deleted-a-branch-lost-commits&quot;&gt;help! i deleted a branch &#x2F; lost commits!&lt;&#x2F;h3&gt;
&lt;p&gt;Don&#x27;t panic. It&#x27;s hard to lose data in git, so if there&#x27;s something you
need to get back and can&#x27;t, come find a TA and we can help you.&lt;&#x2F;p&gt;
&lt;p&gt;See also: &lt;code&gt;git reflog&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;command-reference&quot;&gt;command reference&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;git-add-files&quot;&gt;&lt;code&gt;git add [files...]&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Stage &lt;code&gt;$files&lt;&#x2F;code&gt; for commit. Most commonly, &lt;code&gt;git add .&lt;&#x2F;code&gt; stages all files in the
current directory (recursively).&lt;&#x2F;p&gt;
&lt;p&gt;Remember that &lt;code&gt;git add&lt;&#x2F;code&gt; stages a &lt;em&gt;current&lt;&#x2F;em&gt; snapshot of file state to be
committed — if you make further changes, you need to &lt;code&gt;git add&lt;&#x2F;code&gt; again.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;git-status&quot;&gt;&lt;code&gt;git status&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Show what changes are going to be committed. Recommend always running this
before you commit to make sure you&#x27;re doing what you think you are.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;git-commit-m-message&quot;&gt;&lt;code&gt;git commit -m [message]&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Record a new commit with message &lt;code&gt;$message&lt;&#x2F;code&gt;. In general, you can&#x27;t make commits
without changed files — if you see this, check &lt;code&gt;git status&lt;&#x2F;code&gt; and make sure
you&#x27;ve staged what you think you have.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;git-restore-staged-files&quot;&gt;&lt;code&gt;git restore --staged [files...]&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Unstage &lt;code&gt;$files&lt;&#x2F;code&gt; -- they won&#x27;t be committed.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;git-checkout-files&quot;&gt;&lt;code&gt;git checkout -- [files...]&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Revert changes to unstaged &lt;code&gt;$files&lt;&#x2F;code&gt;. This discards all edits since the last
commit -- be careful!&lt;&#x2F;p&gt;
&lt;p&gt;If you need to discard changes to staged files, use &lt;code&gt;git restore --staged ...&lt;&#x2F;code&gt;
first.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;git-checkout-branch&quot;&gt;&lt;code&gt;git checkout &amp;lt;branch&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Switch to an existing branch called &lt;code&gt;$branch&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;git-checkout-b-branch&quot;&gt;&lt;code&gt;git checkout -b &amp;lt;branch&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Create and switch to a new branch called &lt;code&gt;$branch&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;git-log-graph-oneline&quot;&gt;&lt;code&gt;git log --graph --oneline&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Show a graphical layout&lt;&#x2F;p&gt;
&lt;h2 id=&quot;class-specifics&quot;&gt;class specifics&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;filesize-limits&quot;&gt;filesize limits&lt;&#x2F;h3&gt;
&lt;p&gt;Pace your uploads -- plan to be storing low single-digit megabytes of data in
your repo each week at the beginning of the class, and low double-digit
megabytes closer to the end. You will need to resize your media in order to
achieve this.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;ffmpeg&lt;&#x2F;code&gt; (commandline) supports resizing videos: &lt;a href=&quot;https:&#x2F;&#x2F;academy.cba.mit.edu&#x2F;classes&#x2F;computer_design&#x2F;video.html&quot;&gt;Neil&#x27;s
cheatsheet&lt;&#x2F;a&gt; is
a good reference.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;ImageMagick&lt;&#x2F;code&gt; supports resizing images:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; convert &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;src_image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;resize&lt;&#x2F;span&gt; 720x480 &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;dst_image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;gitlab&quot;&gt;GitLab?&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;m sure you&#x27;ve heard of GitHub; GitLab fills a similar niche. These are both
git repo hosts with web frontends — they exist to be collaboration
platforms. GitHub is a commercial project owned by Microsoft — GitLab is
an open source protocol that can be self-hosted. This is what CBA does.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ui-clients&quot;&gt;ui clients&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;code.visualstudio.com&#x2F;&quot;&gt;VSCode&lt;&#x2F;a&gt; is the editor most of you are
probably going to use — it has a git UI built in&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;desktop.github.com&#x2F;download&#x2F;&quot;&gt;GitHub Desktop&lt;&#x2F;a&gt; is easy to use. You
don&#x27;t need to sign in with GitHub (you can skip that step), but based on my
testing you will need to clone GitLab repos on the command line and add them
manually&lt;&#x2F;li&gt;
&lt;li&gt;GitLab web UI: this is a browser-embedded version of VS Code that lets you commit
directly to GitLab. You &lt;em&gt;could&lt;&#x2F;em&gt; probably technically build your whole site
this way, but there are some operations that will be easier locally.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;why-what-is-version-control&quot;&gt;why&#x2F;what is version control?&lt;&#x2F;h2&gt;
&lt;p&gt;Does this look familiar: &lt;code&gt;paper final final revised (Copy).docx&lt;&#x2F;code&gt;? In the
language of version control, this document and its versions represent a linear
edit history (read bottom-to-top for chronological order):&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;* fix date                              (-&amp;gt; paper final final revised (Copy).docx)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;* more revisions                        (-&amp;gt; paper final final revised.docx)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;* grammar and spelling cleanup          (-&amp;gt; paper final final.docx)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;* first round of edits, restructuring   (-&amp;gt; paper final.docx)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;* first draft                           (-&amp;gt; paper.docx)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Version control systems let you explicitly manage this history — rather
than copying files manually for backup, you tell a VCS to record a new version
of a file, and it records the change in the history for you. You can tell it to
go to a different version, and it updates the file tree to look like it did at
that version. There are many version control systems, but the one we use in
this class (and the most popular for modern software development) is called
&lt;code&gt;git&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;git-concepts&quot;&gt;git concepts&lt;&#x2F;h3&gt;
&lt;p&gt;Git operates at the scope of a directory. It stores the old versions of files
and file history information in a &quot;repository&quot; (repo), which is just a
directory on the filesystem. (Files aren&#x27;t stored literally, there is a lot of
cleverness in git to deduplicate and compress file versions.) To create a repo,
run &quot;git init&quot;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git init&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Initialized&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; empty Git repository in &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;PWD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.git&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; This is telling you that git will store the data for the repo (version,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; history data, etc.) in the `.git` directory.&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A &quot;version&quot; in git is called a &quot;commit&quot;. When you record a new version of your
files in git, you are &quot;committing&quot; them to the repo:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git add my_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git commit&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;m&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;add my file&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[master&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 12a8bef] add my file                     &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; 12a8bef is the commit id (hash)&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; file changed, 0 insertions(+&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 0 deletions(-&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; new file, but it&amp;#39;s empty&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;create&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mode 100644 my_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a two-step process:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;First tell git what you want to commit with &lt;code&gt;git add&lt;&#x2F;code&gt;. You can do this
multiple times and omit files from being committed:&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; make a change to my_file&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; echo foo &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; my_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; create two new files&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; echo bar &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; another_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; echo qux &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; ignored_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tree&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-dot z-shell&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; my_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; another_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ignored_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; only add another_file to be committed -- a `commit` right now will not&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; record ignored_file or changes to my_file!&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git add another_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; show files:&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; - that will be committed (&amp;quot;staged&amp;quot;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; - that won&amp;#39;t (&amp;quot;not staged&amp;quot;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; - that git hasn&amp;#39;t seen before (&amp;quot;untracked&amp;quot;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git status&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;On&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; branch master&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Changes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; to be committed:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;use&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;git restore --staged &amp;lt;file&amp;gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; to unstage&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; file:   another_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Changes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; not staged for commit:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;use&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;git add &amp;lt;file&amp;gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; to update what will be committed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;use&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;git restore &amp;lt;file&amp;gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; to discard changes in working directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;modified:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   my_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Untracked&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; files:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;use&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;git add &amp;lt;file&amp;gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; to include in what will be committed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ignored_file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;Then record the staged changes (those which have been &lt;code&gt;git add&lt;&#x2F;code&gt;ed) as a
commit:&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git commit&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;m&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;create another important file&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[master&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 5552b2b] create another important file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; file changed, 1 insertions(+&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 0 deletions(-&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;create&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mode 100644 another_file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can view the history with &lt;code&gt;git log&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git log&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 5552b2bebd5e185db2891ba2eb0fc91502e52780&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Author:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Nathan Perry &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;np@npry.dev&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Date:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   Mon Sep 9 14:10:23 2024&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;0400&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;create&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; another important file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 12a8befb21236ae527aa0cffbe59384b5493238b&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Author:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Nathan Perry &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;np@npry.dev&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Date:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   Mon Sep 9 13:52:23 2024&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;0400&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; my file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I find this output is more readable with &lt;code&gt;git log --oneline&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git log&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;oneline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;5552b2bebd5e185db2891ba2eb0fc91502e52780&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create another important file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;12a8befb21236ae527aa0cffbe59384b5493238b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; add my file&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;branching&quot;&gt;branching&lt;&#x2F;h3&gt;
&lt;p&gt;I mentioned in the first example that we were looking at a &quot;linear&quot; commit
history. This is by contrast to a &quot;branching&quot; commit history. Git supports multiple
concurrent versions of the repo, in separate &quot;branches&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;A git branch is just a name that points to a commit. When you are &quot;on&quot; a branch, we
call that having the branch &quot;checked out&quot;. As you make commits, the branch
updates to point to the most recent commit.&lt;&#x2F;p&gt;
&lt;p&gt;You can switch branches with &lt;code&gt;git checkout $branch&lt;&#x2F;code&gt;, and you can create a branch
with &lt;code&gt;git checkout -b $new_branch&lt;&#x2F;code&gt;. When you create a new branch this way, it
starts out pointing to the commit you currently have checked out.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;remotes&quot;&gt;remotes&lt;&#x2F;h3&gt;
&lt;p&gt;So far, the git we&#x27;ve described has been completely local — a way
for you to store and browse the history of a project. Git also supports
(indeed, is built for) collaboration with others. The most common way to
accomplish this is by adding remote repositories:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; configure a remote called &amp;quot;origin&amp;quot; at the given address&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git remote add origin ssh:&#x2F;&#x2F;git@gitlab.cba.mit.edu:846&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; print configured remotes&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git remote&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;origin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;  ssh:&#x2F;&#x2F;git@gitlab.cba.mit.edu:846&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (fetch&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;origin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;  ssh:&#x2F;&#x2F;git@gitlab.cba.mit.edu:846&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (push&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; &amp;quot;push&amp;quot; (send) your commits to the master branch on origin&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; associating (-u) the local master branch with the remote&amp;#39;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git push&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;u&lt;&#x2F;span&gt; origin master&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; &amp;quot;pull&amp;quot; (receive) any new commits from the remote&amp;#39;s master branch&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git pull origin master&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;clone&lt;&#x2F;code&gt; downloads an existing remote repo and creates a local one
based on it (with remote &lt;code&gt;origin&lt;&#x2F;code&gt; configured to point at the remote):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; create a new git repo, configure origin with the given url,&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; and pull the default branch (main or master, depending)&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git clone ssh:&#x2F;&#x2F;git@gitlab.cba.mit.edu:846&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cd &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; print configured remotes&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git remote&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;origin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;  ssh:&#x2F;&#x2F;git@gitlab.cba.mit.edu:846&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (fetch&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;origin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;  ssh:&#x2F;&#x2F;git@gitlab.cba.mit.edu:846&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;YOUR_REPO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (push&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since your GitLab repos are already created, you should &lt;code&gt;clone&lt;&#x2F;code&gt; them.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>thesis pitch: interstice</title>
        <published>2024-08-27T00:00:00+00:00</published>
        <updated>2024-09-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/thesis/pitch/"/>
        <id>https://blog.npry.dev/resenv/thesis/pitch/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/thesis/pitch/">&lt;p&gt;The project of pervasive computing and sensing is not succeeding. We imagined a
future where the whole world is instrumented with cheap sensors and tiny
computers — where data about the environment, machines, and humans is
ubiquitous and easy to access; where these tiny computers can distribute work
between them, in many cases obviating the need for dedicated computing devices.&lt;&#x2F;p&gt;
&lt;p&gt;The reality we inhabit has made strides towards this vision but is far from
attaining it. Components are inexpensive, firmware is open, and vendors provide
cheap integrated solutions, yet in practice deploying a nontrivial networked
embedded system requires substantial application-specific technical design and
integration. The landscape of networked sensor systems remains one of bespoke,
fragmented solutions and walled gardens — sensor instrumentation and
compute embedding is routine in today&#x27;s world but not commodity.&lt;&#x2F;p&gt;
&lt;p&gt;In analogy to manufacturing, we live in a time before the adoption of
standardized parts: the story of electronics hardware and firmware development
is one of reinventing the wheel over and over again and hand-fitting each
system to its particular application. This is not an existential challenge to
the field — it is still possible to produce and deploy embedded
electronics that provide paradigm-shifting capabilities — just as it was
once possible for artisans to craft intricate and precise mechanisms with hand
tooling alone. But it is drastically more difficult and costly to do so than
the underlying technologies suggest it could be. Over-the-air updates,
signaling schemes, networking protocols, message formats, bootloaders —
anything that can be reinvented and respecialized will be — and I argue
that this is an essential unsolved problem on the critical path to a future
replete with readily-deployed, low-cost, networked embedded systems.&lt;&#x2F;p&gt;
&lt;p&gt;A critical capability required for the broad deployment of these systems is
transitive reachability across hetereogeneous node types through any variety of
physical-layer interconnects (copper, radio, optical, etc.). If I can reach one
node in the system, then I ought to be able to reach everything in the
connected component of the network graph it belongs to. Further, this graph
must be easy to extend — it can&#x27;t require additional infrastructure to do
so (hubs, access points, external servers, Internet access, etc.), except as
physical reality dictates (range extension, signal conditioning due to distance
or noise).&lt;&#x2F;p&gt;
&lt;p&gt;To this end, I am building easily-integrated firmware libraries and hardware
designs that enable the construction of hotpluggable, modular, switched or
routed (L2&#x2F;L3), densely connected ad-hoc networks of embedded devices over a
variety of physical-layer interconnects (including SPI, UART, I2C, RS-232,
Bluetooth) using standard Internet protocols. The primary technical
contributions in this thesis are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Protocol specifications and drivers for each supported PHY&lt;&#x2F;li&gt;
&lt;li&gt;Arduino-compatible firmware switch library enabling the aggregation of
L2-compatible PHYs&lt;&#x2F;li&gt;
&lt;li&gt;Arduino-compatible router library based on BATMAN, enabling hotpluggable
ad-hoc network construction and modification&lt;&#x2F;li&gt;
&lt;li&gt;Demonstrator systems showcasing communication between my own PCBs, a variety
of Responsive Environments historical projects, and external network clients
under variable network conditions&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>clef</title>
        <published>2024-08-14T00:00:00+00:00</published>
        <updated>2024-08-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/clef/"/>
        <id>https://blog.npry.dev/clef/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/clef/">&lt;p&gt;&lt;code&gt;clef&lt;&#x2F;code&gt; started as a KiCad project template repo, but I just spent a day or two
setting it up to support processing KiCad projects into 3d models, schematics,
SVGs, and fabrication files through &lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&quot;&gt;Nix&lt;&#x2F;a&gt;, which builds this
blog. That means that as part of the deployment process for this blog, the
version of the &lt;a href=&quot;..&#x2F;resenv&#x2F;ocularium&quot;&gt;ocularium&lt;&#x2F;a&gt; repo that I&#x27;ve pinned is
automatically built, meaning the content on that page is always up-to-date.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nix build .#&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-and z-shell&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; run nixpkgs#tree result&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; share&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; npry&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ocularium&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; fab&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   ├── bom.csv&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   ├── gerbers.zip&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   └── pos.csv&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; model&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   ├── okm.glb&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   └── okm.step&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; schematic&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   ├── schematic.pdf&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   └── svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;       ├── IO.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;       ├── MCU.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;       ├── Power.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;       ├── root.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;│&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;       └── Sensors.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;            &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;                &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; back.mirror.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;                &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; back.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;                &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; front.mirror.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;                &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; front.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;                &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; in1.mirror.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;                &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; in1.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;                &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; in2.mirror.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;                &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└──&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; in2.svg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; directories, 19 files&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;board-svgs&quot;&gt;board svgs&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve just realized the board SVGs exported by KiCad are &lt;em&gt;actual size&lt;&#x2F;em&gt; (they
embed board dimensions), so when rendered on a webpage they are by default
the real size of the board. I added an inkscape step to &lt;code&gt;.svgs&lt;&#x2F;code&gt; to support
trimming off the substantial whitespace KiCad includes so they&#x27;re easier to
embed (inkscape preserves the size metadata, including adjusting for its
trimmed size).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>oneclick jlc</title>
        <published>2024-08-12T00:00:00+00:00</published>
        <updated>2024-08-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/oneclick-jlc/"/>
        <id>https://blog.npry.dev/resenv/oneclick-jlc/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/oneclick-jlc/">&lt;p&gt;In pursuit of more and better open source hardware, I&#x27;d really love it if JLC,
PCBWay, or &lt;code&gt;$FAVORITE_CHEAP_FAST_BOARD_HOUSE&lt;&#x2F;code&gt; exposed the ability to manage a
whole board package (gerbers, board stackup + assembly configuration, BoM,
selected parts, placement) as a semantic object through their API. I&#x27;d like to
be able to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;click a button and deterministically populate an order package&lt;&#x2F;li&gt;
&lt;li&gt;query the API for what an order package will cost&lt;&#x2F;li&gt;
&lt;li&gt;query the API for what parts in an order package aren&#x27;t available&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The historical status quo was that only engineers understood how to get a board
fabbed. Now dedicated hobbyists can do this, and it&#x27;s only getting easier. I
think there&#x27;s a huge market to capture here, and there will be someone who gets
it first — the board houses can cut out the middlemen without much risk
simply by reducing the friction in ordering PCBs. In the meantime I&#x27;m frustrated
that I have to keep clicking through the JLC web UI every time I want to change
my order and &lt;a href=&quot;https:&#x2F;&#x2F;jlcpcb.com&#x2F;help&#x2F;article&#x2F;jlcpcb-online-api-available-now&quot;&gt;it&#x27;s not possible to automate (last update
11&#x2F;2023)&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;api_suspended.9fc31191d6830734.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>ppq</title>
        <published>2024-08-11T00:00:00+00:00</published>
        <updated>2024-08-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/ppq/"/>
        <id>https://blog.npry.dev/ppq/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/ppq/">&lt;p&gt;It is a pain in the ass to get project images from my phone (camera) to my
documentation, and then it&#x27;s frequently an additional manual step to resize,
and then I have to go back and delete them off the phone, as I wasn&#x27;t trying to
preserve the images in Google Photos&#x2F;iCloud in the first place--version control
on the documentation is responsible for that persistence. First world problems,
sure, but it&#x27;s a bunch of additional friction to adding images (&quot;documenting as
you go&quot;), which demonstrably makes documentation more engaging and clear.&lt;&#x2F;p&gt;
&lt;p&gt;A 60% solution is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;magic-wormhole&#x2F;magic-wormhole&quot;&gt;magic
wormhole&lt;&#x2F;a&gt; on the receiving
device with something like &lt;a href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=io.sanford.wormhole_william&amp;amp;hl=en_US&quot;&gt;wormhole
william&lt;&#x2F;a&gt;
on the phone. That lets me document as I go, but I need the wormhole running
all the time, I need to sync the code, and I need to take the images
out-of-band. Basically I need my laptop with me and set up to synchronously
receive everything. That&#x27;s fine, but I often am taking pictures in-the-moment,
and it&#x27;s not guaranteed everything will be set up this way ahead of time.&lt;&#x2F;p&gt;
&lt;p&gt;What I actually want is a client-side partitioned media queue that doesn&#x27;t
require a concurrent receiving device — open the app, make a queue, take
a bunch of pictures, go back and title ones I want to keep, they automatically
upload. Later, when I&#x27;m writing up the docs, run something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cd blog&#x2F;content&#x2F;current-post&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ppq list&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;htm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;5 pending&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ppq dump&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;q&lt;&#x2F;span&gt; htm&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;resize&lt;&#x2F;span&gt; 720x480&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dequeue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; demo1.jpg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dequeue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; demo2.jpg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dequeue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; demo.mp4&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dequeue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; test.jpg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dequeue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; broken.jpg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;d also like to support:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ppq stream&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;q&lt;&#x2F;span&gt; htm&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;resize&lt;&#x2F;span&gt; 720x480&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;to stream all the files as I take them, and possibly some undo functionality.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;language-choices&quot;&gt;language choices&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ll probably write the server component in Elixir, as I&#x27;ve been playing with
it recently and this really is a distributed systems problem. I could just use
NATS + JetStream, but I kinda don&#x27;t want to deal with its authentication system
&#x2F; overload it here.&lt;&#x2F;p&gt;
&lt;p&gt;Phone app is Kotlin on Android unless there&#x27;s something nice for Rust (seems
like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-mobile&#x2F;android-activity&quot;&gt;maybe&lt;&#x2F;a&gt; — might try
it out if it doesn&#x27;t seem like too much of a pain in the ass).&lt;&#x2F;p&gt;
&lt;p&gt;CLI will be Rust.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design-sketch&quot;&gt;design sketch&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;server&quot;&gt;server&lt;&#x2F;h3&gt;
&lt;p&gt;Relational DB (probably just SQLite? I don&#x27;t think PG is worth it) for queues +
Phoenix for REST API.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GET &#x2F;&lt;&#x2F;code&gt;: list all queues&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;POST &#x2F;:name&lt;&#x2F;code&gt;: create queue&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;DELETE &#x2F;:name&lt;&#x2F;code&gt;: delete queue&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GET &#x2F;:name&lt;&#x2F;code&gt;: list items in queue (metadata only)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;POST &#x2F;:name&#x2F;item&lt;&#x2F;code&gt;: add item, returns uuid&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;DELETE &#x2F;:name&#x2F;:uuid&lt;&#x2F;code&gt;: remove item&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;POST &#x2F;:name&#x2F;dump&lt;&#x2F;code&gt;: download and remove all items in queue&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;phone-app&quot;&gt;phone app&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Login activity -- set server, token (JWT)&lt;&#x2F;li&gt;
&lt;li&gt;Home activity: queue list (names, number of items)&lt;&#x2F;li&gt;
&lt;li&gt;Queue detail activity: image grid + detail edit modal&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;cli&quot;&gt;cli&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;configure --server $server --token $token&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;list&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;GET &#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-q $name create&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;POST &#x2F;:name&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-q $name rm&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;DELETE &#x2F;:name&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-q $name list&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;GET &#x2F;:name&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-q $name post &amp;lt; $item&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;POST &#x2F;:name&#x2F;item&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-q $name rm $uuid&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;DELETE &#x2F;:name&#x2F;:uuid&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-q $name dump&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;POST &#x2F;:name&#x2F;dump&lt;&#x2F;code&gt;SERVER&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>nix: tinysearch</title>
        <published>2024-08-11T00:00:00+00:00</published>
        <updated>2024-08-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/tinysearch/"/>
        <id>https://blog.npry.dev/tinysearch/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/tinysearch/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tinysearch&#x2F;tinysearch&quot;&gt;tinysearch&lt;&#x2F;a&gt; is a static
site-embedded search engine written in Rust by &lt;a href=&quot;https:&#x2F;&#x2F;endler.dev&quot;&gt;Matthias
Endler&lt;&#x2F;a&gt;. It consumes a &lt;a href=&quot;https:&#x2F;&#x2F;www.fusejs.io&#x2F;&quot;&gt;fuse&lt;&#x2F;a&gt; index
(in my case, &lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;documentation&#x2F;content&#x2F;search&#x2F;&quot;&gt;generated by
Zola&lt;&#x2F;a&gt;) and emits a WASM
binary containing the index and search engine that can be loaded by the site
and hooked up to an input element (see the search bar above).&lt;&#x2F;p&gt;
&lt;p&gt;The functionality is great, but it&#x27;s incompatible with
&lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;&quot;&gt;&lt;code&gt;nix&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; in its current state, as the tinysearch generator
requires network access. In particular, it:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;generates a &lt;code&gt;storage&lt;&#x2F;code&gt; blob in its preferred format from the Zola-emitted
search index&lt;&#x2F;li&gt;
&lt;li&gt;generates an &quot;engine&quot; crate containing the search logic, which also embeds
the &lt;code&gt;storage&lt;&#x2F;code&gt; blob&lt;&#x2F;li&gt;
&lt;li&gt;calls &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rustwasm&#x2F;wasm-pack&quot;&gt;&lt;code&gt;wasm-pack&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to build the
engine crate
&lt;ul&gt;
&lt;li&gt;which calls &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rustwasm&#x2F;wasm-bindgen&quot;&gt;&lt;code&gt;wasm-bindgen&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;which shells out to &lt;code&gt;cargo&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;calls &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;WebAssembly&#x2F;binaryen&quot;&gt;&lt;code&gt;wasm-opt&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; on the result
(optionally) to reduce size&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The bolded step requires network access because &lt;code&gt;cargo build&lt;&#x2F;code&gt; has to download
dependencies. Nix tooling normally solves for this by vendoring dependencies
using the crate&#x27;s &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; and then invoking &lt;code&gt;cargo build --offline&lt;&#x2F;code&gt;, but
it&#x27;s not possible to configure this through the &lt;code&gt;tinysearch&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;wasm-pack&lt;&#x2F;code&gt; -&amp;gt;
&lt;code&gt;wasm-bindgen&lt;&#x2F;code&gt; stack.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;nix-port&quot;&gt;nix port&lt;&#x2F;h2&gt;
&lt;p&gt;I ported &lt;code&gt;tinysearch&lt;&#x2F;code&gt; support to Nix in a pair of packages:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tinysearch&lt;&#x2F;code&gt;: search index generator — consumes a fuse index, outputs
a &lt;code&gt;storage&lt;&#x2F;code&gt; blob (runs on the host, ported using &lt;a href=&quot;https:&#x2F;&#x2F;crane.dev&#x2F;&quot;&gt;crane&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; produces tinysearch index at .&#x2F;store&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tinysearch&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;m&lt;&#x2F;span&gt; store search_index.en.json&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tinysearch_engine&lt;&#x2F;code&gt;: wasm payload and js wrapper to be loaded by website
&lt;ul&gt;
&lt;li&gt;Base &lt;code&gt;wasm&lt;&#x2F;code&gt; payload built directly through &lt;code&gt;cargo build --target wasm32-unknown-unknown&lt;&#x2F;code&gt;, via crane&lt;&#x2F;li&gt;
&lt;li&gt;Invoke &lt;code&gt;wasm_bindgen --target web&lt;&#x2F;code&gt; on the result to produce the js wrapper&lt;&#x2F;li&gt;
&lt;li&gt;Invoke &lt;code&gt;wasm-opt&lt;&#x2F;code&gt; on that result to minimize wasm payload size&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I include it in my blog build like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# flake.nix -- details elided for concision&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;inputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;tinysearch_nix&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;url&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;git+https:&#x2F;&#x2F;pub.npry.dev&#x2F;tinysearch_nix&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;outputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-entity z-function z-2 z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;... &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt; @ &lt;span class=&quot;z-variable z-parameter z-function z-3 z-nix&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;eachDefaultSystem&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-4 z-nix&quot;&gt;system&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;let&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-nix&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;            &lt;span class=&quot;z-keyword z-other z-inherit z-nix&quot;&gt;inherit&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-single z-nix&quot;&gt;system&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-inherit z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;            &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;overlays&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;                &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;tinysearch_nix&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;overlays&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;default&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;            &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;in&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;packages&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;callPackage&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-path z-nix&quot;&gt;.&#x2F;blog.nix&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# blog.nix&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;runCommand&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;tinysearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;tinysearch_engine&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;runCommand&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;my_blog&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-other z-start z-nix&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;    # blog build elided
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;    blog_generate_index | \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;        &lt;span class=&quot;z-markup z-italic&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-nix&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;tinysearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;generate_index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;bin&#x2F;tinysearch_generate_index &amp;gt; $out&#x2F;tinysearch_index
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;    cp &lt;span class=&quot;z-markup z-italic&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-nix&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;tinysearch_engine&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; $out&#x2F;tinysearch_engine
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;    cp &lt;span class=&quot;z-markup z-italic&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-nix&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-path z-nix&quot;&gt;.&#x2F;search.js&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; $out&#x2F;search.js
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-other z-end z-nix&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;engine-changes&quot;&gt;engine changes&lt;&#x2F;h3&gt;
&lt;p&gt;I changed &lt;code&gt;tinysearch_engine&lt;&#x2F;code&gt; to not embed the search index; rather, the
wasm blob is now &lt;em&gt;just&lt;&#x2F;em&gt; the search engine, and you dynamically load (possibly
multiple) indices into it before using it. The result is less &quot;batteries
included&quot; and requires another roundtrip to the server, but is more
straightforwardly compatible with the Nix build process.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Before:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-ts&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;init&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;tinysearch&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Init tinysearch engine.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Submit a user query.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;search&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;user_search&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;load_filters&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-ts&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;init&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;tinysearch&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;fetch_index&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;index_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;resp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;fetch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;index_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blob&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;resp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;blob&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;blob&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array-binding-pattern-variable z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;index_store&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-ts&quot;&gt;]&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-promise z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Init tinysearch engine.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Fetch the search index from the backend.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;fetch_index&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;tinysearch_index&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Load the index into tinysearch.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;filters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;load_filters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;index_store&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Submit a user query.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;search&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;filters&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;user_search&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;And technically more flexible, in that you can load the engine and index
separately — e.g. per-user site indices, dynamically updating the
active index with up-to-date information, or loading multiple indices for
distinct search domains.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>git web frontends</title>
        <published>2024-08-09T00:00:00+00:00</published>
        <updated>2024-08-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/git-repo-frontends/"/>
        <id>https://blog.npry.dev/git-repo-frontends/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/git-repo-frontends/">&lt;p&gt;Maybe I&#x27;m unduly accustomed to the github UI, but to me the singularly useful
way to view a git repo is a unified file tree + readme page. It&#x27;s unfortunate
that there appear to be no standalone web frontends that do this.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;motivation&quot;&gt;motivation&lt;&#x2F;h2&gt;
&lt;p&gt;When I&#x27;m glancing at a git repo, I want:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;basic documentation&lt;&#x2F;li&gt;
&lt;li&gt;access to files in the repo&lt;&#x2F;li&gt;
&lt;li&gt;ability to change branch &#x2F; tag&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;availability&quot;&gt;availability&lt;&#x2F;h2&gt;
&lt;p&gt;Plenty of git &lt;em&gt;hosting&lt;&#x2F;em&gt; tools provide this experience all in one place —
github, &lt;a href=&quot;https:&#x2F;&#x2F;gitea.com&quot;&gt;gitea&lt;&#x2F;a&gt;&#x2F;&lt;a href=&quot;https:&#x2F;&#x2F;gogs.io&quot;&gt;gogs&lt;&#x2F;a&gt;, and now gitlab&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
to my knowledge have the tree-and-readme page figured out — but I can&#x27;t find
any standalone git web frontends that do the same.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Git-on-the-Server-GitWeb&quot;&gt;gitweb&lt;&#x2F;a&gt; shows a
commit shortlog as the summary, and the tree page doesn&#x27;t render readmes.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git.zx2c4.com&#x2F;cgit&#x2F;about&#x2F;&quot;&gt;cgit&lt;&#x2F;a&gt; (which I&#x27;m currently using) has
separate &quot;about&quot; (rendered readme) and tree pages. I also want to dump C if
possible.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;sr.ht&quot;&gt;sourcehut&lt;&#x2F;a&gt; (hosting service) separates the rendered readme
and tree.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git.icyphox.sh&quot;&gt;legit&lt;&#x2F;a&gt; separates the rendered readme and tree.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;narkoz.github.io&#x2F;ginatra&quot;&gt;ginatra&lt;&#x2F;a&gt; appears not have readme and tree
on the main repo summary page, based on screenshots. Unclear if they&#x27;re
rendered together. Not usually willing to run Ruby anyway.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;bitubucket.org&quot;&gt;bitbucket&lt;&#x2F;a&gt; (hosting service) is owned by Atlassian.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;klausdemo.lophus.org&quot;&gt;klaus&lt;&#x2F;a&gt; has the features I want, but 500ed
several times as I was browsing the demo site (and is ugly, imo).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I will probably fork one of these projects or write my own when I&#x27;m
procrastinating sometime soon, but I&#x27;m honestly shocked there isn&#x27;t something
that exists for me.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-do-i-care&quot;&gt;why do i care&lt;&#x2F;h2&gt;
&lt;p&gt;Gitea hosts all of my personal source code, but I don&#x27;t want to use it as the
frontend for &lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&quot;&gt;https:&#x2F;&#x2F;pub.npry.dev&lt;&#x2F;a&gt; — my public source code is a
read-only set of HTTP-accessible git repos, and I intend for it to stay that
way.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;I believe this wasn&#x27;t the case until quite recently.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>rdap crawler monitor</title>
        <published>2024-08-09T00:00:00+00:00</published>
        <updated>2024-08-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/rdap/"/>
        <id>https://blog.npry.dev/rdap/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/rdap/">&lt;p&gt;As part of a long train of dependencies and distractions involved in setting
the CORS headers for &lt;a href=&quot;..&#x2F;resenv&#x2F;ocularium&quot;&gt;ocularium&lt;&#x2F;a&gt;&#x27;s
&lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&#x2F;ocularium&#x2F;tree&quot;&gt;schematics&lt;&#x2F;a&gt;, I discovered a number of web
crawlers accessing pages my robots.txt told them not to, so I decided to IP
blacklist them in my reverse proxy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tcpdump-wireshark&quot;&gt;tcpdump -&amp;gt; wireshark&lt;&#x2F;h2&gt;
&lt;p&gt;I don&#x27;t generally leave http access logs on, and I figured there was probably a
less-invasive and -stateful way to capture the source IPs I as interested in
than updating my nginx config. I went with this &lt;code&gt;tcpdump&lt;&#x2F;code&gt; invocation initially,
inspecting HTTP traffic behind my TLS termination with &lt;code&gt;wireshark&lt;&#x2F;code&gt;, looking for
&lt;code&gt;X-Forwarded-For&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ssh &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_SYSTEM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tcpdump -s 0 -U -n -w - -i &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;IFACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; out.pcap&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-and z-shell&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;wireshark&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This became time-consuming as there were a lot of subnets to block, all coming
from Huawei Cloud (Singapore) IPs, and I had to rerun, analyze the capture, and
add to my blacklist in repeated batches.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tshark&quot;&gt;tshark&lt;&#x2F;h2&gt;
&lt;p&gt;Once I had enough of this manual process I found &lt;code&gt;tshark&lt;&#x2F;code&gt;, a commandline
interface to wireshark&#x27;s functionality, and was able to stream WHOIS results:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ssh &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_SYSTEM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tcpdump -s 0 -U -n -w - -i &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;IFACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tshark&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;        -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; -&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;Y&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;http.request.uri.path contains &amp;quot;&#x2F;interesting&amp;quot; &amp;amp;&amp;amp; http.x_forwarded_for&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;        -&lt;&#x2F;span&gt;T&lt;&#x2F;span&gt; fields&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;e&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;http.x_forwarded_for&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n1&lt;&#x2F;span&gt; whois&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;egrep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;route|CIDR|Organization|Country|netname&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;line-buffered&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Country:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; SG&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;route:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 94.74.80.0&#x2F;20&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Country:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ZZ&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Country:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; SG&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;netname:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Huawei-Cloud-SG&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This hacked approach worked but gave pretty ugly and imprecise results, and by
this point I figured I was seeing enough volume consistently that it was worth
going the whole nine yards and packaging it up into a systemd service whose
logs I can grep at my leisure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;full-automation&quot;&gt;full automation&lt;&#x2F;h2&gt;
&lt;p&gt;First, &lt;code&gt;tshark&lt;&#x2F;code&gt; can take over &lt;code&gt;tcpdump&lt;&#x2F;code&gt;&#x27;s responsibilities:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tshark&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;IFACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;Y&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;FILTER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;T&lt;&#x2F;span&gt; fields&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;e&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;http.x_forwarded_for&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then to make the results nicer than the whois -&amp;gt; grep from above, so it&#x27;d
be easy to read and the association ip -&amp;gt; owner, it turns out
&lt;a href=&quot;https:&#x2F;&#x2F;about.rdap.org&#x2F;&quot;&gt;RDAP&lt;&#x2F;a&gt; is the new iteration of WHOIS — basically
the same info, just in a REST JSON API — and there are plenty of free
services out there. I came across &lt;a href=&quot;https:&#x2F;&#x2F;www.ripe.net&#x2F;&quot;&gt;RIPE&lt;&#x2F;a&gt; first and wrote
a quick Python script that reads IPs off of stdin and logs &lt;code&gt;(IP, CIDR, owner, country)&lt;&#x2F;code&gt; with a Bash script to feed it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;!&#x2F;usr&#x2F;bin&#x2F;env bash&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-set z-shell&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; -euo pipefail&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tshark&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;IFACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;Y&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;FILTER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;T&lt;&#x2F;span&gt; fields&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;e&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;EXPR&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rdap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And a systemd service unit, expressed as a &lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&quot;&gt;NixOS&lt;&#x2F;a&gt; module.&lt;&#x2F;p&gt;
&lt;p&gt;Results of the first few hours (I had already blocked the worst-offending
subnets -- this is comparatively slow):&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;22:20:59 cidrs=[&amp;#39;94.74.80.0&#x2F;20&amp;#39;] country=SG ip=94.74.93.108 name=Huawei-Cloud-SG
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;22:22:28 cidrs=[&amp;#39;114.119.172.0&#x2F;22&amp;#39;] country=SG ip=114.119.174.108 name=Huawei-Cloud-Singapore
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;22:24:14 cidrs=[&amp;#39;166.108.192.0&#x2F;19&amp;#39;] country=SG ip=166.108.201.248 name=Huawei-Cloud-SG
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;23:43:56 cidrs=[&amp;#39;159.138.80.0&#x2F;20&amp;#39;] country=SG ip=159.138.85.139 name=Huawei-SG-CLOUDS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;00:11:57 cidrs=[&amp;#39;159.138.80.0&#x2F;20&amp;#39;] country=SG ip=159.138.85.139 name=Huawei-SG-CLOUDS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;00:17:50 cidrs=[&amp;#39;159.138.80.0&#x2F;20&amp;#39;] country=SG ip=159.138.85.139 name=Huawei-SG-CLOUDS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;00:38:07 cidrs=[&amp;#39;159.138.80.0&#x2F;20&amp;#39;] country=SG ip=159.138.88.165 name=Huawei-SG-CLOUDS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;01:39:10 cidrs=[&amp;#39;159.138.80.0&#x2F;20&amp;#39;] country=SG ip=159.138.85.139 name=Huawei-SG-CLOUDS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;02:02:30 cidrs=[&amp;#39;159.138.80.0&#x2F;20&amp;#39;] country=SG ip=159.138.85.139 name=Huawei-SG-CLOUDS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;02:42:54 cidrs=[&amp;#39;159.138.80.0&#x2F;20&amp;#39;] country=SG ip=159.138.85.139 name=Huawei-SG-CLOUDS
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I plan to publish the scripts and NixOS module sooner or later.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;postscript-robots-txt&quot;&gt;postscript: &lt;code&gt;robots.txt&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;As it turns out, I had originally misconfigured nginx and only had &lt;code&gt;robots.txt&lt;&#x2F;code&gt;
for the default http vhost, meaning none of the crawlers I was looking at ever
saw it -- amazonbot probably wasn&#x27;t being impolite.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>ocularium v0.1.0</title>
        <published>2024-08-08T00:00:00+00:00</published>
        <updated>2024-09-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/ocularium/"/>
        <id>https://blog.npry.dev/resenv/ocularium/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/ocularium/">&lt;link rel=&quot;stylesheet&quot; href=&quot;ocularium.css&quot;&#x2F;&gt;
&lt;script async type=&quot;module&quot; src=&quot;https:&#x2F;&#x2F;ajax.googleapis.com&#x2F;ajax&#x2F;libs&#x2F;model-viewer&#x2F;3.5.0&#x2F;model-viewer.min.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;script async type=&quot;module&quot; src=&quot;board_zoom.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;script async type=&quot;module&quot; src=&quot;annotations.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;p&gt;&lt;em&gt;Board renders, schematics, interactive bom, and fabrication files on this page
were automatically generated by &lt;a href=&quot;..&#x2F;..&#x2F;clef&quot;&gt;clef&lt;&#x2F;a&gt; + &lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&quot;&gt;Nix&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;ocularium&#x2F;bom&#x2F;ibom.html&quot;&gt;interactive bom&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;div id=&quot;model_parent&quot;&gt;
    &lt;model-viewer src=&quot;&#x2F;ocularium&#x2F;model&#x2F;okm.glb&quot; shadow-intensity=&quot;1&quot; camera-controls touch-action=&quot;pan-y&quot; environment-image=&quot;https:&#x2F;&#x2F;modelviewer.dev&#x2F;shared-assets&#x2F;environments&#x2F;music_hall_01_1k.hdr&quot;&gt;
        &lt;noscript&gt;
            &lt;p&gt;JavaScript disabled, model viewer not loaded.&lt;&#x2F;p&gt;
            &lt;a href=&quot;&#x2F;ocularium&#x2F;model&#x2F;okm.glb&quot;&gt;Download board model (.glb)&lt;&#x2F;a&gt;
        &lt;&#x2F;noscript&gt;
        &lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-1&quot; data-position=&quot;0.14760093670821386m 0.0026000000160187487m 0.09963027191667925m&quot; data-normal=&quot;0m 1m 0m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;rp2040 (microcontroller)&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;&lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-2&quot; data-position=&quot;0.13439221206217564m 0.004166923014032854m 0.10490555174254299m&quot; data-normal=&quot;0m 1m 0m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;veml7700 (lux)&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;&lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-3&quot; data-position=&quot;0.14069545004446807m -0.002050000094994888m 0.10398218950734957m&quot; data-normal=&quot;4.4408920985006257e-16m -1m -9.860761315262644e-32m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;micro SD&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;&lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-4&quot; data-position=&quot;0.1599382733020378m -0.0033099999103695177m 0.10126869139545787m&quot; data-normal=&quot;-4.440892098500625e-16m -1m -9.860761315262643e-32m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;usb-c (charging)&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;&lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-5&quot; data-position=&quot;0.14117298271012144m 0.0026300000116229196m 0.08929344628723895m&quot; data-normal=&quot;-3.9518573113016147e-32m 1m 2.2204460492503136e-16m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;microphone&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;&lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-6&quot; data-position=&quot;0.15221604145787268m -0.0008300000021234221m 0.1035482132730995m&quot; data-normal=&quot;-1.2246467991473532e-16m -1m 3.951857311301614e-32m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;accel &amp;amp; gyro&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;&lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-7&quot; data-position=&quot;0.14205263746719196m 0.002430000002123416m 0.10618781385778686m&quot; data-normal=&quot;0m 1m 0m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;bme680 (gas)&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;
        &lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-8&quot; data-position=&quot;0.14436974369641598m 0.0037681753294515974m 0.11432977456046267m&quot; data-normal=&quot;0.9975640484642385m 0.06975649942219526m 1.3765541624477502e-16m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;debug&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;
        &lt;button class=&quot;Hotspot&quot; slot=&quot;hotspot-9&quot; data-position=&quot;0.15372688248764602m 0.0031500000130385165m 0.11273835360211604m&quot; data-normal=&quot;0m 1m 0m&quot; data-visibility-attribute=&quot;visible&quot;&gt;
            &lt;div class=&quot;HotspotAnnotation&quot;&gt;battery&lt;&#x2F;div&gt;
        &lt;&#x2F;button&gt;
    &lt;&#x2F;model-viewer&gt;
    &lt;div id=&quot;annotations&quot;&gt;
        &lt;input type=&quot;checkbox&quot; unchecked&gt;
        &lt;label&gt;annotations&lt;&#x2F;label&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;em&gt;ocularium&lt;&#x2F;em&gt; is a tiny sensor platform I designed to be flown on kites. I&#x27;m
working with &lt;a href=&quot;https:&#x2F;&#x2F;chuchoocampo.com&quot;&gt;Chucho Ocampo&lt;&#x2F;a&gt; on this project, who I
met on &lt;a href=&quot;https:&#x2F;&#x2F;www.media.mit.edu&#x2F;projects&#x2F;lunar-research-in-lanzarote&#x2F;overview&#x2F;&quot;&gt;SEI&#x27;s trip to
Lanzarote&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;board_outer&quot;&gt;
&lt;div class=&quot;board_inner&quot;&gt;
    &lt;div class=&quot;board_wrap&quot;&gt;
        &lt;img src=&quot;&#x2F;ocularium&#x2F;svg&#x2F;front.trim.svg&quot; class=&quot;boardimg noborder&quot;&#x2F;&gt;
        &lt;i&gt;front&lt;&#x2F;i&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;board_wrap&quot;&gt;
        &lt;img src=&quot;&#x2F;ocularium&#x2F;svg&#x2F;in1.trim.svg&quot; class=&quot;boardimg noborder&quot;&#x2F;&gt;
        &lt;i&gt;in1&lt;&#x2F;i&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;board_wrap&quot;&gt;
        &lt;img src=&quot;&#x2F;ocularium&#x2F;svg&#x2F;in2.trim.svg&quot; class=&quot;boardimg noborder&quot;&#x2F;&gt;
        &lt;i&gt;in2&lt;&#x2F;i&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;board_wrap&quot;&gt;
        &lt;img src=&quot;&#x2F;ocularium&#x2F;svg&#x2F;back.mirror.trim.svg&quot; class=&quot;boardimg noborder&quot;&#x2F;&gt;
        &lt;i&gt;reverse&lt;&#x2F;i&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;div style=&quot;display: flex; flex-direction: column; width: 100%; align-items: center&quot;&gt;
    &lt;i style=&quot;max-width: 75%&quot; class=&quot;actual_size_disclaimer&quot;&gt;
        These board files are actual-size on your screen if your browser is at
        normal (100%) zoom.
    &lt;&#x2F;i&gt;
    &lt;button id=&quot;zoom_boards&quot; style=&quot;display: none; margin: 1rem&quot;&gt;Toggle Zoom&lt;&#x2F;button&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;The design is finished, and as of writing this post I&#x27;m just sending it out to
be fabricated.&lt;&#x2F;p&gt;
&lt;object data=&quot;&#x2F;ocularium&#x2F;schematic&#x2F;schematic.pdf&quot; type=&quot;application&#x2F;pdf&quot; style=&quot;width: 100%; height: 500px&quot;&gt;
    &lt;a href=&quot;&#x2F;ocularium&#x2F;schematic&#x2F;schematic.pdf&quot;&gt;Rendered Schematics (PDF)&lt;&#x2F;a&gt;
&lt;&#x2F;object&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;ocularium&#x2F;fab&#x2F;gerbers.zip&quot;&gt;gerbers.zip&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;ocularium&#x2F;fab&#x2F;bom.csv&quot;&gt;bom&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;ocularium&#x2F;fab&#x2F;pos.csv&quot;&gt;placement file&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;&#x2F;strong&gt;: these production files &lt;em&gt;have not been validated&lt;&#x2F;em&gt; — I am
in the process of converting to kikit (which generates them and puts them here)
but spun the boards using &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bennymeg&#x2F;Fabrication-Toolkit&quot;&gt;Fabrication
Toolkit&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design&quot;&gt;design&lt;&#x2F;h2&gt;
&lt;p&gt;The board is 30x30mm with a 25x25mm M2 hole pattern. It&#x27;s powered by a lithium
cell via a battery controller, and uses an SD card for data storage. The
sensors onboard are a six-axis accelerometer&#x2F;gyro, a BME680 gas sensor
(temperature, humidity, pressure, air quality), a lux sensor, and a MEMS
microphone.&lt;&#x2F;p&gt;
&lt;p&gt;Design goals:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Small and light, to minimize impact on the kite&#x27;s flight -- Chucho&#x27;s previous
solution was bulky&#x2F;heavy and would pull the kite&lt;&#x2F;li&gt;
&lt;li&gt;Useful &#x2F; interesting sensor payload&lt;&#x2F;li&gt;
&lt;li&gt;~4-hour endurance -- long enough to be forgiving about state of charge&lt;&#x2F;li&gt;
&lt;li&gt;Low-cost&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;software-firmware&quot;&gt;software &#x2F; firmware&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;m writing the firmware in &lt;a href=&quot;http:&#x2F;&#x2F;rust-lang.org&quot;&gt;Rust&lt;&#x2F;a&gt; using the
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;embassy-rs&#x2F;embassy&quot;&gt;embassy&lt;&#x2F;a&gt; family of embedded libraries.&lt;&#x2F;p&gt;
&lt;p&gt;I am currently planning on writing a host-side UI in &lt;a href=&quot;https:&#x2F;&#x2F;iced.rs&#x2F;&quot;&gt;iced&lt;&#x2F;a&gt;,
which I&#x27;ve had luck with in the past (I&#x27;m using it for an in-progress mission
UI for &lt;a href=&quot;..&#x2F;antrelay&quot;&gt;antrelay&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;future-work&quot;&gt;future work&lt;&#x2F;h2&gt;
&lt;p&gt;I will be tying this in with &lt;a href=&quot;..&#x2F;interstice&quot;&gt;interstice&lt;&#x2F;a&gt; as a networking test
platform.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bringup-log&quot;&gt;bringup log&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;2024-08-22&quot;&gt;2024-08-22&lt;&#x2F;h3&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;board_assy_front.961d20d2d62c4827.jpg&quot;&gt;

    
    &lt;i style=&quot;margin-top: 0.5rem&quot;&gt;
        &lt;p&gt;depaneled board, front&lt;&#x2F;p&gt;

    &lt;&#x2F;i&gt;
    
&lt;&#x2F;div&gt;
&lt;p&gt;Boards came in today. Production went well — they look great. I&#x27;m looking
at a power issue: the &lt;a href=&quot;https:&#x2F;&#x2F;www.ti.com&#x2F;product&#x2F;BQ25185&quot;&gt;BQ25185&lt;&#x2F;a&gt; battery
charger IC has a regulated output that I was using to supply 3.3V. Problem is
that it&#x27;s actually 4.5V — didn&#x27;t catch this at design time. In
retrospect, I think I had it as a placeholder part that I planned to replace
(or augment with a DCDC), but it slipped through the cracks.&lt;&#x2F;p&gt;
&lt;p&gt;Also have an ADC problem — I have VBAT, VUSB, and 3.3V connected to ADC
lines, but I didn&#x27;t add voltage dividers, so they&#x27;re overvolting the ADCs and I
suspect leaking through the ESD protection, if not damaging the silicon. I
still have 2 untouched assembled boards if I already managed to burn one out.&lt;&#x2F;p&gt;
&lt;p&gt;Going to have to respin, but provisionally powering 3.3V directly off of my
bench supply to enable bringup on this rev and find any more issues.&lt;&#x2F;p&gt;
&lt;p&gt;Tried to connect over SWD with an st-link clone, but it appears they &lt;a href=&quot;https:&#x2F;&#x2F;community.st.com&#x2F;t5&#x2F;stm32-mcus-boards-and-hardware&#x2F;swd-multidrop-does-any-stm32-or-st-link-support-it&#x2F;td-p&#x2F;80861&quot;&gt;don&#x27;t
support
multidrop&lt;&#x2F;a&gt;,
which seems to be required for rp2040. Tried flashing &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;blackmagic-debug&#x2F;blackmagic&quot;&gt;black magic
probe&lt;&#x2F;a&gt;, which notionally
addresses this, but it couldn&#x27;t see the core. Ordered a few picos (I seem to
have run out) to flash &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;debugprobe&quot;&gt;picoprobe&lt;&#x2F;a&gt;
onto, which I know will work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2024-08-26&quot;&gt;2024-08-26&lt;&#x2F;h3&gt;
&lt;div style=&quot;display: flex; flex-direction: column; align-items: center; padding: 1rem&quot; class=&quot;vidwrap&quot;&gt;
    &lt;video
        src=&quot;blink.webm&quot;
        
        muted
        controls
        
        autoplay
        
        
        loop
        
        class=&quot;hover_controls&quot;
        style=&quot;width: 480px; border-radius: 1rem&quot;
    &gt;
    &lt;&#x2F;video&gt;
    
    &lt;i style=&quot;margin-top: 0.5rem&quot;&gt;
        &lt;p&gt;she blinks&lt;&#x2F;p&gt;

    &lt;&#x2F;i&gt;
    
&lt;&#x2F;div&gt;

&lt;p&gt;Got my picos set up as &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;debugprobe&quot;&gt;picoprobes&lt;&#x2F;a&gt;,
but no dice. Hooked up to my logic analyzer and saw well-formed SWD traffic. I
don&#x27;t know the protocol so couldn&#x27;t tell if there was any response data, but I
assumed not as &lt;a href=&quot;https:&#x2F;&#x2F;probe.rs&#x2F;&quot;&gt;&lt;code&gt;probe-rs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; complained that the device wasn&#x27;t
responding:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; probe-rs info&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;chip&lt;&#x2F;span&gt; rp2040&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;protocol&lt;&#x2F;span&gt; swd&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;target-sel&lt;&#x2F;span&gt; 0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Probing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; target via SWD&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; showing ARM chip information: An ARM specific error occurred.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Caused&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; by:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;0:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; An ARM specific error occurred.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;1:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Failed to connect to the debug port. Please check the debug cable and target power. If SWD multi-drop is used, ensure the correct TARGETSEL value is used.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My priority is get the rp2040 powering on and be able to flash code, so I moved
on to triggering BOOTSEL mode. Shorted &lt;code&gt;QSPI_SS&lt;&#x2F;code&gt; to &lt;code&gt;GND&lt;&#x2F;code&gt; and plugged in via
USB, but measured voltage on my power supply shot up to &amp;gt; 3.5V and it wasn&#x27;t
sourcing any current, implying that the circuit was powering itself off of USB,
even with the switch between &lt;code&gt;VSYS&lt;&#x2F;code&gt; (battery charger output, 4.5V —
discussed in last entry) and 3.3V turned off. I don&#x27;t know how — the only
place VUSB goes other than the charger IC are the ADC pins. Could be something
fried and bridged the nets, but in this whole process I&#x27;ve neither seen magic
smoke nor noticed comonents getting warm — that&#x27;s no more than
speculation at the moment.&lt;&#x2F;p&gt;
&lt;p&gt;On my last untouched board, I cut the VUSB traces right at the USB connector
and verified open circuit to the regulator. Again shorted QSPI_SS to ground,
powered on with my bench supply, and connected to USB.&lt;&#x2F;p&gt;
&lt;p&gt;Linux tries to connect, but can&#x27;t talk to the device:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; dmesg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427079.861946]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4-port3: attempt power cycle&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427080.457606]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4.3: new low-speed USB device number 91 using ehci-pci&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427080.869588]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4.3: device not accepting address 91, error&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427080.945619]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4.3: new low-speed USB device number 92 using ehci-pci&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427081.357619]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4.3: device not accepting address 92, error&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Seems like progress, but I logic analyzed this too, and the rp2040 isn&#x27;t even
trying to respond — the traffic on the bus is just the host sending
&lt;code&gt;SETUP&lt;&#x2F;code&gt; and &lt;code&gt;DATA0 -&amp;gt; GET_DESCRIPTOR&lt;&#x2F;code&gt; packets until it gives up.&lt;&#x2F;p&gt;
&lt;p&gt;There is &lt;em&gt;something&lt;&#x2F;em&gt; happening on the board — when I power it, I see a
reproducible pattern of power usage stabilizing at single-digit milliamps on my
bench supply, but there&#x27;s no way for me to tell at present whether that&#x27;s from
the RP2040 or any of the other ICs.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;rescue-port&quot;&gt;rescue port&lt;&#x2F;h4&gt;
&lt;p&gt;Did some digging in the hardware design guide and saw this section about the
rescue debug port:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The rescue debug port (DP) on RP2040 can be used to reset the chip into a
known state if the user has programmed some bad code into the flash. For
example some code that turned off the system clock would stop the processor
debug ports being accessed, but the rescue DP would still work because it is
clocked from the SWCLK of the SWD interface.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This seems like exactly what I want, because the whole contents of my flash are
known to be garbage, as I&#x27;ve never flashed anything to the board before. The
question of why I haven&#x27;t been able to enter BOOTSEL mode is still open, but
hopefully this will let me bypass it.&lt;&#x2F;p&gt;
&lt;p&gt;It requires you to use the Raspberry Pi Foundation&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;openocd&quot;&gt;own independent fork of
openocd&lt;&#x2F;a&gt; (the practice of forking off
vendor-specific tooling continues to be a pain in the ass):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; openocd&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; interface&#x2F;cmsis-dap.cfg&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; target&#x2F;rp2040-rescue.cfg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;MY_SERIAL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : CMSIS-DAP: Interface Initialised (SWD&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : CMSIS-DAP: Interface ready&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Now&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; attach a debugger to your RP2040 and load some code&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; openocd&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; interface&#x2F;cmsis-dap.cfg&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; target&#x2F;rp2040.cfg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;MY_SERIAL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : CMSIS-DAP: Interface Initialised (SWD&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : CMSIS-DAP: Interface ready&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : clock speed 100 kHz&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : SWD DPIDR 0x0bc12477, DLPIDR 0x00000001&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : SWD DPIDR 0x0bc12477, DLPIDR 0x10000001&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;rp2040.core0&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; Cortex-M0+ r0p1 processor detected&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;rp2040.core0&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; target has 4 breakpoints, 2 watchpoints&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;rp2040.core1&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; Cortex-M0+ r0p1 processor detected&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;rp2040.core1&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; target has 4 breakpoints, 2 watchpoints&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : starting gdb server for rp2040.core0 on 3333&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(&lt;code&gt;openocd&lt;&#x2F;code&gt; output substantially cleaned for readability).&lt;&#x2F;p&gt;
&lt;p&gt;I connected with &lt;code&gt;gdb&lt;&#x2F;code&gt;, but this failed initially because it was trying to
identify my SPI flash and &lt;code&gt;QSPI_SS&lt;&#x2F;code&gt; (= &lt;code&gt;~BOOTSEL&lt;&#x2F;code&gt;) was still shorted to &lt;code&gt;GND&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : accepting &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gdb&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; connection on tcp&#x2F;3333&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Error:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Unknown flash device (ID 0x00ffffff&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Error:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; auto_probe failed&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Error:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect, or use &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gdb_memory_map disable&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Error:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; attempted &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gdb&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; connection rejected&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Fixed by opening this short:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : accepting &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gdb&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; connection on tcp&#x2F;3333&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : Found flash device &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;win w25q128fv&#x2F;jv&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (ID 0x001840ef&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : RP2040 B0 Flash Probe: 16777216 bytes @0x10000000, in 256 sectors&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; : New GDB Connection: 1, Target rp2040.core0, state: halted&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then flashed blinky firmware:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; gdb&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(gdb&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; extended-remote localhost:3333&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Remote&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; debugging using localhost:3333&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;0x00000030&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; in &lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(gdb&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;MY_BLINKY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; program is being debugged already.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;Are you sure you want to change the file&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt; (y or n&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Reading&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; symbols from &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;MY_BLINKY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(gdb&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;load&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Loading&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; section .boot2, size 0x100 lma 0x10000000&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Loading&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; section .vector_table, size 0xc0 lma 0x10000100&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Loading&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; section .text, size 0x4cd8 lma 0x100001c0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Loading&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; section .rodata, size 0xaac lma 0x10004ea0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Loading&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; section .data, size 0xb4 lma 0x1000594c&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; address 0x100001c0, load size 23032&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Transfer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rate: 1 KB&#x2F;sec, 3838 bytes&#x2F;write.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(gdb&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;The&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; program being debugged has been started already.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;Start it from the beginning&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt; (y or n&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div style=&quot;display: flex; flex-direction: column; align-items: center; padding: 1rem&quot; class=&quot;vidwrap&quot;&gt;
    &lt;video
        src=&quot;blink.webm&quot;
        
        muted
        controls
        
        autoplay
        
        
        loop
        
        class=&quot;hover_controls&quot;
        style=&quot;width: 480px; border-radius: 1rem&quot;
    &gt;
    &lt;&#x2F;video&gt;
    
&lt;&#x2F;div&gt;

&lt;p&gt;And now &lt;code&gt;probe-rs run&lt;&#x2F;code&gt; (via &lt;code&gt;cargo run&lt;&#x2F;code&gt;) works:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cargo run&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Finished&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; dev &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;optimized + debuginfo&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; target(s&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 0.12s&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Running&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-command z-backticks z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;probe-rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; run&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;chip&lt;&#x2F;span&gt; RP2040 target&#x2F;thumbv6m-none-eabi&#x2F;debug&#x2F;blinky&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Erasing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ✔ &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;00:00:00&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;############################&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; 24.00 KiB&#x2F;24.00 KiB @ 66.55 KiB&#x2F;s (eta 0s &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Programming&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ✔ &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;00:00:00&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;############################&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; 24.00 KiB&#x2F;24.00 KiB @ 42.71 KiB&#x2F;s (eta 0s &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Finished&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; in 0.95s&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;0.001210&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; INFO  boot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;probe-rs info&lt;&#x2F;code&gt; works, but it locks up the core and &lt;code&gt;probe-rs reset&lt;&#x2F;code&gt; doesn&#x27;t reset it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; probe-rs info&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;chip&lt;&#x2F;span&gt; rp2040&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;protocol&lt;&#x2F;span&gt; swd&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Probing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; target via SWD&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ARM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Chip:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Debug&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Port: Version 2, MINDP, Designer: Raspberry Pi Trading Ltd, Part: 0x1002, Revision: 0x0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; probe-rs reset&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;chip&lt;&#x2F;span&gt; rp2040&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;protocol&lt;&#x2F;span&gt; swd&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Error:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Connecting to the chip was unsuccessful.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Caused&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; by:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;0:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; An ARM specific error occurred.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;1:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; An ARM specific error occurred.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;2:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Failed to connect to the debug port. Please check the debug cable and target power. If SWD multi-drop is used, ensure the correct TARGETSEL value is used.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This last note about multidrop&#x2F;TARGETSEL could be the solution, but there isn&#x27;t
a flag to set TARGETSEL for &lt;code&gt;probe-rs reset&lt;&#x2F;code&gt;. Fine in the end — I can manually
reset with the power supply.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2024-08-27&quot;&gt;2024-08-27&lt;&#x2F;h3&gt;
&lt;p&gt;Working on USB, seeing the same issue as before: host sees the pull-up and
tries to contact the device a few times before giving up:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; dmesg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427079.861946]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4-port3: attempt power cycle&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427080.457606]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4.3: new low-speed USB device number 91 using ehci-pci&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427080.869588]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4.3: device not accepting address 91, error&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427080.945619]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4.3: new low-speed USB device number 92 using ehci-pci&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1427081.357619]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 2-1.4.4.3: device not accepting address 92, error&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;m testing with firmware that I&#x27;ve flashed to a &lt;a href=&quot;https:&#x2F;&#x2F;www.seeedstudio.com&#x2F;XIAO-RP2040-v1-0-p-5026.html&quot;&gt;XIAO
RP2040&lt;&#x2F;a&gt;, which
successfully establishes a high-speed link and opens a CDC-ACM port which is
recognized by the host computer. Expected output:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; dmesg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1506678.033057]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 1-1.5: new full-speed USB device number 22 using ehci-pci&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1506678.113650]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 1-1.5: New USB device found, idVendor=8888, idProduct=0001, bcdDevice= 0.10&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1506678.113655]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 1-1.5: New USB device strings: Mfr=1, Product=2, SerialNumber=0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1506678.113656]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 1-1.5: Product: &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;PRODUCT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1506678.113657]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; usb 1-1.5: Manufacturer: npry&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;[1506678.114587]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cdc_acm 1-1.5:1.0: ttyACM1: USB ACM device&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Probed voltage on D+ and I&#x27;m seeing 3.0V with a cable plugged in rather than
expected 3.3V for LS operation. D- is at ground potential. Possibly an issue
with drive strength on the USB peripheral on the RP2040? But apparently 2.8V is
the specified signaling minimum, so perhaps this shouldn&#x27;t be surprising. Tried
a few different USB cables that have been known to work and different ports on
the host, no dice.&lt;&#x2F;p&gt;
&lt;p&gt;Probed D+ with USB cable disconnected and I&#x27;m seeing 3.20V, which for me counts
as effectively nominal for a specified 3.3V.&lt;&#x2F;p&gt;
&lt;p&gt;Tried shorting the 27.4Ω impedance-matching resistors just for something
to try — no change.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;cc2-vconn&quot;&gt;cc2 &#x2F; vconn&lt;&#x2F;h4&gt;
&lt;p&gt;Found an issue on my schematic: CC2 wasn&#x27;t terminated — I left it
floating. Another thing I intended to get back to at the time, but didn&#x27;t, and
then by the time I went to ship the board, I assumed past-me had validated it.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m testing with a USB A-to-C cable, which I suppose must internally have
orientation detection logic, so this seems a likely culprit — I
definitely need to fix it for the next rev. However, now I&#x27;m thinking back to
the fact that I got a signal that looked fine on a scope and decoded as valid
host-to-device control packets with a logic analyzer, probed right at the
impedance-matching resistors next to the rp2040 pins.&lt;&#x2F;p&gt;
&lt;p&gt;I &lt;em&gt;have&lt;&#x2F;em&gt; kept coming back to this idea that maybe my data lines are backwards,
but I&#x27;ve checked several times, and they weren&#x27;t. Then again, I&#x27;ve only been
checking by looking at the voltage at D+, the pull-up for which is
device-supplied, so possibly that&#x27;s not a reliable test. And when I scoped&#x2F;
logic-analyzed the traffic, I was looking at the BOOTSEL behavior, so there
could be another confounding issue.&lt;&#x2F;p&gt;
&lt;p&gt;Next thing I guess is to properly terminate CC2 and see if that makes a
difference.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2024-09-22&quot;&gt;2024-09-22&lt;&#x2F;h2&gt;
&lt;p&gt;Been almost a month since my last update — haven&#x27;t gotten around to
writing progress up. Mostly been working on &lt;a href=&quot;..&#x2F;molybdos&quot;&gt;molybdos&lt;&#x2F;a&gt; as a basis
for the firmware, converting chunks of old projects (e.g. &lt;a href=&quot;..&#x2F;janus&quot;&gt;janus&lt;&#x2F;a&gt;,
&lt;a href=&quot;..&#x2F;hexrx&quot;&gt;hexrx&lt;&#x2F;a&gt;) to portable library code, and porting third-party sensor
libraries to async (&lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&#x2F;drogue_bme680_async&quot;&gt;bme680&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&#x2F;lsm6dsm&quot;&gt;lsm6dsm&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&#x2F;veml7700_async&quot;&gt;veml7700_async&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The problem with USB &lt;em&gt;was&lt;&#x2F;em&gt; swapped polarity on the data lines — I was
able to rework it and verify the fix. I thought it was a footprint issue
initially, but I actually just swapped them in the schematic at the decoupling
resistors.&lt;&#x2F;p&gt;
&lt;p&gt;Also discovered that I got my I2C lines wrong — they&#x27;re attached to
different MCU peripherals. There doesn&#x27;t seem to be a good software or PIO
I2C implementation in Rust yet — I started writing a PIO one based on
the example in the RP2040 C SDK, but decided the verification overhead wasn&#x27;t
worth it right at this moment. Going to test by breaking out the bus and
connecting with my Bus Pirate or a Xiao board.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2024-09-24&quot;&gt;2024-09-24&lt;&#x2F;h2&gt;
&lt;p&gt;Got a PIO I2S driver semi-working — enough to get working PDM audio back.
Scaling the bits to &lt;code&gt;i16::MAX&lt;&#x2F;code&gt; and &lt;code&gt;i16::MIN&lt;&#x2F;code&gt; is enough to get recognizable but
choppy sound out of it.&lt;&#x2F;p&gt;
&lt;p&gt;The issue I&#x27;m dealing with is that the DMA shots from the PIO FIFOs to memory
are taking way longer (40x) than they should. I&#x27;m not sure yet whether I&#x27;m
miscalculating my clock, am missing something about PIO functionality, or if
it&#x27;s something with the host MCU (backpressure or scheduling). I&#x27;m running the
read loop in the regular thread-mode executor, so it could just be a scheduling
issue (though there shouldn&#x27;t be any other futures running concurrently, so that&#x27;s
kind of dubious). Next thing I&#x27;ll try is a dedicated higher-priority interrupt
executor just because it&#x27;s easy.&lt;&#x2F;p&gt;
&lt;p&gt;That said, not going to bother for now. I can hear audio, so I know it&#x27;s working
enough to proceed with the next rev.&lt;&#x2F;p&gt;
&lt;p&gt;Confirmed that the BME is reachable over its SPI bus by reading its chip id.
Not going to bother trying to read data off of it, just made sure I can talk
to it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2024-09-25&quot;&gt;2024-09-25&lt;&#x2F;h2&gt;
&lt;p&gt;Took a look at the SD card today — it wasn&#x27;t working right off the bat.
Looks like I flipped the MOSI and MISO lines (guessing I feel victim to the
SDO&#x2F;SDI terminology mismatch: CMD is &quot;data in&quot; but &quot;master out&quot; &#x2F; DAT0 is &quot;data
out&quot; but &quot;master in&quot;, and I matched on the wrong role). Reworking this would be
a pain in the ass because the pins are tiny, so I&#x27;m going to just blindly
respin it.&lt;&#x2F;p&gt;
&lt;p&gt;Also relevant: last week or so, I broke out &lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&#x2F;embedded_sdmmc_async&quot;&gt;my
fork&lt;&#x2F;a&gt; of &lt;code&gt;embedded_sdmmc&lt;&#x2F;code&gt; from the
&lt;a href=&quot;https:&#x2F;&#x2F;pub.npry.dev&#x2F;hexrx&quot;&gt;hexrx&lt;&#x2F;a&gt; firmare as a standalone repo.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2024-09-26&quot;&gt;2024-09-26&lt;&#x2F;h2&gt;
&lt;p&gt;Had to find my &lt;a href=&quot;https:&#x2F;&#x2F;www.sparkfun.com&#x2F;products&#x2F;12942&quot;&gt;bus pirate&lt;&#x2F;a&gt; yesterday
— ran I2C sanity checks today:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bus-scan&quot;&gt;bus scan&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C&amp;gt;(1)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Searching I2C address space. Found devices at:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;0x20(0x10 W) 0x21(0x10 R) 0xD6(0x6B W) 0xD7(0x6B R)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Correctly found the VEML7700 at 0x10 and the LSM6DSM at 0x6B.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lsm6dsm&quot;&gt;lsm6dsm&lt;&#x2F;h3&gt;
&lt;p&gt;Find &lt;code&gt;WHOAMI&lt;&#x2F;code&gt; reg (0x0f):&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C&amp;gt;[0xd6 0x0f [0xd7 r]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C START BIT
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;WRITE: 0xD6 ACK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;WRITE: 0x0F ACK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C START BIT
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;WRITE: 0xD7 ACK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;READ: 0x6A
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NACK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C STOP BIT
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sees correct value 0x6a.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;veml7700&quot;&gt;veml7700&lt;&#x2F;h3&gt;
&lt;p&gt;chipid reg at 0x7:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C&amp;gt;[0x20 0x7 [0x21 rr]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C START BIT
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;WRITE: 0x20 ACK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;WRITE: 0x07 ACK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C START BIT
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;WRITE: 0x21 ACK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;READ: 0x81
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;READ:  ACK 0xC4
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NACK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;I2C STOP BIT
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;16 bit registers, default configuration is 0xC4 with address 0x81 —
checks out.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;respin-todo&quot;&gt;respin todo&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
3V3 regulator&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
fix cc termination&lt;&#x2F;li&gt;
&lt;li&gt;adc
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
voltage dividers&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
voltage reference&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
purple LED -&amp;gt; change to blue (too dim)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
esd protection
&lt;ul&gt;
&lt;li&gt;VBUS, D+&#x2F;D-&lt;&#x2F;li&gt;
&lt;li&gt;SWCLK, SWDIO&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
usb data polarity&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
i2c pin fix&lt;&#x2F;li&gt;
&lt;li&gt;sd card fixes
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
fix mosi&#x2F;miso flip&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
(optional) card detect&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
connect sensor hub to i2c (solder jumpers, default-open)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
connect bme to i2c&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
switch to proper i2s part&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>home lab equipment</title>
        <published>2024-08-01T00:00:00+00:00</published>
        <updated>2024-08-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/home-lab/"/>
        <id>https://blog.npry.dev/home-lab/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/home-lab/">&lt;h2 id=&quot;electronics&quot;&gt;electronics&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B06XZML6RD&quot;&gt;Siglent SDS-1202X-E 2-channel
Oscilloscope&lt;&#x2F;a&gt;: $350&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B07K6HXDH1&quot;&gt;USB Logic Analyzer&lt;&#x2F;a&gt;, $14
&lt;ul&gt;
&lt;li&gt;Works in &lt;a href=&quot;https:&#x2F;&#x2F;www.saleae.com&#x2F;pages&#x2F;downloads&quot;&gt;Saleae Logic&lt;&#x2F;a&gt;, which is
the most important part of their package for me. Most of the time I don&#x27;t
need the super high sample rates, analog channels, or independent
per-channel grounds, but being able to write an
&lt;a href=&quot;https:&#x2F;&#x2F;support.saleae.com&#x2F;extensions&#x2F;high-level-analyzer-extensions&quot;&gt;HLA&lt;&#x2F;a&gt;
is great.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;store.arduino.cc&#x2F;products&#x2F;ts80p-main-smart-soldering-iron&quot;&gt;TS-80 USB-C powered soldering
iron&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;At the Media Lab I use a
&lt;a href=&quot;https:&#x2F;&#x2F;pine64.com&#x2F;product&#x2F;pinecil-smart-mini-portable-soldering-iron&#x2F;&quot;&gt;Pinecil&lt;&#x2F;a&gt;
at my desk — quite happy with both&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;amscope.com&#x2F;products&#x2F;se305r-p&quot;&gt;AmScope SE305 binocular microscope&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Cheap lab power supply&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;3d-print&quot;&gt;3d-print&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.creality.com&#x2F;products&#x2F;ender-3-3d-printer&quot;&gt;Creality Ender 3&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;a href=&quot;https:&#x2F;&#x2F;www.antclabs.com&#x2F;bltouch&quot;&gt;BLTouch&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;With &lt;a href=&quot;https:&#x2F;&#x2F;www.creality3dofficial.com&#x2F;products&#x2F;creality-silent-mainboard-v4-2-7&quot;&gt;silent mainboard (trinamic
drivers)&lt;&#x2F;a&gt;
running &lt;a href=&quot;https:&#x2F;&#x2F;www.klipper3d.org&#x2F;&quot;&gt;Klipper firmware&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;With raspi running &lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;&quot;&gt;NixOS&lt;&#x2F;a&gt;, Klipper,
&lt;a href=&quot;https:&#x2F;&#x2F;moonraker.readthedocs.io&#x2F;en&#x2F;latest&#x2F;&quot;&gt;moonraker&lt;&#x2F;a&gt;, and controlled
via &lt;a href=&quot;https:&#x2F;&#x2F;docs.mainsail.xyz&#x2F;&quot;&gt;mainsail&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;store.anycubic.com&#x2F;products&#x2F;anycubic-photon-s&quot;&gt;Anycubic Photon S&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;compute&quot;&gt;compute&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Modern desktop: 12700KF, 64GB DDR5, 3080Ti. Dual boots Windows 10 and
&lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;&quot;&gt;NixOS&lt;&#x2F;a&gt; — I spend most of my time in Windows.&lt;&#x2F;li&gt;
&lt;li&gt;Older desktop: 4770, 16GB DDR4 — runs NixOS, more of a dedicated lab pc&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>tmc5240</title>
        <published>2024-07-25T00:00:00+00:00</published>
        <updated>2024-08-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/tmc5240/"/>
        <id>https://blog.npry.dev/resenv/tmc5240/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/tmc5240/">&lt;div style=&quot;display: flex; flex-direction: column; align-items: center; padding: 1rem&quot; class=&quot;vidwrap&quot;&gt;
    &lt;video
        src=&quot;stepper_spin.webm&quot;
        
        muted
        controls
        
        
        loop
        
        class=&quot;hover_controls&quot;
        style=&quot;width: 480px; border-radius: 1rem&quot;
    &gt;
    &lt;&#x2F;video&gt;
    
    &lt;i style=&quot;margin-top: 0.5rem&quot;&gt;
        &lt;p&gt;she spins&lt;&#x2F;p&gt;

    &lt;&#x2F;i&gt;
    
&lt;&#x2F;div&gt;

&lt;p&gt;I wrote a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zephyrproject-rtos&#x2F;zephyr&#x2F;commit&#x2F;c3f45bcbe9aec9833921ce157db1bd04390f775c&quot;&gt;Zephyr
driver&lt;&#x2F;a&gt;
over the past week or two for the
&lt;a href=&quot;https:&#x2F;&#x2F;www.analog.com&#x2F;en&#x2F;products&#x2F;tmc5240.html&quot;&gt;tmc5240&lt;&#x2F;a&gt;
(&lt;a href=&quot;https:&#x2F;&#x2F;perrynaseck.com&#x2F;&quot;&gt;Perry&lt;&#x2F;a&gt;&#x27;s project). It speaks SPI, adheres to a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zephyrproject-rtos&#x2F;zephyr&#x2F;pull&#x2F;68774&quot;&gt;new
stepper API Perry is involved
with&lt;&#x2F;a&gt;, and provides
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zephyrproject-rtos&#x2F;zephyr&#x2F;blob&#x2F;c3f45bcbe9aec9833921ce157db1bd04390f775c&#x2F;include&#x2F;zephyr&#x2F;drivers&#x2F;stepper&#x2F;tmc5240.h&quot;&gt;device-specific
functionality&lt;&#x2F;a&gt;
such as pipelined SPI transactions, full register load&#x2F;dump, and a
Kconfig-urable shadow register file.&lt;&#x2F;p&gt;
&lt;p&gt;I did this to help Perry out and because he&#x27;s offered to give me access to some
of his boards, which look like a good test and demo platform for
&lt;a href=&quot;..&#x2F;interstice&quot;&gt;interstice&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zephyr-reflections&quot;&gt;zephyr reflections&lt;&#x2F;h2&gt;
&lt;p&gt;It&#x27;s basically like Linux kernel dev. Everything is Kconfig, it&#x27;s based on
device tree, the functions look POSIX-y (all of this intentionally, I&#x27;m sure).
This is nice in that the API and general conventions are known &#x2F; comparable,
but not-so-nice in that the knowledge barrier is huge and implicit. Yes, there
are manuals to rtf, but they&#x27;re really there to guide you on the presumption
that you&#x27;re already mostly familiar with the environment. For embedded, having
consistent abstractions and not a vendor hal is great. Device-tree remains a
lesser evil.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m glad I did this to see what it&#x27;s like, and I think if you&#x27;re writing
embedded C in anger, Zephyr&#x27;s probably one of the absolute best options. I
probably wont pick it up for a personal project, though, unless I&#x27;m armtwisted
into it (e.g. if I &lt;em&gt;really need&lt;&#x2F;em&gt; the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nrfconnect&#x2F;sdk-nrf&quot;&gt;nRF Connect
SDK&lt;&#x2F;a&gt;) — Rust is just too
expressive by comparison, especially for the &lt;a href=&quot;..&#x2F;interstice&quot;&gt;kinds of things&lt;&#x2F;a&gt; I
have planned on embedded. I think I could have written this driver in
substantially less than half the time in Rust, with better ergonomics, and for
a non-vendor-locked interface abstraction
(&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;embedded-hal-async&#x2F;latest&#x2F;embedded_hal_async&#x2F;spi&#x2F;trait.SpiDevice.html&quot;&gt;&lt;code&gt;embedded_hal_async::spi::SpiDevice&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>early thesis pitch: drone swarming</title>
        <published>2024-06-24T00:00:00+00:00</published>
        <updated>2024-06-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/thesis/pitch-old/"/>
        <id>https://blog.npry.dev/resenv/thesis/pitch-old/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/thesis/pitch-old/">&lt;div style=&quot;background: var(--dimYellow); padding: 0.25rem 1rem; border: var(--yellow) 2px dashed; border-radius: 1rem; margin-top: 1rem&quot;&gt;
    &lt;p&gt;&lt;strong&gt;this document describes an outdated vision of my work, and is preserved for
reference.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;please see the current revision &lt;a href=&quot;..&#x2F;thesis-pitch&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;

&lt;p&gt;An economy can be viewed as a framework for coordinating a massive multi-agent
system by allowing it to express incentives that conduce to useful work over an
extended timescale. Humanity, writ large, represents an adaptable, self-scaling
swarm intelligence, despite being composed of fully independent autonomous
agents, who share approximate incentives and are coordinated at the macro scale
by economic forces. Consider what economic development looks like, at a long
time scale and birds-eye view. Humans grow in fractals -- they follow
incentives, gather around resource centers, and reproduce themselves to exploit
surplus. This effect can be observed on timescales of hours and days with
groups of dozens up to decades and centuries with populations of tens of
millions: there is a direct analogy to bacterial colonies reproducing in Petri
dishes and ants building nests.&lt;&#x2F;p&gt;
&lt;p&gt;Most large physical systems scale this way -- they are composed of autonomous
individual units following incentive gradients. The notion of incentive and the
space in which it is embedded varies greatly between physical species, from
spatial nutrient density for single-celled organisms to sophisticated,
high-dimensional notions of value incorporating explicit, codified social
structures, language, tradition, experience, and so on, as humans do. What
remains interesting about this world model, despite the differences in
objective function between bacterium and human, is that humans still scale in
the real world more or less like bacterial colonies once you zoom out far
enough. Bacteria are contained to the Petri dish -- they are not structurally
sophisticated enough to have an understanding of the world around them or
meaningful ability to leap energy thresholds to exploit remote resources.
Bacteria are effectively spatially confined to resource areas, and have little
to no ability to expand beyond that. Bacterial colonies cannot, except
accidentally, spread to an adjacent Petri dish, no matter how high the nutrient
density (and hence notional incentive) because they cannot collectively sense
beyond their colonies and have no structural capability to actuate in the
world.&lt;&#x2F;p&gt;
&lt;p&gt;Humans, by contrast, are able to do exactly that. We build logistics networks
to transport utility away from production sites, expanding our reach. Human
history is a story of repeated expansion beyond a succession of these
archetypal Petri dishes, as advances in science and technology enable us to
reach beyond our current capabilities and express structure in the universe at
grander and grander scales. The most substantial and rapid advances have been
due to the commodification of microelectronics and capacity to embed and
express computation ubiquitously. But this capability has not yet converged
with the human species&#x27; ability to scale actuation. We use electronic
computation to manage logistics and enable more rapid and wide-area
communication. But our models for integrating automation into actuation on the
world -- actually scaling our resource cultivation and exploitation
capabilities -- have not yet come to fruition. We are starting to see the
beginning of this process, but we don&#x27;t see large numbers of robots
participating in economic activity in a scalable way.&lt;&#x2F;p&gt;
&lt;p&gt;On the face of it, this statement appears wrong -- robotic automation is
everywhere in mass manufacturing, and automated systems manage inventories,
investment, logistics, and more. But they are not &lt;em&gt;integrated&lt;&#x2F;em&gt; in the
recursive, fractal, log-boundary-crossing way that living systems are.
Automated systems are leaves in the graph conceived and purpose-built for a
single application. They are not robust in the sense that they admit of a
composition of modular, independent agents that are straightforwardly replaced,
which communicate and negotiate in order to produce mutually-beneficial results
that conduce towards economic incentives. Assembly lines are hard-coded,
prebaked, and require human intervention for all maintenance.&lt;&#x2F;p&gt;
&lt;p&gt;Research in drone and swarming applications mostly does not look at this
problem, and is instead concerned with optimality and efficiency of acutation
control. While the results of this research are interesting, they make the
essential mistake of disregarding investigations of communications and network
topology in favor of easier-to-implement centralized control. This makes most
of these results functionally unusable for implementing a living system of the
kind I describe, as the agents are not independent or self-motivated but limbs
of a central brain.&lt;&#x2F;p&gt;
&lt;p&gt;My resources to address this problem are relatively constrained. I work in a
hardware group without a strong history of drone research. We don&#x27;t have
terribly deep prior connections nor an existing drone lab to &amp;lt;...&amp;gt;. I don&#x27;t
have much funding to work with. Hence I will be strategic in my approach to
proving out this perspective.&lt;&#x2F;p&gt;
&lt;p&gt;The most useful thing to build is a prototype for the concept -- something that
demonstrates a simple but unsophisticated living system that can work as a demo
and testbed. This is what I intend to do with my master&#x27;s thesis. It will be a
mixed sim-real digital twin environment supporting a swarm of drones that
initially can be controlled by a human directly.&lt;&#x2F;p&gt;
&lt;p&gt;I plan to produce a simulation amenable to wide-area, large-unit-count
drone control by a human operator, using interfacing paradigms inspired by
real-time-strategy (RTS) video games (notably StarCraft II, Beyond All Reason),
which have proven effective for this actuation mode. I intend to demonstrate
mixed sim-real operation in a digital twin model of a test space, enabling a
small number of physical drones (five to ten) to act as a representative subset
of a complete virtual swarm of up to hundreds of members, validating behaviors
in the real world, helping the simulation converge towards real behavior, and
acting as demonstration aids. Taking additional inspiration from the RTS game
genre, individual drones will be of limited local intelligence: capable of
locomotion, basic obstacle and neighbor avoidance, and a small command library,
deferring to the human controller for all higher-level planning and
decision-making.&lt;&#x2F;p&gt;
&lt;p&gt;I hope to demonstrate that under an appropriate interfacing paradigm, this
limited drone intelligence can be leveraged by a single human operator to
rapidly complete wide-area tasks such as object cleanup, delivery logistics,
surveillance, interdiction, and sensor deployment &#x2F; recovery. The goal is to
show that this approach provides a substantial productivity multiplier compared
with manual human operation, without requiring complicated, training-intensive,
motivationally-opaque behavior implemented via ML or RL. I intend to
demonstrate that this approach is also amenable to remote control, even with
significant actuation and sensing latency.&lt;&#x2F;p&gt;
&lt;p&gt;This approach is exciting because RTS games supply a proven, robust interfacing
paradigm that supports sustainable human control of hundreds of independent
agents at an actuation rate of hundreds of discrete inputs per minute – actions
which are leveraged in a context of evolving, goal-oriented human tactical and
strategic decisionmaking, which directly mirrors many forms of real-world
productive work. The RTS genre provides a clear model for separation of agent
and human responsibilities, making the agent relatively dumb (and therefore
easy to implement), but proves that this extremely minimal form of autonomy is
sufficient to enable a human operator to produce wide-area effects rapidly and
effectively.&lt;&#x2F;p&gt;
&lt;p&gt;To tie this back to the conceptual motivation, the point of this work is to
demonstrate that highly-scalable swarms are possible now, implementable by
leveraging human intelligence as the strategic and tactical control and keeping
individual drone behavior simple and understandable. The abstraction boundary
provided by the agent-human interface provides a natural modularization surface
that simplifies implementation, enabling me to demonstrate results quickly, but
is readily suited to incremental improvements in capability as the work
progresses.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>progress: casette</title>
        <published>2024-04-04T00:00:00+00:00</published>
        <updated>2024-04-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/casette/"/>
        <id>https://blog.npry.dev/class/machines/casette/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/casette/">&lt;script type=&quot;module&quot; src=&quot;https:&#x2F;&#x2F;ajax.googleapis.com&#x2F;ajax&#x2F;libs&#x2F;model-viewer&#x2F;3.4.0&#x2F;model-viewer.min.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;p&gt;&lt;model-viewer src=&quot;casette.glb&quot; shadow-intensity=&quot;1&quot; modes=&quot;scene-viewer quicklook&quot; tone-mapping=&quot;commerce&quot; camera-controls touch-action=&quot;pan-y&quot; style=&quot;width: 600px; height: 600px;&quot;&gt;&lt;&#x2F;model-viewer&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For my &lt;a href=&quot;..&#x2F;pcb-system&quot;&gt;two-sided PCB mill&lt;&#x2F;a&gt;, I&#x27;m designing a casette that carries the FR-1 blank. The
aim is to put indexing features on the casette rather than milling them into the blank.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;casette_initial.5b13407f4c11b31f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This solves a whole bunch of problems mechanically that otherwise would require rather more
involved solutions (a vision system, milled locating pins that would require manipulation, etc.).&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;flipper.bd30218c2b282442.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The first design (above) is a two-part carrier held together with M5 bolts and heatset inserts. The top and bottom pieces are identical and symmetrical about 180 degree flips.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;casette_gap.5f3b0a968d34fcab.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Unfortunately (and unsurprisingly) this design has a gap in the center where there is no clamping force. The second design adds bolts to apply clamping force here:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;iteration_2.ccaf5970a0587b63.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;And adds the &lt;a href=&quot;https:&#x2F;&#x2F;clank.tools&#x2F;tools&#x2F;&quot;&gt;Kleat&lt;&#x2F;a&gt; kinematic mount:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;kleat_mount.bc3b59c4b372c7d9.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Next iteration will adjust the Kleat mounting point and pin lengths so they don&#x27;t collide. I&#x27;m still
solving for the interaction between the mount and the board-flipping system.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;considerations-clamping-force&quot;&gt;considerations: clamping force&lt;&#x2F;h3&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;current_state.16aadea7398f1c57.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Another way to solve the center-clamping problem would be to print the casette bowed out &#x2F; as a
spring that must meet in the center first and is then preloaded using the bolts on the edges.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;spring.9314921d25eb9937.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This would be nice in that it would reduce part count and presumably clamping uniformity (the
current solution of additional screws along the long edges I expect has a tendency to pinch only the
outside edge of the board). However, this approach would make 3d printing very annoying, as I&#x27;m
using the inner face as a flat surface that doesn&#x27;t require support. Additionally, I expect PLA&#x2F;PETG
to creep, so I would anticipate clamping force to drop off over time using this approach. Perhaps
it&#x27;s acceptable?&lt;&#x2F;p&gt;
&lt;p&gt;The other obvious way I can think to approach this is printing the parts flat, then heat-softening
and molding them to have that slight curve. Doing this would require a jig and a heater, but might
be worth it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>motivating research concepts</title>
        <published>2024-04-03T00:00:00+00:00</published>
        <updated>2024-08-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/research/"/>
        <id>https://blog.npry.dev/resenv/research/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/research/">&lt;h2 id=&quot;embedded-sucks&quot;&gt;embedded sucks&lt;&#x2F;h2&gt;
&lt;p&gt;for anachronistic, unnecessary, solvable reasons&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;no os and c&#x2F;c++ are basically not reusable &#x2F; this is such a pain that
people don&#x27;t do it, and when they do, it&#x27;s very poor quality&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;or you have an rtos and are locked into their ecosystem&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;rust is great&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a language package manager, wow&lt;&#x2F;li&gt;
&lt;li&gt;many usable &lt;code&gt;#![no_std]&lt;&#x2F;code&gt; libraries&lt;&#x2F;li&gt;
&lt;li&gt;no vendor lock-in with rtos -- embassy is the most central thing, but
almost all of the components work independent of any runtime&lt;&#x2F;li&gt;
&lt;li&gt;it&#x27;s still a pain in the ass to setup (hence
&lt;a href=&quot;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;molybdos&quot;&gt;&lt;code&gt;molybdos&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;there are a bunch of &lt;a href=&quot;https:&#x2F;&#x2F;www.aliexpress.us&#x2F;item&#x2F;3256804850399956.html&quot;&gt;&lt;em&gt;very&lt;&#x2F;em&gt; low cost
microcontrollers&lt;&#x2F;a&gt;
($0.10) out there. it often makes sense in an embedded project to offload
work to another processor, but usually a single mcu only has one core. so
add more! but you often need to write your own primitive networking stack
to have them talk to each other, and that integration complexity makes it
not worthwhile&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;however, we&#x27;ve solved this problem already. we have a lot of mature
networking standards and software, and the reason they&#x27;re not on
embedded is how people wrote them and how they&#x27;re packaged, not that
they&#x27;re not fit for purpose&lt;&#x2F;li&gt;
&lt;li&gt;in rust this isn&#x27;t an issue -- look at
&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;resenv&#x2F;research&#x2F;%22https:&#x2F;&#x2F;github.com&#x2F;embassy-rs&#x2F;embassy&#x2F;tree&#x2F;main&#x2F;embassy-net%22&quot;&gt;&lt;code&gt;embassy_net&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-embedded-community&#x2F;embedded-nal&quot;&gt;&lt;code&gt;embedded_nal&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;smoltcp-rs&#x2F;smoltcp&quot;&gt;&lt;code&gt;smoltcp&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. these are intentionally
intercompatbile networking interface definitions that are a de-facto
standard for embedded rust.&lt;&#x2F;li&gt;
&lt;li&gt;hence &lt;a href=&quot;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;interstice&quot;&gt;&lt;code&gt;interstice&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; --
embassy already has a ppp implementation that wraps
&lt;code&gt;embedded_io_async::{Read,Write}&lt;&#x2F;code&gt; types (e.g. UARTs), we just need a
packet switch to bridge multiple L2 links&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;what else is nice? just having an operating system -- then you don&#x27;t need
a different software kind for bare-metal&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;wiki.pine64.org&#x2F;wiki&#x2F;Ox64&quot;&gt;Ox64&lt;&#x2F;a&gt; + elixir + rust&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;minimum-cost-hardware&quot;&gt;minimum cost hardware&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;lots of &quot;open source hardware&quot; publishes the schematics and firmware but not
the board design. this is a fine model but it also means there are a lot of
designs out there that are way more expensive than the components and in
reach for to relayout (optionally publish) and use for myself&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;e.g.:
&lt;ul&gt;
&lt;li&gt;vesc&lt;&#x2F;li&gt;
&lt;li&gt;crazyflie&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;basically, it&#x27;s not really open source hardware if it doesn&#x27;t have a bom
and design files — should be a single digikey order + basically 1
click from jlc&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;embarassingly parallel physical problems&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;drones suggest themselves as the obvious thing&lt;&#x2F;li&gt;
&lt;li&gt;&quot;beach cleanup&quot;-type -- keep adding units with simple logic&lt;&#x2F;li&gt;
&lt;li&gt;rts control -- 2.5d paradigm&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;drone swarms for useful work&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;so far they don&#x27;t do this -- only single-operator or preplanned missions&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;dumbing down drone control&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;what is an actually-useful mvp for a drone swarm?&lt;&#x2F;li&gt;
&lt;li&gt;things only need to be able to see &quot;good enough&quot; and share information&lt;&#x2F;li&gt;
&lt;li&gt;super high-fidelity is probably not that great&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;...&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>progress: clank-stretch</title>
        <published>2024-03-21T00:00:00+00:00</published>
        <updated>2024-04-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/clank-build/"/>
        <id>https://blog.npry.dev/class/machines/clank-build/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/clank-build/">&lt;p&gt;&lt;em&gt;clank: current state&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;2024_04_11_update.4fe47572113f7c55.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I&#x27;ve fixed mounting issues for the x-axis gantry, tensioned the belts, and built&#x2F;installed the
z-axis and Kleat holder mechanism.&lt;&#x2F;p&gt;
&lt;p&gt;The main item still remaining on the base machine is the shaft for the pulley&#x2F;mechanical stepdown on
the on the Z-axis. This is required for me to mount the Z motor — I&#x27;ve threaded the belt
through in preparation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;belt-tensioner&quot;&gt;belt tensioner&lt;&#x2F;h3&gt;
&lt;p&gt;I designed and 3d printed (out of PETG) a simple belt tensioner:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;belt_tensioner.5756eef384015fa8.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;belt_tensioner_installed.4c77ecead4f1b0ba.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;It screws into a T-nut in the 80&#x2F;20 and uses another M5 screw to jack the belt tight. Had some
issues with imperfect mounting of the threaded insert producing torque&#x2F;rotation on the idler
stackup, but it worked sufficiently well to get all the belts tight.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2024-03-21&quot;&gt;2024&#x2F;03&#x2F;21&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;clank: state as of 2024&#x2F;03&#x2F;11&lt;&#x2F;em&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;clank_base.5f34842612f09467.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;I built my clank-stretch &#x2F; mini-zund &#x2F; data printer (CSMZDP?) this week — thank you to Jake
for sourcing and arranging all the materials and prints.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;minor-build-issues&quot;&gt;minor build issues&lt;&#x2F;h3&gt;
&lt;p&gt;Hit a couple of snags building -- sent along to Jake.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Linear rail mounts for tool carriage had a tendency to break if printed in this orientation. Fixed
by printing holes vertically.&lt;&#x2F;em&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;clank_z_break.06812924bd39127f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Missing screw hole on Y-axis motor mounts. Since fixed in the CAD.&lt;&#x2F;em&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;clank_missing_screw.0b75b71420b01fbb.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;X-axis belt clearance issue — mine rubs currently. I think I can fix by removing some plastic
with a file.&lt;&#x2F;em&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;clank_belt.ba541c66a1722bcc.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;h3 id=&quot;improvements-todo&quot;&gt;improvements todo&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;[&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;machines&#x2F;clank-build&#x2F;#belt-tensioner&quot;&gt;DONE&lt;&#x2F;a&gt;] Idler tensioner fixture (to CAD + print)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;T-nut in 8020, screw at 90 degrees (on X-Y plane) that you can tighten to jack the idler
assembly tighter. Unscrew when done &#x2F; reusable.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Jig for idler stackup assembly (to CAD + print)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Really a pain in the ass to set these up if the tolerances aren&#x27;t on the right side of the
relevant line — sometimes very hard to get the part into a vice &#x2F; press to get the
bearings on. I think there&#x27;s a relatively simple 3D-printed part that could make this easy.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>concept: interstice: embedded, phy-agnostic meshing + ip routing</title>
        <published>2024-03-14T00:00:00+00:00</published>
        <updated>2024-04-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/ip-embedded/"/>
        <id>https://blog.npry.dev/class/machines/ip-embedded/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/ip-embedded/">&lt;p&gt;&lt;strong&gt;library link&lt;&#x2F;strong&gt;: &lt;a href=&quot;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;interstice&quot;&gt;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;interstice&lt;&#x2F;a&gt; (placeholder currently)&lt;&#x2F;p&gt;
&lt;p&gt;As &lt;a href=&quot;https:&#x2F;&#x2F;ekswhyzee.com&#x2F;2024&#x2F;03&#x2F;09&#x2F;mudlink.html&quot;&gt;Jake has written about&lt;&#x2F;a&gt;, there is a lack of
easy networking &#x2F; communication on embedded, prompting his implementation of MUDL (and my &lt;a href=&quot;..&#x2F;mudlrs&quot;&gt;Rust
port&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;To motivate more directly: it is frankly a pain in the ass to make a
microcontroller talk to anything, and communication is normally at some layer ad-hoc. As a result,
nothing is reused — we don&#x27;t get the nicely-layered abstraction that the OSI model suggests
we should, and I reimplement a COBS encoder &#x2F; decoder, message buffering, etc. in pretty much every
embedded project I work on. Partially that&#x27;s my problem for not standardizing my own work, but I&#x27;m
also pointing a finger at the embedded world for not having any networking standards outside of
microcontrollers with wireless stacks — I&#x27;m generally pretty good about using nice things
when they exist.&lt;&#x2F;p&gt;
&lt;p&gt;To some extent, this problem is a function of working in the embedded world. There&#x27;s a tendency to
see the embedded environment as categorically different from programming with an OS available.
This makes sense if your first thought when you hear the word &quot;embedded&quot; is a PIC-8 — I can&#x27;t
afford a networking stack when I&#x27;m working with at most 4KB RAM.&lt;&#x2F;p&gt;
&lt;p&gt;However, we now live in a world where you can easily get megabytes of both flash and RAM on low-cost
(&amp;lt; $10) MCUs — that&#x27;s enough to store the entire disk and process image of a regular OS
executable without stripping or size optimization. We can afford to have some nice things.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, I would like to have a networking stack that &lt;em&gt;works&lt;&#x2F;em&gt; with regular IP — you
know, what the internet is made of. And when I say &quot;works&quot;, I don&#x27;t mean supports-being-a-leaf
in the way that all the wireless networking stacks do. Rather, I mean I want to implement a routed,
PHY-agnostic IP &lt;em&gt;network&lt;&#x2F;em&gt;. For IP to work as-designed, you need to be able to route packets.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aside-storage-cost&quot;&gt;aside: storage cost&lt;&#x2F;h3&gt;
&lt;p&gt;I write most of my firmware in Rust, which has many of the nice bells and whistles you&#x27;d expect in an
OS environment as libraries. This costs memory (on the order of hundreds of KiB flash, dozens of KiB
RAM), but even so, I&#x27;m typically not space-constrained.&lt;&#x2F;p&gt;
&lt;p&gt;If storage space is a concern though,
&lt;a href=&quot;https:&#x2F;&#x2F;www.mouser.com&#x2F;c&#x2F;semiconductors&#x2F;memory-ics&#x2F;?interface%20type=SPI&quot;&gt;flash&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;www.adafruit.com&#x2F;product&#x2F;4677&quot;&gt;RAM&lt;&#x2F;a&gt; are cheap — if it&#x27;s going to make
firmware development easier, I lean heavily towards just adding more space to the board, even at the
shocking cost of a whole additional couple dollars.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;goal&quot;&gt;goal&lt;&#x2F;h2&gt;
&lt;p&gt;I want to be able to power on an MCU and have it automatically advertise itself as an IP-capable
&lt;em&gt;router&lt;&#x2F;em&gt; over all communication interfaces:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;USB: CDC-NCM, optionally CDC-ACM as serial-ppp&lt;&#x2F;li&gt;
&lt;li&gt;UART, I2C, SPI, CAN: ppp&lt;&#x2F;li&gt;
&lt;li&gt;WiFi: native&lt;&#x2F;li&gt;
&lt;li&gt;Bluetooth, LoRa, Thread: 6LoWPAN &#x2F; native Thread&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;By &lt;em&gt;router&lt;&#x2F;em&gt; I mean it should support:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;iBGP&lt;&#x2F;li&gt;
&lt;li&gt;MLD &#x2F; IGMP&lt;&#x2F;li&gt;
&lt;li&gt;ICMP{,v6}&lt;&#x2F;li&gt;
&lt;li&gt;ARP &#x2F; NDP (as necessary -- most of these are point-to-point)&lt;&#x2F;li&gt;
&lt;li&gt;IP{,v6}&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;update-4-4-24-routing&quot;&gt;update (4&#x2F;4&#x2F;24): routing&lt;&#x2F;h3&gt;
&lt;p&gt;I was thinking about proposing some version of this project for an &lt;a href=&quot;https:&#x2F;&#x2F;nlnet.nl&#x2F;&quot;&gt;nlnet&lt;&#x2F;a&gt; grant
and so have been reading more on prior art. There are really two components to the project: the generic
network-interface implementation and bridging and routing. There is &lt;em&gt;extensive&lt;&#x2F;em&gt; prior art on the
routing side that I was no more than peripherally aware of. The term of art for this problem is
MANET (mobile ad-hoc network), and routing implementations differ in a few dimensions — most
notably between reactive and proactive paradigms, and in node-local state overhead. For my use-case,
a proactive routing algorithm that does not require global network knowledge is ideal, as I value
both low latency and a minimal memory footprint.&lt;&#x2F;p&gt;
&lt;p&gt;I have considered both
&lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;draft-wunderlich-openmesh-manet-routing-00&quot;&gt;BATMAN&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc8966#name-introduction&quot;&gt;Babel&lt;&#x2F;a&gt; in some depth.&lt;&#x2F;p&gt;
&lt;p&gt;BATMAN(-advanced) operates at layer 2 and has an in-tree Linux kernel implementation. Its goal as
described in its draft RFC is to discover the best next-hop for each route, rather than computing
the route in its entirety. I&#x27;m hopeful that this means that memory overhead can be kept small,
in accordance with the goal of operating on embedded microcontrollers.&lt;&#x2F;p&gt;
&lt;p&gt;Babel was interesting mostly because it has a reference implementation that isn&#x27;t tied to the Linux
kernel and states that it has a low code-size. It&#x27;s a hybrid MANET implementation that seems (by
reputation) to be fairly efficient, has nice loop-avoidance capabilities, and is designed to respond favorably during reconvergence events.&lt;&#x2F;p&gt;
&lt;p&gt;Based on the RFCs, BATMAN appears more suited to my needs and easier to implement, so I intend to
port it to Rust, then expose an Arduino interface to the Rust library.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;meshing&quot;&gt;meshing&lt;&#x2F;h3&gt;
&lt;p&gt;The system should support automatic, provisioning-free&#x2F;zero-configuration meshing. That is, every
device that can see any other device should connect to it and route packets for it.&lt;&#x2F;p&gt;
&lt;p&gt;In order to efficiently make use of routing tables, the network should ideally converge to an
addressing scheme that divides subnets based on locality and connectivity. Graph regions with low
diameter should be seen as candidates for subnet division — what we want is for this graph:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;A - B - C
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    D
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;E - F - G
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;to &quot;understand&quot; that the addresses for A, B, C should be in one subnet, and E, F, G should be in
another, so that D can serve as an edge router between them.&lt;&#x2F;p&gt;
&lt;p&gt;To rephrase the problem in the converse sense, if we randomly assign addresses, we should expect a
high degree of fragmentation in the routing tables. In the limiting &#x2F; pathological case, every node&#x27;s
routing table contains the whole network topology — the benefit of dynamic destination routing
vanishes. So we need some spatial organization of the node addressing.&lt;&#x2F;p&gt;
&lt;p&gt;I suspect such an addressing scheme can be achieved with a locally-greedy algorithm, but the price
we pay is that existing node addresses may change when new nodes are added to the network. We can
address this algorithmically and mitigate the impact by having old addressing information survive
network reorganization for a limited period of time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;prior-art&quot;&gt;prior art&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Zephyr&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Has a &lt;a href=&quot;https:&#x2F;&#x2F;docs.zephyrproject.org&#x2F;latest&#x2F;connectivity&#x2F;networking&#x2F;api&#x2F;net_l2.html#net-l2-interface&quot;&gt;nice
model&lt;&#x2F;a&gt;
for abstracting the L2 networking interface and allowing pluggable implementations. I don&#x27;t use
zephyr, but it&#x27;s compelling and a great model for portability for OS concepts onto embedded
platforms.&lt;&#x2F;li&gt;
&lt;li&gt;Has
&lt;a href=&quot;https:&#x2F;&#x2F;docs.zephyrproject.org&#x2F;2.7.5&#x2F;reference&#x2F;kconfig&#x2F;CONFIG_NET_ROUTING.html&quot;&gt;&lt;code&gt;CONFIG_NET_ROUTING&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
which unfortunately appears to be unused (&quot;something would have to populate the routing table&quot;
— doesn&#x27;t give me confidence that it&#x27;s stable&#x2F;definitely working)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Rust&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;smoltcp-rs&#x2F;smoltcp&quot;&gt;&lt;code&gt;smoltcp&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;: &lt;code&gt;no_std&lt;&#x2F;code&gt;-compatible userspace networking
stack (name misleading -- not just TCP!)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-embedded-community&#x2F;embedded-nal&quot;&gt;&lt;code&gt;embedded-nal&lt;&#x2F;code&gt;,
&lt;code&gt;embedded-nal-async&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:
&lt;code&gt;no_std&lt;&#x2F;code&gt;-compatible interface traits&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;embassy-rs&#x2F;embassy&#x2F;tree&#x2F;main&#x2F;embassy-net&quot;&gt;&lt;code&gt;embassy-net&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and associated
drivers: &lt;code&gt;no_std&lt;&#x2F;code&gt; networking stack built on top of &lt;code&gt;smoltcp&lt;&#x2F;code&gt;, intended for use within the
&lt;code&gt;embassy&lt;&#x2F;code&gt; project
&lt;ul&gt;
&lt;li&gt;Associated drivers include &lt;code&gt;embassy-net-ppp&lt;&#x2F;code&gt;, which runs a networking link over&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Meshing&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.open-mesh.org&#x2F;projects&#x2F;batman-adv&#x2F;wiki&quot;&gt;batman-adv&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.bluetooth.com&#x2F;learn-about-bluetooth&#x2F;feature-enhancements&#x2F;mesh&#x2F;&quot;&gt;bluetooth mesh&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Thread_(network_protocol)&quot;&gt;Thread&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;meshtastic.org&#x2F;&quot;&gt;meshtastic&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;plan-project-components&quot;&gt;plan &#x2F; project components&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Meshing experiments in simulation&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Candidate meshing implementation -- develop addressing algorithm&lt;&#x2F;li&gt;
&lt;li&gt;Simulate a bunch of agents connecting, disconnecting&lt;&#x2F;li&gt;
&lt;li&gt;Measure network throughput, packet loss, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;IP transport over multiple PHYs&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Currently planning to use &lt;code&gt;embassy-net-ppp&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Validate functionality across multiple PHYs
&lt;ul&gt;
&lt;li&gt;Highest priority: SPI, UART, I2C&lt;&#x2F;li&gt;
&lt;li&gt;CAN if possible&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Router implementation&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Rust library to act as an IP router — own multiple smoltcp interfaces, route packets across them&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>maxl over unreliable networks</title>
        <published>2024-03-14T00:00:00+00:00</published>
        <updated>2024-03-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/maxl-unreliable/"/>
        <id>https://blog.npry.dev/class/machines/maxl-unreliable/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/maxl-unreliable/">&lt;p&gt;Jake published a paper called &lt;a href=&quot;https:&#x2F;&#x2F;cba.mit.edu&#x2F;docs&#x2F;papers&#x2F;23.10.MAXL-Motion.pdf&quot;&gt;MAXL&lt;&#x2F;a&gt;, which
is a distributed&#x2F;networked machine controller that does time sync and manages trajectory buffers.&lt;&#x2F;p&gt;
&lt;p&gt;As I wrote about &lt;a href=&quot;..&#x2F;ip-embedded&quot;&gt;here&lt;&#x2F;a&gt;, I&#x27;m working on meshing + IP routing on embedded. The
short version is that I want this because it&#x27;s compatible with, you know, the internet —
essentially everything, from anywhere. Security, obviously, would be a huge concern with exposing
this to the internet, and it would need to be locked down before doing so. But you &lt;em&gt;could&lt;&#x2F;em&gt;, and
more relevantly, IP allows arbitrary network topologies, up to limitations of your link budget. It
would make it very easily, comparatively, to plug in a new actuator, rearrange cables, etc.&lt;&#x2F;p&gt;
&lt;p&gt;The apparent problem with doing this is that dynamically destination-routed packets in an unreliable
network may never arrive, and if we&#x27;re using them for machine control, that seems bad — MAXL
depends on realtime network qualities that an IP network (that hides the PHY layer) totally
trashes. My answer to this problem is to make the MAXL system CAM- and kinematics-aware, in order
to ensure that in the worst case, the machine pauses briefly in a safe location while waiting for
new packets.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;trajectory-plannning&quot;&gt;trajectory plannning&lt;&#x2F;h2&gt;
&lt;p&gt;How? As part of the CAM process, partition your tool trajectories into those with tool engagement
and those without. Plunge -&amp;gt; side-mill -&amp;gt; retract might be a trajectory with engagement, and a rapid
above the plane of the part is an example of one without.&lt;&#x2F;p&gt;
&lt;p&gt;(For simplicity we&#x27;ll treat rapids in-plane as engaged moves as actuators require some, but
potentially not precise, synchronization — we can cut corners here to optimize, but that can
come later.)&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re going to execute an engaged trajectory (using this plunge -&amp;gt; side-mill -&amp;gt; retract as our
example), you make sure all motors can execute it &lt;em&gt;atomically&lt;&#x2F;em&gt; before  committing to execution.
That is, the whole trajectory must be loaded into memory on all distributed actuators, and you only
command execution of this one safe trajectory at a time. Now if you let the machine run, it will do
one safe thing — it will end in the retracted state, not engaged with the part.&lt;&#x2F;p&gt;
&lt;p&gt;If the command is disengaged, then you can execute the command without waiting for global
synchronization from all motors.&lt;&#x2F;p&gt;
&lt;p&gt;In general, as long as you can ensure that all actuators have loaded or executed all programs &lt;em&gt;up to
the end&lt;&#x2F;em&gt; of a given engaged trajectory in the program, you can queue execution of that trajectory.
This means that you can keep loading trajectory data as long as the motor has available memory,
and queue execution as all other actuators report readiness.&lt;&#x2F;p&gt;
&lt;p&gt;These assumptions mean that we don&#x27;t need a realtime network. If we only execute when it&#x27;s safe, and
end up in a safe place, then we can&lt;&#x2F;p&gt;
&lt;h3 id=&quot;estop&quot;&gt;estop&lt;&#x2F;h3&gt;
&lt;p&gt;In order to avoid Byzantine problems, I&#x27;m assuming an estop is in the machine reachable by the
controller, and I treat it as an absolutely-reliable communication channel. (For robustness to
Byzantine faults we can say it has watchdog timer functionality, so network partitions mean estop.)
This solves the problem of the controller telling the motors to start, but only wanting them all to
start if they&#x27;re &lt;em&gt;all&lt;&#x2F;em&gt; ready. But establishing that requires another roundtrip, which the motors may
also not acknowledge, etc. etc.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, send the &quot;go&quot; as normal, and if any motors don&#x27;t acknowledge within a window, trigger
estop — this doesn&#x27;t sacrifice functionality for us, as this is definitely a failure
condition for a distributed machine.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;safe-tails-leaders&quot;&gt;safe tails + leaders&lt;&#x2F;h3&gt;
&lt;p&gt;What happens if our atomic trajectories are too long to fit in memory? The scheme relies on this
being possible. As-required, compute &quot;safe tails&quot; for too-long atomic trajectories (power off
spindle, raise Z), etc. and inject them into the program in order to create synthetic safe points
(you&#x27;ll need to create safe lead-ins as well that undo the tail operation). This has the effect of
producing new atomic subtrajectories — you intentionally size these to fit into memory on
your actuators.&lt;&#x2F;p&gt;
&lt;p&gt;In the normal case, you&#x27;re aiming not to execute these — you try to load the whole next segment,
acquire global actuator acknowledgement, and cancel the next tail&#x2F;leader pair before the
distributed machine starts to run it.&lt;&#x2F;p&gt;
&lt;p&gt;If required though, if the machine is stuck waiting for new data, the result is that it
automatically goes to a safe spot to wait.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>component: molybdos (rust arduino-inspired library)</title>
        <published>2024-03-14T00:00:00+00:00</published>
        <updated>2024-03-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/molybdos/"/>
        <id>https://blog.npry.dev/class/machines/molybdos/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/molybdos/">&lt;p&gt;&lt;em&gt;batteries-included, arduino-inspired library for easy rust embedded bringup&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;molybdos&quot;&gt;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;molybdos&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I want more people to use Rust on embedded. It&#x27;s a great language, it has a package manager, the
library support is great, and it encourages people to write better, clearer, more correct code,
while not reinventing the wheel.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;current-shortcomings-improvement-areas&quot;&gt;current shortcomings &#x2F; improvement areas&lt;&#x2F;h2&gt;
&lt;p&gt;Unfortunately, the story for Rust on embedded currently involves a lot of boilerplate and pitfalls.
Once you have your environment set up properly, it&#x27;s great, but for instance:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Common, quasi-standard library needs to be re-added to every project
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;heapless&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;embassy_*&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;embedded_*&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;defmt&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;panic_*&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cortex_m{,_rt}&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;riscv{,_rt}&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Common build scripts need to be added to every project&lt;&#x2F;li&gt;
&lt;li&gt;Shared features (&lt;code&gt;defmt&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;log&lt;&#x2F;code&gt;, &lt;code&gt;alloc&lt;&#x2F;code&gt;, &lt;code&gt;serde&lt;&#x2F;code&gt;, &lt;code&gt;default_features = false&lt;&#x2F;code&gt;) are tedious to add
to every project&lt;&#x2F;li&gt;
&lt;li&gt;Often need to write a linker file for your chip&lt;&#x2F;li&gt;
&lt;li&gt;Some libraries use weak linking for dependency management — they need linker definitions
added in each project&lt;&#x2F;li&gt;
&lt;li&gt;Boilerplate peripheral bringup is kind of annoying to write
&lt;ul&gt;
&lt;li&gt;E.g. no USB-CDC by default (typical Arduino &lt;code&gt;Serial&lt;&#x2F;code&gt; implementation)&lt;&#x2F;li&gt;
&lt;li&gt;Pins are unique type-level handles to register values. This provides type-safety but means you
can&#x27;t access them generically (e.g. put them into an array) without &lt;code&gt;.downgrade()&lt;&#x2F;code&gt;ing them
individually&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;embedded_*&lt;&#x2F;code&gt; interfaces use AFIT (async-function-in-trait) rather than a polling interface, making
them not easily compatible with e.g. &lt;code&gt;futures::{Stream, Sink}&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;No-op imports for lang items:&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;use&lt;&#x2F;span&gt; panic_abort &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;use&lt;&#x2F;span&gt; defmt_rtt &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All of this is pretty straightforwardly mitigated by writing a library crate, which is what I&#x27;m
working on.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;progress&quot;&gt;progress&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;linker-file-generation&quot;&gt;linker file generation&lt;&#x2F;h3&gt;
&lt;p&gt;One of the first tasks I&#x27;m tackling is a linker file generator that runs at build-time. Intended interface:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; class=&quot;language-toml z-code&quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-toml&quot;&gt;#&lt;&#x2F;span&gt; Cargo.toml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-table z-begin z-toml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-table z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-table z-toml&quot;&gt;dependencies&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-table z-end z-toml&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;molybdos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-inline-table z-begin z-toml&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-basic z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-inline-table z-toml&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;features&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-array z-begin z-toml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-basic z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;linker_gen&lt;span class=&quot;z-punctuation z-definition z-string z-end z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-array z-end z-toml&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-inline-table z-end z-toml&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will cause a &lt;code&gt;molybdos&lt;&#x2F;code&gt;&#x27; &lt;code&gt;build.rs&lt;&#x2F;code&gt; to generate a linker file
(&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;embassy-rs&#x2F;embassy&#x2F;blob&#x2F;main&#x2F;examples&#x2F;nrf51&#x2F;memory.x&quot;&gt;e.g.&lt;&#x2F;a&gt;) for the selected
chip and emit the typical Cargo instructions (example below from
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;embassy-rs&#x2F;embassy&#x2F;blob&#x2F;ee1aa80e3063de35a6f68c918a18b506d7f49539&#x2F;examples&#x2F;nrf51&#x2F;build.rs#L19-L34&quot;&gt;here&lt;&#x2F;a&gt;
(nRF51*, but meaningfully the same for at least most Cortex-M MCUs with &lt;code&gt;defmt&lt;&#x2F;code&gt; enabled)):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; out &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;PathBuf&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;from&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;env&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;var_os&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;OUT_DIR&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;File&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;create&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;out&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;memory.x&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;    &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;    &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;write_all&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;include_bytes!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;memory.x&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;    &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cargo:rustc-link-search=&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; out&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;display&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cargo:rerun-if-changed=memory.x&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cargo:rustc-link-arg-bins=--nmagic&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cargo:rustc-link-arg-bins=-Tlink.x&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cargo:rustc-link-arg-bins=-Tdefmt.x&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This task is still in-progress.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;peripheral-bringup&quot;&gt;peripheral bringup&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;ontology&quot;&gt;ontology&lt;&#x2F;h4&gt;
&lt;p&gt;The embedded ontology de-facto settled upon by Rust embedded projects is very generic:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;p&lt;&#x2F;strong&gt;eripheral &lt;strong&gt;a&lt;&#x2F;strong&gt;ccess &lt;strong&gt;c&lt;&#x2F;strong&gt;rate (aka &quot;pac&quot;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nrf-rs&#x2F;nrf-pacs&#x2F;blob&#x2F;90977499146de8444579538e7ad2466d1d9823db&#x2F;pacs&#x2F;nrf52833-pac&#x2F;src&#x2F;lib.rs&quot;&gt;e.g. for
nRF52833&lt;&#x2F;a&gt;)
is written (usually generated using &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-embedded&#x2F;svd2rust&quot;&gt;&lt;code&gt;svd2rust&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;). This is a
register-level interface to the MCU.&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;strong&gt;h&lt;&#x2F;strong&gt;ardware &lt;strong&gt;a&lt;&#x2F;strong&gt;bstraction &lt;strong&gt;l&lt;&#x2F;strong&gt;ayer (aka &quot;hal&quot;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;embassy-rs&#x2F;embassy&#x2F;blob&#x2F;ee1aa80e3063de35a6f68c918a18b506d7f49539&#x2F;embassy-nrf&#x2F;src&#x2F;lib.rs&quot;&gt;e.g. for
nRF&lt;&#x2F;a&gt;)
is (usually hand-) written that wraps the pac and makes it ergonomic to use — this usually
means adapting it to Rust embedded conventions and interfaces. The pac will contain your SPI
control register definition and access, the hal will make it look like an
&lt;code&gt;embedded_hal_async::spi::SpiBus&lt;&#x2F;code&gt;.
&lt;ul&gt;
&lt;li&gt;A common convention in hals is providing a &lt;code&gt;Peripherals&lt;&#x2F;code&gt; struct that contains unique handles
to the pac registers. On startup, you run an &lt;code&gt;init&lt;&#x2F;code&gt; function exactly once to receive a
&lt;code&gt;Peripherals&lt;&#x2F;code&gt; instance, and then destructure it into relevant fields that you can use to
construct the hal types you need. E.g.:&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Pull in the HAL GPIO types.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;use&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;embassy_nrf&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;gpio&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; p&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;embassy_nrf&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Peripherals &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;embassy_nrf&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;init&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Construct a new HAL gpio::Output type (which has e.g.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Output::{set_high, set_low, toggle})
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; led &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Output&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;new&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; gpio::Output requires a handle to a pin, which we can only
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; get from an embassy_nrf::Peripherals
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;    p&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-rust&quot;&gt;P0_13&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Level&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Low&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;OutputDrive&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Standard&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; SPI buses, I2C, USB, timers, ADCs, etc. are all constructed
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; following a similar pattern.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;loop&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    led&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;toggle&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Timer&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;after_millis&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;300&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;await&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;Interface crates are a level higher and what the hals are written against, and typically only
contain trait definitions and common helper functions. They exist as common definitions to decouple
dependencies and improve compatibility. (Examples: &lt;code&gt;embedded_hal{,_async}&lt;&#x2F;code&gt;,
&lt;code&gt;embedded_io{,_async}&lt;&#x2F;code&gt;, &lt;code&gt;embedded_nal{,_async}&lt;&#x2F;code&gt;, etc., which provide bus definitions, an embedded
version of &lt;code&gt;io::{Read, Write, Seek}&lt;&#x2F;code&gt;, network interfaces, and more)&lt;&#x2F;li&gt;
&lt;li&gt;Bus peripheral drivers and applications are ideally written on top of the interface crates for
portability, compatibility, and decoupling. E.g. the
&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;sx127x_lora&#x2F;latest&#x2F;sx127x_lora&#x2F;&quot;&gt;&lt;code&gt;sx127x&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; LoRa radio driver is written against
the generic &lt;code&gt;embedded_hal::spi::SpiBus&lt;&#x2F;code&gt; definition and can run on anything that can provide one
(including Linux! as their examples point out — there is an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-embedded&#x2F;linux-embedded-hal&quot;&gt;&lt;code&gt;embedded_hal&lt;&#x2F;code&gt;
interface&lt;&#x2F;a&gt; for Linux userspace).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;While this stack is well-designed and great to use once you understand it, it can take quite a while
to understand how it wants to be used and configured. It also requires repetitive setup of the same
things, when across most projects you just want a quick, low-overhead way to e.g. get access to the
SPI bus.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;hiding-the-stack&quot;&gt;hiding the stack&lt;&#x2F;h4&gt;
&lt;p&gt;By contrast to the above, Arduino doesn&#x27;t tell us anything about the abstraction stack or require
us to configure it beyond selecting our board. Your interface to Arduino as a user is &lt;code&gt;Wire&lt;&#x2F;code&gt;,
&lt;code&gt;Serial&lt;&#x2F;code&gt;, &lt;code&gt;SPI&lt;&#x2F;code&gt;, &lt;code&gt;{analog,digital}{Write,Read}&lt;&#x2F;code&gt;, etc. I want to make it similarly easy to access
Rust peripherals without requiring this explicit understanding or direct bringup of the stack.&lt;&#x2F;p&gt;
&lt;p&gt;However, I want to strike a good balance re: not going too far in the Arduino direction and making
assumptions willy-nilly. A nice interface looks like this to me:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;molybdos&lt;&#x2F;span&gt;::&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;async &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;molybdos&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Molybdos,
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;molybdos&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;molybdos&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;info&lt;span class=&quot;z-keyword z-operator z-logical z-rust&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;started up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; spi &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; m&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;spi&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;init&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;molybdos&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;SPIConfig &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        mosi&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        miso&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        sck&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;P0.12&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;pin&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Supported by a trait -- molybdos::PinLookup.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        cs&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; peripheral lookup by string name -- could support BSPs as well as IC pinout names
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    m&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;gpio&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;named&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;P0.13&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;toggle&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; resolve pin name to id to avoid repeated lookup
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; pin_id &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;molybdos&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;platform&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;lookup_pin&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;P0.13&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    m&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;gpio&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;pin_id&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;toggle&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; &amp;quot;take&amp;quot; a pin from the molybdos::Molybdos instance to reserve it exclusively.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; When exclusive handle is dropped, becomes available to take again.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; pin &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; m&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;gpio&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;take&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;pin_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;into_output&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Level&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Low&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;DriveStrength&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Standard&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    pin&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;set_high&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;loop&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; numeric indexing if already known
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        m&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;gpio&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;toggle&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;embassy_time&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Timer&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;after_millis&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;300&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;await&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This interface implies type-erased peripherals — I want to present peripherals with
duplicates uniformly rather than specialized to their pac type as the normal Rust stack does.&lt;&#x2F;p&gt;
&lt;p&gt;The configuration interface I&#x27;m aiming for would be as follows:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; class=&quot;language-toml z-code&quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-toml&quot;&gt;#&lt;&#x2F;span&gt; Cargo.toml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-table z-begin z-toml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-table z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-table z-toml&quot;&gt;dependencies&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-table z-end z-toml&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;molybdos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-inline-table z-begin z-toml&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-basic z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-inline-table z-toml&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;features&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-array z-begin z-toml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-basic z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;nrf52833&lt;span class=&quot;z-punctuation z-definition z-string z-end z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-array z-end z-toml&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-inline-table z-end z-toml&quot;&gt;}&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-toml&quot;&gt;#&lt;&#x2F;span&gt; only need to specify MCU&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Still working on this — focusing on developing the nRF platform to completion currently.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aside-curse-of-abstraction-zero-cost-abstraction&quot;&gt;aside: curse of abstraction &#x2F; zero-cost abstraction&lt;&#x2F;h2&gt;
&lt;p&gt;There&#x27;s a &quot;curse of abstraction&quot; in many programming environments, where people accept abstractions
having a cost &#x2F; this is in the culture and basic assumptions. But if every library has a 2% cost to
your expressive capability, and your transitive dependency graph has 50 libraries in it, all of a
sudden you have 36% of your original capabilities (assuming that 2% is multiplicative, which it
probably isn&#x27;t), because everything&#x27;s making tiny &quot;probably true&quot; assumptions for &quot;convenience&quot;,
not all of which are actually true, but you&#x27;re stuck with them unless you actually fork the repo,
go read the datasheet in detail to make the thing do what you want, and basically redo all the work
you were trying to avoid by using a library. Ask me how I know.&lt;&#x2F;p&gt;
&lt;p&gt;One of Rust&#x27;s mantras, borrowed from C++ with some additional flavor, is that of zero-cost abstraction:
if you don&#x27;t use it, it doesn&#x27;t cost you. Illustratively, Java does not have zero-cost abstractions.
You pay for the hundreds of megabytes of runtime loading on every process startup. If you want to
run a program to add two integers and print the result, the whole GC still loads, the whole class loading
mechanism, etc. But if you run a {Rust, C, C++} program, it just runs and does exactly what you
want. The &lt;code&gt;class&lt;&#x2F;code&gt; mechanism in C++ is relatively minimal and doesn&#x27;t depend on any runtime components,
as a specific example. An enhancement of the zero-cost principle is that even abstractions that you
&lt;em&gt;do&lt;&#x2F;em&gt; use shouldn&#x27;t impose any additional cost over hand-writing the concretized version yourself.
This is what Rust aims for. See the Godbolt embedded below for an example — in Rust, functional combinators
&lt;em&gt;are equivalent to for loops&lt;&#x2F;em&gt; after compiler optimization.&lt;&#x2F;p&gt;
&lt;iframe width=&quot;1000px&quot; height=&quot;600px&quot; src=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;e#g:!((g:!((g:!((h:codeEditor,i:(filename:&#x27;1&#x27;,fontScale:14,fontUsePx:&#x27;0&#x27;,j:1,lang:rust,selection:(endColumn:40,endLineNumber:21,positionColumn:40,positionLineNumber:21,selectionStartColumn:40,selectionStartLineNumber:21,startColumn:40,startLineNumber:21),source:&#x27;%23%5Bno_mangle%5D%0A%23%5Binline(never)%5D%0Apub+fn+sum_of_squares_loop(nums:+%26%5Bi32%5D)+-%3E+i32+%7B%0A++++let+mut+sum+%3D+0%3B%0A%0A++++for+num+in+nums+%7B%0A++++++++sum+%2B%3D+num+*+num%0A++++%7D%0A%0A++++sum%0A%7D%0A%0A%23%5Bno_mangle%5D%0A%23%5Binline(never)%5D%0Apub+fn+sum_of_squares(nums:+%26%5Bi32%5D)+-%3E+i32+%7B%0A++++nums.into_iter().map(%7Cn%7C+n+*+n).sum()%0A%7D%0A%0A%0Apub+fn+main()+%7B%0A++++let+x+%3D+sum_of_squares(%26%5B1,+2,+3,+4%5D)%3B%0A++++let+y+%3D+sum_of_squares_loop(%26%5B1,+2,+3,+4%5D)%3B%0A++++println!!(%22%7Bx%7D+%7By%7D%22)%3B%0A%7D&#x27;),l:&#x27;5&#x27;,n:&#x27;0&#x27;,o:&#x27;Rust+source+%231&#x27;,t:&#x27;0&#x27;)),k:50,l:&#x27;4&#x27;,n:&#x27;0&#x27;,o:&#x27;&#x27;,s:0,t:&#x27;0&#x27;),(g:!((g:!((h:compiler,i:(compiler:r1640,filters:(b:&#x27;0&#x27;,binary:&#x27;1&#x27;,binaryObject:&#x27;1&#x27;,commentOnly:&#x27;0&#x27;,debugCalls:&#x27;1&#x27;,demangle:&#x27;0&#x27;,directives:&#x27;0&#x27;,execute:&#x27;1&#x27;,intel:&#x27;0&#x27;,libraryCode:&#x27;0&#x27;,trim:&#x27;1&#x27;),flagsViewOpen:&#x27;1&#x27;,fontScale:14,fontUsePx:&#x27;0&#x27;,j:1,lang:rust,libs:!(),options:&#x27;-C+opt-level%3D3+-C+no-vectorize-loops&#x27;,overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:&#x27;5&#x27;,n:&#x27;0&#x27;,o:&#x27;+rustc+1.64.0+(Editor+%231)&#x27;,t:&#x27;0&#x27;)),k:50,l:&#x27;4&#x27;,m:50,n:&#x27;0&#x27;,o:&#x27;&#x27;,s:0,t:&#x27;0&#x27;),(g:!((h:output,i:(compilerName:&#x27;rustc+1.64.0&#x27;,editorid:1,fontScale:14,fontUsePx:&#x27;0&#x27;,j:1,wrap:&#x27;1&#x27;),l:&#x27;5&#x27;,n:&#x27;0&#x27;,o:&#x27;Output+of+rustc+1.64.0+(Compiler+%231)&#x27;,t:&#x27;0&#x27;)),header:(),l:&#x27;4&#x27;,m:50,n:&#x27;0&#x27;,o:&#x27;&#x27;,s:0,t:&#x27;0&#x27;)),k:50,l:&#x27;3&#x27;,n:&#x27;0&#x27;,o:&#x27;&#x27;,t:&#x27;0&#x27;)),l:&#x27;2&#x27;,n:&#x27;0&#x27;,o:&#x27;&#x27;,t:&#x27;0&#x27;)),version:4&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;(Had to disable loop autovectorization to make the equivalence legible.)&lt;&#x2F;p&gt;
&lt;p&gt;You&#x27;ll notice that there&#x27;s only one function in the disassembly, &lt;code&gt;sum_of_squares&lt;&#x2F;code&gt;. The compiler optimized
the combinator loop to the exact same assembly as the for loop. (On a newer Rust compiler, it was actually
able to unroll the combinator loop (and not the for loop), so I had to roll it back to an older
version to get this result.)&lt;&#x2F;p&gt;
&lt;p&gt;In this spirit, having all the knobs available is absolutely, 100% the right thing for the embedded
ecosystem in Rust to have done. None of the libraries make assumptions for you, at least not that
you can&#x27;t reconfigure. However, we want to end up with high-level wrapper libraries that &lt;em&gt;do&lt;&#x2F;em&gt; make
those assumptions for you — they can let you get started quickly, and you can sub them out
for the lower- level interfaces as needed. Rust doesn&#x27;t currently have these, and that&#x27;s what I&#x27;m
aiming to write.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;etymology-molubdos&quot;&gt;etymology: μόλυβδος&lt;&#x2F;h2&gt;
&lt;p&gt;μόλυβδος (&lt;em&gt;molybdos&lt;&#x2F;em&gt;) is Greek for lead. &quot;Batteries-included&quot; -&amp;gt; lead-acid batteries -&amp;gt; lead. I just
like the word (and the evident but unexpected connection to molybdenum).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>component: rust: mudl</title>
        <published>2024-03-14T00:00:00+00:00</published>
        <updated>2024-03-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/mudlrs/"/>
        <id>https://blog.npry.dev/class/machines/mudlrs/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/mudlrs/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;molybdos&quot;&gt;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;molybdos&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is a work-in-progress port of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jakeread&#x2F;mudlink&quot;&gt;Jake&#x27;s MUDL library&lt;&#x2F;a&gt; to
&lt;a href=&quot;https:&#x2F;&#x2F;rust-lang.org&quot;&gt;Rust&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; class=&quot;language-toml z-code&quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-toml&quot;&gt;#&lt;&#x2F;span&gt; Cargo.toml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-table z-begin z-toml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-table z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-table z-toml&quot;&gt;dependencies&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-table z-end z-toml&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;mudl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-inline-table z-begin z-toml&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-basic z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;https:&#x2F;&#x2F;public.git.npry.dev&#x2F;molybdos&lt;span class=&quot;z-punctuation z-definition z-string z-end z-toml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-inline-table z-end z-toml&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;rust-codec&quot;&gt;rust: &lt;code&gt;Codec&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;There are multiple versions of a generic &lt;code&gt;codec&lt;&#x2F;code&gt; concept in Rust crates:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;tokio-util&#x2F;latest&#x2F;tokio_util&#x2F;codec&#x2F;index.html&quot;&gt;&lt;code&gt;tokio_util::codec&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (&lt;a href=&quot;https:&#x2F;&#x2F;tokio.rs&#x2F;&quot;&gt;tokio&lt;&#x2F;a&gt;-specific)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;asynchronous-codec&#x2F;latest&#x2F;asynchronous_codec&#x2F;&quot;&gt;&lt;code&gt;asynchronous_codec&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matthunz&#x2F;futures-codec&quot;&gt;&lt;code&gt;futures_codec&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (defunct)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The concept interacts with Rust&#x27;s &lt;code&gt;Stream&lt;&#x2F;code&gt; and &lt;code&gt;Sink&lt;&#x2F;code&gt; types, which represent sources and sinks
(respectively) of values, which may be unbounded in length and can be iterated or submitted to
asynchronously.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;code&gt;Decoder&amp;lt;T&amp;gt;&lt;&#x2F;code&gt; implementation wraps an &lt;code&gt;io::AsyncRead&lt;&#x2F;code&gt; and converts it to a &lt;code&gt;Stream&amp;lt;T&amp;gt;&lt;&#x2F;code&gt;. An
&lt;code&gt;Encoder&amp;lt;T&amp;gt;&lt;&#x2F;code&gt; wraps an &lt;code&gt;io::AsyncWrite&lt;&#x2F;code&gt; and converts it to a &lt;code&gt;Sink&amp;lt;T&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Concretely, we might have &lt;code&gt;Decoder&amp;lt;serde_json::Json&amp;gt;&lt;&#x2F;code&gt; which decodes bytes into the generic
json inductive type, or  &lt;code&gt;Encoder&amp;lt;String&amp;gt;&lt;&#x2F;code&gt;, a trivial &lt;code&gt;Encoder&lt;&#x2F;code&gt; that encodes strings as
(for instance) utf-8 bytes.&lt;&#x2F;p&gt;
&lt;p&gt;This is the abstraction I would like to use for my implementation of &lt;code&gt;mudl&lt;&#x2F;code&gt;, as it&#x27;s extremely
generic and abstracts exactly the concept I&#x27;m aiming for. Unfortunately, existing implementations
of this type depend on rust&#x27;s full stanadard library, which isn&#x27;t generally available on
embedded targets.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;week-of-3-14-2024&quot;&gt;Week of 3&#x2F;14&#x2F;2024&lt;&#x2F;h2&gt;
&lt;p&gt;I forked and began rewriting &lt;code&gt;asynchronous_codec&lt;&#x2F;code&gt; to support &lt;code&gt;embedded-io-async&lt;&#x2F;code&gt;&#x27;s &lt;code&gt;Read&lt;&#x2F;code&gt; and
&lt;code&gt;Write&lt;&#x2F;code&gt; traits instead of &lt;code&gt;AsyncRead&lt;&#x2F;code&gt; and &lt;code&gt;AsyncWrite&lt;&#x2F;code&gt; (standard-library-dependent traits) —
you can see this in the repo. Unfortunately, the signatures for &lt;code&gt;Stream&lt;&#x2F;code&gt; and &lt;code&gt;Sink&lt;&#x2F;code&gt; aren&#x27;t readily
compatible with the embedded traits&#x27; &lt;code&gt;read&lt;&#x2F;code&gt; and &lt;code&gt;write&lt;&#x2F;code&gt; methods. I haven&#x27;t decided yet if I&#x27;m going
to adapt them to one another or write a specialized &lt;code&gt;embedded_codec&lt;&#x2F;code&gt; crate instead.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;week-of-3-21-2024&quot;&gt;Week of 3&#x2F;21&#x2F;2024&lt;&#x2F;h2&gt;
&lt;p&gt;This week I realized &lt;code&gt;mudl&lt;&#x2F;code&gt;&#x27;s approach doesn&#x27;t agree with my needs, so I decided to diverge from it.&lt;&#x2F;p&gt;
&lt;p&gt;The project I&#x27;m writing now (to be renamed) has the same goals (establishing a plug-and-play link
over Serial), but uses FEC rather than checksumming and has packet segmentation + reassembly
built-in.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m using Reed-Solomon as an ECC and COBS still for delimiting frames.&lt;&#x2F;p&gt;
&lt;p&gt;The message encoding stack is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|           Original data           |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            COBS Encode
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  COBS  |  COBS  |  COBS  |  COBS  | 0 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    |____________
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            Reed-Solomon
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            (each frame)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  COBS  |  Parity  | (one frame)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            COBS Encode
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|        COBS        | 0 |
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I.e. we split the original packet into COBS subpackets (can be done iteratively), calculate
Reed-Solomon for each subpacket, then COBS encode that. This gives a natural way to do segmentation
while only requiring a single subframe in memory at any time (applications may choose to fully
reassemble) the complete original frame if desired, but this is not required for the protocol to work.&lt;&#x2F;p&gt;
&lt;p&gt;The double-COBS wrapping is an attempt to mitigate corruptions of the sentinel.&lt;&#x2F;p&gt;
&lt;p&gt;The Reed-Solomon ECC overhead can be tuned based on the physical link characteristics to mitigate
packet corruption or loss without stateful negotiation or a control channel in the protocol.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m still in the middle of implementing this.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>(abandoned) component: mini heat press</title>
        <published>2024-03-01T00:00:00+00:00</published>
        <updated>2024-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/heat-press/"/>
        <id>https://blog.npry.dev/class/machines/heat-press/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/heat-press/">&lt;p&gt;&lt;strong&gt;NOTE&lt;&#x2F;strong&gt;: This project is relatively expensive for the course budget (~$350 &#x2F;
person) and isn&#x27;t strictly necessary for my system, so I&#x27;m not including it as
a component I&#x27;m committing to.&lt;&#x2F;p&gt;
&lt;p&gt;A heat press for flattening or forming small pieces of sheet stock.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;specifications&quot;&gt;specifications&lt;&#x2F;h2&gt;
&lt;p&gt;(subject to adjustment)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Stock dimensions &amp;lt;= 200mm x 200mm x 10mm, must be rectilinear&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Conveyor or roller feed in&#x2F;out in a north-south direction&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;50C &amp;lt; Max temperature &amp;lt; 100C&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;1N &amp;lt; Max closing force &amp;lt; 10N&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Package dimensions: &amp;lt;= 250mm x 250mm x 250mm&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;DIN rail mountable&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;M4 machine screw mounting holes in corners&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Power interface: 12V, 5A barrel jack&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;heat-forming-dies&quot;&gt;heat forming dies&lt;&#x2F;h3&gt;
&lt;p&gt;Machine is configurable with low-relief heat-forming dies &amp;lt; 50mm x 50mm.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Low-pressure only! Not for stamping or punching unless very malleable material&lt;&#x2F;li&gt;
&lt;li&gt;Must be sufficiently heat-conductive&lt;&#x2F;li&gt;
&lt;li&gt;Die holder geometry TBD -- currently envisioning a replaceable section of the
heating plates&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;communication-interface&quot;&gt;communication interface&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Speaks &lt;a href=&quot;https:&#x2F;&#x2F;protobuf.dev&quot;&gt;Protobuf&lt;&#x2F;a&gt; (&lt;a href=&quot;..&#x2F;misc&#x2F;protobuf&quot;&gt;plug&lt;&#x2F;a&gt;) over UART&lt;&#x2F;li&gt;
&lt;li&gt;12-pin IDC connector (&lt;a href=&quot;..&#x2F;misc&#x2F;pinout&quot;&gt;candidate standardized pinout&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Digital pin control (preconfigured temperature, closing height, feed distance)
&lt;ul&gt;
&lt;li&gt;In
&lt;ul&gt;
&lt;li&gt;Feed  &#x2F; Not Stop&lt;&#x2F;li&gt;
&lt;li&gt;Close &#x2F; Not Open&lt;&#x2F;li&gt;
&lt;li&gt;Heat  &#x2F; Not Cool&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Out
&lt;ul&gt;
&lt;li&gt;Overheat&lt;&#x2F;li&gt;
&lt;li&gt;Motion complete&lt;&#x2F;li&gt;
&lt;li&gt;General fault&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;cost-complexity&quot;&gt;cost&#x2F;complexity&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;On the order of $100 in parts, most COTS, some 3d printed, PCB&lt;&#x2F;li&gt;
&lt;li&gt;Assembly time: an afternoon&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;work-in-progress-bom&quot;&gt;work-in-progress BoM&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$32 &lt;a href=&quot;https:&#x2F;&#x2F;www.digikey.com&#x2F;en&#x2F;products&#x2F;detail&#x2F;sparkfun-electronics&#x2F;COM-11288&#x2F;6569360&quot;&gt;resistive heaters x 8&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$20 &lt;a href=&quot;https:&#x2F;&#x2F;www.mcmaster.com&#x2F;products&#x2F;shafts&#x2F;linear-motion-shafts-5&#x2F;&quot;&gt;shafts (~10mm?)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$10 &lt;a href=&quot;https:&#x2F;&#x2F;www.mcmaster.com&#x2F;products&#x2F;bushings&#x2F;plain-bearings~&#x2F;oil-embedded-sleeve-bearings-7&#x2F;system-of-measurement~metric&#x2F;&quot;&gt;bushings&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$15 &lt;a href=&quot;https:&#x2F;&#x2F;www.mcmaster.com&#x2F;products&#x2F;springs&#x2F;compression-springs-7&#x2F;system-of-measurement~metric&#x2F;id~10-6-mm&#x2F;&quot;&gt;springs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;OR: $10 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B08B4JDB67&quot;&gt;v rollers&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$30? 8020 frame + assembly hardware&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$5 3d prints&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$10 electrical components&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$15 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B08JPM29FD&quot;&gt;lead screw x2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$12 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B00PNEQ9T4&quot;&gt;NEMA 12 stepper&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$9 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B07BRKZGMS&quot;&gt;GT2 Belt&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$7 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B077GNZK3J&quot;&gt;GT2 Pulleys&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Total ~$150 at current estimate.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>system: pushbutton two-layer pcb mill</title>
        <published>2024-03-01T00:00:00+00:00</published>
        <updated>2024-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/pcb-system/"/>
        <id>https://blog.npry.dev/class/machines/pcb-system/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/pcb-system/">&lt;p&gt;&lt;a href=&quot;..&#x2F;clank-build&quot;&gt;update: clank build&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;..&#x2F;casette&quot;&gt;update: casette build&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;script type=&quot;module&quot; src=&quot;https:&#x2F;&#x2F;ajax.googleapis.com&#x2F;ajax&#x2F;libs&#x2F;model-viewer&#x2F;3.1.1&#x2F;model-viewer.min.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;p&gt;Desktop-scale PCB maker that completes a 2-layer board in under an hour.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;state-of-the-world-why&quot;&gt;state of the world &#x2F; why&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;PCBs from China are cheap and fast (JLC, PCBWay)
&lt;ul&gt;
&lt;li&gt;Still too slow for iterating effectively&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;PCBs from the US are expensive and slow, but required sometimes for export
control&lt;&#x2F;li&gt;
&lt;li&gt;DIY options have major drawbacks
&lt;ul&gt;
&lt;li&gt;Approaches
&lt;ul&gt;
&lt;li&gt;Mill&lt;&#x2F;li&gt;
&lt;li&gt;Lasercut&lt;&#x2F;li&gt;
&lt;li&gt;Chemical etch&lt;&#x2F;li&gt;
&lt;li&gt;Print conductive ink&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&amp;lt; 1 day turnaround, but at the cost of babysitting and obtuse tooling&lt;&#x2F;li&gt;
&lt;li&gt;Low quality
&lt;ul&gt;
&lt;li&gt;Process variability&lt;&#x2F;li&gt;
&lt;li&gt;Resolution limits&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Process limitations:
&lt;ul&gt;
&lt;li&gt;2-layer is difficult, &amp;gt; 2 infeasible&lt;&#x2F;li&gt;
&lt;li&gt;Masking is difficult&lt;&#x2F;li&gt;
&lt;li&gt;Silks are difficult&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The product I want can take a KiCad project and produce a consistent board (with mask, no assembly)
within the hour without supervision.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;requirements&quot;&gt;requirements&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;At least 200um trace width&lt;&#x2F;li&gt;
&lt;li&gt;2 layers&lt;&#x2F;li&gt;
&lt;li&gt;(Nice-to-have) selectively applies solder mask&lt;&#x2F;li&gt;
&lt;li&gt;(Nice-to-have) conductive vias&lt;&#x2F;li&gt;
&lt;li&gt;If milling
&lt;ul&gt;
&lt;li&gt;Mesh bed leveling&lt;&#x2F;li&gt;
&lt;li&gt;Automatic tool changer&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;design-draft&quot;&gt;design draft&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;model-viewer src=&quot;blockout.glb&quot; shadow-intensity=&quot;1&quot; camera-controls touch-action=&quot;pan-y&quot; style=&quot;width: 900px; height: 600px;&quot;&gt;&lt;&#x2F;model-viewer&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Currently planning on using most recent revision of &lt;a href=&quot;https:&#x2F;&#x2F;clank.tools&quot;&gt;Clank&lt;&#x2F;a&gt; (stretch variant)
as the platform.&lt;&#x2F;p&gt;
&lt;p&gt;Additional features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Vacuum holddown&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Toolchanger&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Isolation: V-bit&lt;&#x2F;li&gt;
&lt;li&gt;Cutout: endmill&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Stock loading and manipulation (ER arm)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;anticipated-flow&quot;&gt;anticipated flow&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Upload KiCad board file to website hosted by rpi attached to clank&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.kicad.org&#x2F;8.0&#x2F;en&#x2F;cli&#x2F;cli.html&quot;&gt;Export gerbers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Run &lt;a href=&quot;https:&#x2F;&#x2F;modsproject.org&#x2F;&quot;&gt;mods&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pcb2gcode&#x2F;pcb2gcode&quot;&gt;pcb2gcode&lt;&#x2F;a&gt; as
CAM -&amp;gt; GCode&lt;&#x2F;li&gt;
&lt;li&gt;Auto-tabs (require at least 2)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;GCode translation &#x2F; edits as required -- working with Jake&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Trying MAXL&lt;&#x2F;li&gt;
&lt;li&gt;Fallback: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;grbl&#x2F;grbl&quot;&gt;GRBL&lt;&#x2F;a&gt; or similar on a COTS controller + motor driver
board&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Stock handling&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Goals:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Load sheets from stack of stock, index to consistent position&lt;&#x2F;li&gt;
&lt;li&gt;Flip stock for second side of board, reindex &lt;em&gt;stock outline&lt;&#x2F;em&gt; to same position&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Want to use &lt;a href=&quot;https:&#x2F;&#x2F;www.elephantrobotics.com&#x2F;en&#x2F;mycobot-en&#x2F;&quot;&gt;ER mycobot arm&lt;&#x2F;a&gt; with
suction cups (vacuum)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Probably need to reserve some real-estate on the stock for clean pickup points&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Open-loop stock indexing: pins, push into corner&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Indexing side 2&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Cutouts for X-Y probing?&lt;&#x2F;li&gt;
&lt;li&gt;Could do CV, but not really a fan. Maybe the right thing to do here though.&lt;&#x2F;li&gt;
&lt;li&gt;Maybe just measure width of stock, compute where board should be, fix x zero&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Outfeed to stack by machine&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Vacuum holddown&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Just a plate with hole pattern and a plenum underneath. Use a shop vac with a relay.&lt;&#x2F;li&gt;
&lt;li&gt;Selected because it seems most straightforward way to automatically control holddown&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Autoleveling&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Probe with Clank&#x27;s load cell&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Machining sequence&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;V-bit isolation (front)&lt;&#x2F;li&gt;
&lt;li&gt;Flip&lt;&#x2F;li&gt;
&lt;li&gt;V-bit isolation (back)&lt;&#x2F;li&gt;
&lt;li&gt;Cutout&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Tool changing&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Use &quot;fork&quot; design suggested by Jake&lt;&#x2F;li&gt;
&lt;li&gt;Interpose a holdable U slot shape in the Kleat interface stackup&lt;&#x2F;li&gt;
&lt;li&gt;Several forks mounted to the bed&lt;&#x2F;li&gt;
&lt;li&gt;Lower the U of the tool onto the fork, release the Kleat, pull back&lt;&#x2F;li&gt;
&lt;li&gt;Inverse for pickup&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;u_holder.e8be58ed48e82c1b.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;model-viewer src=&quot;u_holder.glb&quot; shadow-intensity=&quot;1&quot; camera-controls touch-action=&quot;pan-y&quot; style=&quot;width: 900px; height: 600px;&quot;&gt;&lt;&#x2F;model-viewer&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;solder-mask&quot;&gt;Solder mask&lt;&#x2F;h3&gt;
&lt;p&gt;Not in first rev of the machine. If the two-sided milling works, will add.&lt;&#x2F;p&gt;
&lt;p&gt;Concept:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;squeegee liquid mask through screen for consistent application amount&lt;&#x2F;li&gt;
&lt;li&gt;cure with UV light mounted to machine or on tool head&lt;&#x2F;li&gt;
&lt;li&gt;selectively mill off with &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=wr7l67sd3NM&quot;&gt;springloaded v-bit&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sequencing: after isolation on each layer.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;vias&quot;&gt;Vias&lt;&#x2F;h3&gt;
&lt;p&gt;Not in first rev of the machine. If the two-sided milling works, will add.&lt;&#x2F;p&gt;
&lt;p&gt;Concept:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;rivets&lt;&#x2F;li&gt;
&lt;li&gt;anvil &#x2F; die at a fixed location mounted to bed&lt;&#x2F;li&gt;
&lt;li&gt;cobot picks up and holds stock, referencing gerbers or pcb file (** cobot probably insufficient for precision)&lt;&#x2F;li&gt;
&lt;li&gt;custom end effector with a rivet magazine and punch&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sequencing: after both sides isolated, before cutout.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>(abandonded) component: mini stock elevator</title>
        <published>2024-03-01T00:00:00+00:00</published>
        <updated>2024-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/machines/stock-elevator/"/>
        <id>https://blog.npry.dev/class/machines/stock-elevator/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/machines/stock-elevator/">&lt;p&gt;An elevator for feeding stacked sheet stock sheet-by-sheet.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;sketch.e2363a6f2c434628.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;specifications&quot;&gt;specifications&lt;&#x2F;h2&gt;
&lt;p&gt;(subject to adjustment)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Accepts vertical 100mm stack of stock&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Dimensional tolerance across stackup +- 2mm in XY&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Stock dimensions &amp;lt;= 200mm x 200mm x 10mm, must be rectilinear&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Outfeed at the top of the stack, height TBD&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Package dimensions: &amp;lt;= 250mm x 250mm x 250mm&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;DIN rail mountable&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;M4 machine screw mounting holes in corners&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Power interface: 12V, 5A barrel jack&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;communication-interface&quot;&gt;communication interface&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Speaks &lt;a href=&quot;https:&#x2F;&#x2F;protobuf.dev&quot;&gt;Protobuf&lt;&#x2F;a&gt; (&lt;a href=&quot;..&#x2F;misc&#x2F;protobuf&quot;&gt;plug&lt;&#x2F;a&gt;) over UART,
115200 baud&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;12-pin IDC connector (&lt;a href=&quot;..&#x2F;misc&#x2F;pinout&quot;&gt;candidate standardized pinout&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Digital pin control (preconfigured temperature, closing height, feed distance)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;In
&lt;ul&gt;
&lt;li&gt;Feed once (edge triggered)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Out
&lt;ul&gt;
&lt;li&gt;Feeding&lt;&#x2F;li&gt;
&lt;li&gt;Out of stock&lt;&#x2F;li&gt;
&lt;li&gt;General fault&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;cost-complexity&quot;&gt;cost&#x2F;complexity&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;On the order of $100 in parts, most COTS, some 3d printed, PCB&lt;&#x2F;li&gt;
&lt;li&gt;Assembly time: an afternoon&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;work-in-progress-bom&quot;&gt;work-in-progress BoM&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$20 &lt;a href=&quot;https:&#x2F;&#x2F;www.mcmaster.com&#x2F;products&#x2F;shafts&#x2F;linear-motion-shafts-5&#x2F;&quot;&gt;shafts (~10mm?)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$10 &lt;a href=&quot;https:&#x2F;&#x2F;www.mcmaster.com&#x2F;products&#x2F;bushings&#x2F;plain-bearings~&#x2F;oil-embedded-sleeve-bearings-7&#x2F;system-of-measurement~metric&#x2F;&quot;&gt;bushings&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;OR: $10 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B08B4JDB67&quot;&gt;v rollers&lt;&#x2F;a&gt; with 8020&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$30? 8020 frame + assembly hardware&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$10 3d prints&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$10 electrical components&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$15 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B08JPM29FD&quot;&gt;lead screw x2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$12 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B00PNEQ9T4&quot;&gt;NEMA 12 stepper&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$9 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B07BRKZGMS&quot;&gt;GT2 Belt&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;$7 &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B077GNZK3J&quot;&gt;GT2 Pulleys&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>edf&#x2F;tvc drone</title>
        <published>2023-12-29T00:00:00+00:00</published>
        <updated>2024-08-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/edf/"/>
        <id>https://blog.npry.dev/resenv/edf/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/edf/">&lt;div style=&quot;display: flex; flex-direction: column; align-items: center; padding: 1rem&quot; class=&quot;vidwrap&quot;&gt;
    &lt;video
        src=&quot;tvc_drone.webm&quot;
        
        muted
        controls
        
        
        class=&quot;hover_controls&quot;
        style=&quot;width: 480px; border-radius: 1rem&quot;
    &gt;
    &lt;&#x2F;video&gt;
    
    &lt;i style=&quot;margin-top: 0.5rem&quot;&gt;
        &lt;p&gt;inspiration (&lt;a href=&quot;https:&#x2F;&#x2F;youtube.com&#x2F;watch?v=u2cETOyuJ20&quot;&gt;youtube&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.printables.com&#x2F;model&#x2F;722967-ducted-fan-thrust-vectoring-drone&quot;&gt;docs&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;

    &lt;&#x2F;i&gt;
    
&lt;&#x2F;div&gt;

&lt;p&gt;I&#x27;ve been into controls for a year or so and thought this would be a great
project to experiment with. I should be able to (literally) get it off the
ground for design validation using &lt;a href=&quot;https:&#x2F;&#x2F;docs.px4.io&#x2F;main&#x2F;en&#x2F;&quot;&gt;PX4&lt;&#x2F;a&gt; —
they use it in this video, just running PID. I have a flight controller to use
from work on &lt;a href=&quot;..&#x2F;omnidrone&quot;&gt;omnicopter&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m aiming to implement LQR with an observer from scratch running on a
microcontroller, then bring in more advanced approaches in &lt;a href=&quot;https:&#x2F;&#x2F;underactuated.mit.edu&quot;&gt;underactuated
robotics&lt;&#x2F;a&gt; (I was a listener in Spring 2024).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;progress&quot;&gt;progress&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve been iterating on mechanical for a long time, more or less whenever I&#x27;ve
had a spare moment in the past 6 months. Many many revisions of the nacelle,
mostly to work out fitment and assembly around the servo mounting and control
vanes.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m currently dealing with an apparent mismatch on the nacelle and vane
dimensions — the vane shaft is too long to the point it collides with the
servo. It looks wrong, but the measurements I&#x27;ve taken all line up with the
CAD, which doesn&#x27;t look wrong and suggests the servo should fit. I&#x27;ve had other
things to do for a few weeks so have just left it in this state for now.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>final project</title>
        <published>2023-12-19T00:00:00+00:00</published>
        <updated>2023-12-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/final-tracking/"/>
        <id>https://blog.npry.dev/class/htm/final-tracking/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/final-tracking/">&lt;script type=&quot;module&quot; src=&quot;https:&#x2F;&#x2F;ajax.googleapis.com&#x2F;ajax&#x2F;libs&#x2F;model-viewer&#x2F;3.1.1&#x2F;model-viewer.min.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;p&gt;&lt;video src=&#x27;final_video.mp4&#x27; type=&quot;video&#x2F;mp4&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;vr cockpit simulator&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;welded steel frame&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;adjustable chair&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;mfd button bezel&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;mfd test interface&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;final-tracking&#x2F;mfd_controller.ino&quot;&gt;mfd controller arduino sketch&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;final-tracking&#x2F;mfd.tar.gz&quot;&gt;mfd design files&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;final-tracking&#x2F;mfd_test_interface.tar.gz&quot;&gt;mfd interface&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;final-tracking&#x2F;chair.step&quot;&gt;chair + frame design files (STEP)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;final-tracking&#x2F;final_slide.pdf&quot;&gt;summary slide&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Seat model viewer:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;model-viewer src=&quot;chair.glb&quot; shadow-intensity=&quot;1&quot; camera-controls touch-action=&quot;pan-y&quot; style=&quot;width: 640px; height: 480px;&quot;&gt;&lt;&#x2F;model-viewer&gt;&lt;&#x2F;p&gt;
&lt;p&gt;MFD model viewer:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;model-viewer src=&quot;mfd.gltf&quot; shadow-intensity=&quot;1&quot; camera-controls touch-action=&quot;pan-y&quot; style=&quot;width: 640px; height: 480px;&quot;&gt;&lt;&#x2F;model-viewer&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Early render (previous revision):&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chair.486ad0f7036396cb.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I built a flight simulator cockpit designed for VR. It integrates:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Position-adjustable mounts for components I had prior to the class (flight stick, throttle, rudder pedals)&lt;&#x2F;li&gt;
&lt;li&gt;Multi-function display (&quot;MFD&quot;) button bezels that present to the host computer as 25-button gamepads over USB&lt;&#x2F;li&gt;
&lt;li&gt;A highly position-adjustable seat, supporting independently setting:
&lt;ul&gt;
&lt;li&gt;The height of the front of the seat&lt;&#x2F;li&gt;
&lt;li&gt;The height of the back of the seat&lt;&#x2F;li&gt;
&lt;li&gt;Seat back angle&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;A test interface for the MFDs&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Problems I&#x27;m solving:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Setup and teardown cost of my existing peripherals is high
(attaching&#x2F;detaching to desk and putting back into storage). I want a fixed,
desk-independent setup where everything is in position by default.&lt;&#x2F;li&gt;
&lt;li&gt;Using rudder pedals for an extended period of time in a normal chair causes
you to lean back on your tailbone. Not ergonomic over any meaningful amount of time -- chair is adjustable to allow me to find a reasonably comfortable sitting position.&lt;&#x2F;li&gt;
&lt;li&gt;For similar reasons, control manipulator (throttle, rudder pedals, joystick) position is important relative to sitting position -- these should be finely adjustable.&lt;&#x2F;li&gt;
&lt;li&gt;VR-controller-based cockpit interaction is very clunky. I want physical
buttons instead, where possible. MFDs are the clearest pain point -- I use them a lot to interact with menuing, and they&#x27;re impractical to bind to existing surplus buttons.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;prior-art&quot;&gt;prior art&lt;&#x2F;h2&gt;
&lt;p&gt;There is extensive prior art in building simulated cockpits online. A conceptual
inspiration for me is &lt;a href=&quot;https:&#x2F;&#x2F;thewarthogproject.com&#x2F;&quot;&gt;The Warthog Project&lt;&#x2F;a&gt;,
building a simulator for an A-10C II Warthog, who I&#x27;ve watched extensively on YouTube.&lt;&#x2F;p&gt;
&lt;p&gt;Worth also putting in this section that I already had my primary flight controls before
even starting the class and had desk mounts for them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;production-summary-bom&quot;&gt;production summary + bom&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;seat&quot;&gt;seat&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;MIG welded steel tube (1.25&quot; OD x 0.125&quot; wall thickness, ~30&#x27; from CBA shop stock)&lt;&#x2F;li&gt;
&lt;li&gt;FDM-printed bearing and interface blocks (PLA, produced on ResEnv Prusas and my personal Ender 3)&lt;&#x2F;li&gt;
&lt;li&gt;1&#x2F;2-13 threaded rod (&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B07N91CGYB&quot;&gt;Amazon&lt;&#x2F;a&gt;, $13 per 2), with &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B009EE2SN0&quot;&gt;nuts&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B009OJI0XC&quot;&gt;washers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;M8 and 5&#x2F;16&quot; (nearly the same OD, so functionally interchangeable in my project) bolts, nuts, and washers (various lengths, some from &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B01C3KUGVC&quot;&gt;Amazon&lt;&#x2F;a&gt;, some from Home Depot)&lt;&#x2F;li&gt;
&lt;li&gt;8mm ground shaft -- &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B01NCOMFLT&quot;&gt;Amazon&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Skateboard bearings (8mm x 22mm x 7mm) -- &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;dp&#x2F;B08XVFSZTF&quot;&gt;Amazon&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Latex foam matress topper (seat, unknown provenance -- received for free)&lt;&#x2F;li&gt;
&lt;li&gt;3&#x2F;4&quot; plywood (seat, unknown provenance -- received for free)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;flight-controls-i-already-owned-all-from-virpil-controls&quot;&gt;flight controls (i already owned, all from &lt;a href=&quot;https:&#x2F;&#x2F;virpil-controls.us.com&#x2F;&quot;&gt;virpil controls&lt;&#x2F;a&gt;)&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;virpil-controls.us.com&#x2F;vpc-mongoost-50cm2-grip.html&quot;&gt;MongoosT-50CM2 Grip&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;virpil-controls.us.com&#x2F;vpc-mongoost-50cm3-base.html&quot;&gt;MongoosT-50CM3 Stick Base&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;virpil-controls.us.com&#x2F;vpc-flightstick-extension-200mm.html&quot;&gt;VPC Flightstick Extension (200mm)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;virpil-controls.us.com&#x2F;vpc-mongoost-50cm3-throttle.html&quot;&gt;MongoosT-50CM3 Throttle&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;virpil-controls.us.com&#x2F;vpc-ace-flight-pedals.html&quot;&gt;VPC ACE Pedals&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;mfd-panel&quot;&gt;mfd panel&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;22ga sheet steel (cold-rolled), lasercut and hemmed in CBA shop (see &lt;a href=&quot;..&#x2F;wildcard&#x2F;&quot;&gt;wildcard week&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;FR1 copper boards, double-sided (&lt;a href=&quot;https:&#x2F;&#x2F;www.sparkfun.com&#x2F;products&#x2F;14979&quot;&gt;SparkFun&lt;&#x2F;a&gt;) -- milled on ResEnv PCB mill with 20 deg v-bits&lt;&#x2F;li&gt;
&lt;li&gt;FDM-printed MFD frame (PLA, ResEnv Prusas)&lt;&#x2F;li&gt;
&lt;li&gt;M4 heat-set inserts and machine screws (from ResEnv inventory)&lt;&#x2F;li&gt;
&lt;li&gt;12mm momentary buttons (from ResEnv inventory)&lt;&#x2F;li&gt;
&lt;li&gt;SLA-printed button heads (ResEnv Form 3, Clear V4 resin)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;software&quot;&gt;software&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Autodesk Inventor (CAD)&lt;&#x2F;li&gt;
&lt;li&gt;OnShape (CAD, switched from Inventor)&lt;&#x2F;li&gt;
&lt;li&gt;KiCad (EDA)&lt;&#x2F;li&gt;
&lt;li&gt;Blender (misc renders)&lt;&#x2F;li&gt;
&lt;li&gt;Arduino (controller firmware)&lt;&#x2F;li&gt;
&lt;li&gt;pygame (test interface)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;mfds&quot;&gt;mfds&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;Early concept:&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;mfd.0104aa52284938d5.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h3&gt;
&lt;p&gt;&quot;Multi-function display&quot; -- displays in cockpit with buttons around them that a
pilot can press for various menued functions. Since I fly in VR, I don&#x27;t need
the display element itself, just the buttons.&lt;&#x2F;p&gt;
&lt;p&gt;I designed the MFD in 4 modular parts that fit together with dovetails. Each
side mounts a PCB:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;board_fit.b3bb8345cf8cae58.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;and has 5 buttons:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;boards_inplace.538db757baa31aa4.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The boards interface with IDC connectors which are connected to a controller
board. The controller is a RasPi Pico that reads the digital state of all of
its pins and connects to a host computer over USB as a generic gamepad.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;controller_assembled.a48fe03e55dfc3f9.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;v1-button-boards-frame&quot;&gt;v1 (button boards + frame)&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;dovetails&quot;&gt;dovetails&lt;&#x2F;h4&gt;
&lt;p&gt;I started by printing a test piece for the corner dovetails (zero offset
made a nice tight fit):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;corner_test.8b92d54e593c1be3.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;With heatsets installed and M3 screws:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;corner_test_heatset.b2ec8eb6edccdd54.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;First version with full sides (wrong size, mitered corners):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;full_edges.e695d8ac03a224ce.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h4 id=&quot;button-assembly&quot;&gt;button assembly&lt;&#x2F;h4&gt;
&lt;p&gt;I printed heads for 12mm pushbuttons using the Form 3 out of clear resin:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;button_heads.7c00852b139ccba0.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Assmbled:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;button_assembled.f858b52edb4d8d37.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Zero offset was also just right for these.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;pcb&quot;&gt;pcb&lt;&#x2F;h4&gt;
&lt;p&gt;I transfered the relevant outline from Inventor and designed the boards
to fit within the available space. I marked mounting holes where the heatsets
would be.&lt;&#x2F;p&gt;
&lt;p&gt;I did some test patterns because I was seeing axis-aligned inconsistency in my
cuts:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;test_patterns.f1363de62bf22d09.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;First try was a bit fuzzy:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;milling_burrs.0346a171eb73ee23.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Some more attempts:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;milling_attempts.1fde8412bc44b7bb.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;milling_attempts_2.f6856b59ab721064.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Finally a successful board:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;milled_board_ok_inplace.cc708e0bcbbaa978.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;milled_board_ok.487eadbfeed894b8.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;buttons-final&quot;&gt;buttons (final)&lt;&#x2F;h3&gt;
&lt;p&gt;The board needed a minor rev after I updated the layout of the controller board
to change the order of the pinout. I also increased trace width and isolation
to make the boards easier to mill and solder:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;buttons_inplace.002118d8f0ac4617.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;To get the buttons in the right spot, I placed them in the frame upside-down and put
a dot of superglue onto each one:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;superglue_applied.e68849e6e947eae3.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Then I screwed the pcb into the frame and let the superglue dry. I took the
whole assembly out once it was dry and had the buttons in exactly the right
place:&lt;&#x2F;p&gt;
&lt;p&gt;Then I soldered them:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;buttons_soldered.2a50b6a8b30897c7.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I discovered eventually that all of the boards always reported button 1 pressed.
This was because of this mounting hole (rightmost):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;short.852d15bd1c4f37f4.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The threaded insert would short the ground plane to the trace next to the hole,
making it look like the right button was always pressed. So I applied superglue
as conformal coating:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;conformal.6aed17c65c47a4ef.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This worked.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;controller&quot;&gt;controller&lt;&#x2F;h3&gt;
&lt;p&gt;Milled controller board:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;mfd_controller_milled.c8e077d6152d0eda.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Cleaned up:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;mfd_controller_milled2.9c76bc82fbd94dec.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Forgot to individually isolate pads on pico reverse, so as in the button boards,
applied superglue as conformal coating:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;superglue_rp2040.8f23775e59ae0c82.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Pico soldered:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;soldered_rp2040.e9895601c70a779d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Assembled with IDC connectors:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;controller_assembled.a48fe03e55dfc3f9.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;You&#x27;ll note I&#x27;m using 2-layer boards with through-hole components -- as I
described in &lt;a href=&quot;..&#x2F;elec-production&#x2F;&quot;&gt;electronics production&lt;&#x2F;a&gt;, I used a small drill
bit (~3mm OD) by hand to chamfer &#x2F; countersink the holes on the reverse side of
the board so the pins wouldn&#x27;t make contact. If you&#x27;re deliberate about it, this
approach is very consistent in ensuring the pins don&#x27;t short to the back plane.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;firmware&quot;&gt;firmware&lt;&#x2F;h3&gt;
&lt;p&gt;Uses the rp2040 port of the Arduino &lt;code&gt;Joystick&lt;&#x2F;code&gt; library to represent the mfd as a gamepad.
Very simple -- polling-based. Slight optimization I made that drastically improves
responsiveness is setting manual reporting and doing change tracking myself
— naive approach sends a USB packet for every button it scans.&lt;&#x2F;p&gt;
&lt;p&gt;Sketch &lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;final-tracking&#x2F;mfd_controller.ino&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;interface&quot;&gt;interface&lt;&#x2F;h3&gt;
&lt;p&gt;I made &lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;final-tracking&#x2F;mfd_test_interface.tar.gz&quot;&gt;an interface&lt;&#x2F;a&gt; in pygame to validate the function of
the MFD controllers.&lt;&#x2F;p&gt;
&lt;p&gt;This is functionally duplicative of the Windows gamepad tester -- I really only made this to
fulfill the requirement that I personally implement the interface.&lt;&#x2F;p&gt;
&lt;p&gt;Plugging and unplugging a controller:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;plug_unplug.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Shorting a button gpio to ground (emulating button press):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;basic_demo.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;MFDs are hotpluggable and multiple are supported simultaneously:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;second_mfd.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;controller-enclosure&quot;&gt;controller enclosure&lt;&#x2F;h3&gt;
&lt;p&gt;I 3d-printed an enclosure for the controller out of PLA:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;pcb_enclosure.50620401fffa00fb.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Cable routing (reverse):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;pcb_enclosure_wiring.86c1451d91a8b978.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;frame&quot;&gt;frame&lt;&#x2F;h2&gt;
&lt;p&gt;I made the frame out of 1 1&#x2F;4&quot; OD x 1&#x2F;8&quot; wall round pipe. I cut
the pieces I need on the horizontal bandsaw:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;bandsaw.6a47c59220041daa.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Result:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;pieces_cut.a39acde521e41b38.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I chamfered them on the belt sander:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;belt_sander.9b8eb2fcec12ca51.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chamfered.d9acc422ed47f3f0.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;And used an angle grinder with a flap disk to clean the scale off the surfaces
to prepare for welding:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;angle_grinder.928c2e94c0d4410a.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;weld_cleaned.fd242ae270985a2e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I milled cutouts on several of the T-joints to improve fitment:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;milling_corner.3b97f46fe3d1ab68.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I needed through-holes in several parts, which I did on the drill press.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;thru_holes_center.0bd2095e51ea2220.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;thru_holes.84999f1b6bd1c022.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I didn&#x27;t do a great job controlling weld heat, so the T-joints on the upright
warped the frame upwards. I added feet made out of scrap to level the piece:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;welded_feet.c8a24fbba42104be.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;mfd-front-panel&quot;&gt;mfd front panel&lt;&#x2F;h3&gt;
&lt;p&gt;I stiffened the front panel I made in &lt;a href=&quot;..&#x2F;wildcard&#x2F;&quot;&gt;wildcard week&lt;&#x2F;a&gt; using
MIG welding and some small square tube:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;stiffened_welds.c189022df8fc7494.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Obviously, it&#x27;s not perfect -- nowhere close to rigid -- but I was able to take
most of the warp out of it that I put into it from hammering the hem.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;stiffened_panel.8bc97a4e84f720fd.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;chair-joints&quot;&gt;chair joints&lt;&#x2F;h2&gt;
&lt;p&gt;The joints are 3d printed and have bearings pressed into them that
ride on 8mm shaft.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;3dprints_assembled.af457f8a1953ecbd.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The chair legs are height-adjustable via nuts on threaded rod.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;nut_interface.c1202820ca35aa93.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The top of the threaded rod is captured by a clevis block with a bearing that
allows the connected part of the chair to move vertically:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;joint.647bc09e0f78f1df.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Together, these blocks permit fore-and-aft vertical adjustment of the seat base
and angular adjustment of the seat back.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;controls-mounting&quot;&gt;controls mounting&lt;&#x2F;h2&gt;
&lt;p&gt;The controls mount with custom blocks that friction fit (tightly) onto the
tube — adjusting the position of the controls means wiggling them on the
tube they&#x27;re mounted on.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;panel_mount.ccfee0ea576f06aa.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This is the rudder mount being printed:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;printing_rudder_mount.5188649d99da2635.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;It is the one mount that needs to be tapped in with a hammer because there&#x27;s
so much contact area.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problems&quot;&gt;problems&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;racking&quot;&gt;racking&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;video src=&#x27;frame&#x2F;frame_racking.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The clevis joints on the frame are nowhere near sturdy enough to resist racking
laterally — I could tell they were going to snap. So I sacrificed a couple
of degrees of freedom and welded the front of the chair in place. This made the
chair sturdy enough, but still left me the back screws to adjust.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3d-printing&quot;&gt;3d printing&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;broken-heater&quot;&gt;broken heater&lt;&#x2F;h4&gt;
&lt;p&gt;I mostly used Responsive Environments&#x27; fdm printers for my 3d printing needs.
On one of them, the wires fatigued off of the heating element because the
heater block wasn&#x27;t screwed into the heat brake tightly:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;hotend_broken.be771cdd67967ba6.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;fab.cba.mit.edu&#x2F;classes&#x2F;863.10&#x2F;people&#x2F;brian.mayton&#x2F;index.html&quot;&gt;Brian&lt;&#x2F;a&gt; and
I fixed this up with spare parts he brought from home.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;clevis-split&quot;&gt;clevis split&lt;&#x2F;h4&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;split_clevis.bcdb979d57bba180.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;These clevis blocks were printed in a convenient-but-weak orientation and split
when I pressed bearings into them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-evaluated&quot;&gt;how evaluated&lt;&#x2F;h2&gt;
&lt;p&gt;The project&#x27;s internal evaluation norms are whether I&#x27;m comfortable in the seat
and if it&#x27;s sufficiently adjustable to put my body where it needs to be to use
the controls, but the adjustability shouldn&#x27;t permit it to move if I&#x27;m not
adjusting it. I also needed it to be minimally portable (I need to be able to
move it in my car).&lt;&#x2F;p&gt;
&lt;p&gt;The project succeeds on the comfort and portability axes — I built it
for everything to come off of the frame, so it will fit in my car. The latex foam
makes it very comfortable.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s not perfectly stable — I didn&#x27;t handle lateral stability well. I&#x27;m
considering fine-tuning the position and then welding the back legs of the chair
in place to make it fully rigid.&lt;&#x2F;p&gt;
&lt;p&gt;It doesn&#x27;t entirely succeed on the adjustability axis either — I was able
to get pretty close to what I want, but I put the uprights for the front panel
slightly in the way of where my legs want to be to use the rudder pedals, and
the joystick is too far forward (I may be able to fix this with more padding
on the seat back).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implications&quot;&gt;implications&lt;&#x2F;h2&gt;
&lt;p&gt;There are minimal procedural or research implications from the work — this
was instead primarily a fabrication project and learning experience for me.
Personally, the learnings are to simplify more aggressively, and intend + plan
to iterate more.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>wildcard</title>
        <published>2023-12-13T00:00:00+00:00</published>
        <updated>2023-12-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/wildcard/"/>
        <id>https://blog.npry.dev/class/htm/wildcard/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/wildcard/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;cad.onshape.com&#x2F;documents&#x2F;5dc9365a8ee70304f1b05067&#x2F;w&#x2F;76d905231d4bc180fafdc1a7&#x2F;e&#x2F;34fe706dffdfdb7ae7433d47&quot;&gt;onshape design&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;wildcard&#x2F;wildcard-step-files.tar.gz&quot;&gt;step files&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;wildcard&#x2F;wildcard-dxfs.tar.gz&quot;&gt;dxfs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;requirements&quot;&gt;requirements&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;design, cut, and assemble a sheet metal part
&lt;ul&gt;
&lt;li&gt;the design should include at least one hem or bend&lt;&#x2F;li&gt;
&lt;li&gt;and should require spot welding to assemble&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;summary&lt;&#x2F;h2&gt;
&lt;p&gt;I designed the front panel for my final project that will hold the two mfds.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;v1&quot;&gt;v1&lt;&#x2F;h2&gt;
&lt;p&gt;I made my design in OnShape and only exported a &lt;em&gt;face&lt;&#x2F;em&gt; as dxf to import into
the laser software the first time.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cutout_inlaser_v1.09da6905a5bcaf99.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Since I only exported the face, the design was missing all of the material for
the bends.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cutout_v1.6dbaf28f009dc475.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;v2&quot;&gt;v2&lt;&#x2F;h2&gt;
&lt;p&gt;Successfully unfolded the sheet metal design as dxf and exported.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cutout_inlaser_v2.ae618b105b3ae498.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Hemmed, bent, and spot-welded together:&lt;&#x2F;p&gt;
&lt;p&gt;
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cutout_spot_welded_bottom.c4056e7c1d913c5c.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;


&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cutout_spot_welded_top.4e82d085efc17116.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;With the mfd outline in place:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cutout_with_panel.3cc68c26fb8372d5.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;welding&quot;&gt;welding&lt;&#x2F;h2&gt;
&lt;p&gt;I spent most of a day self-teaching welding on both mig and tig.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mig&quot;&gt;mig&lt;&#x2F;h3&gt;
&lt;p&gt;Some miscellaneous experiments out of scrap:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;misc_experiments_1.0994b94a9d31a3ff.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;misc_experiments_2.0d883424e14f71eb.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Real attempts at nicer joints:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;butt_joint.f2fb73435042f1a9.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;round_tube.d010a54c3d669a4d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;scraper&quot;&gt;scraper&lt;&#x2F;h3&gt;
&lt;p&gt;I tried to make a scraper to clean the welding spatter off of the table out of
scrap:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;scraper.ce5865c781de1e37.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;scraper_2.363f9b01ad17c645.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;But the spatter is very hard, and my scraper was mild steel, so the edge mostly
just deformed:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;scraper_edge.a72a4564ee32fad8.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;tig&quot;&gt;tig&lt;&#x2F;h3&gt;
&lt;p&gt;There was some warp in my panel and I wanted to take it out by welding
stiffeners to it. I figured I&#x27;d need to use tig to do this -- I practiced
on scrap 22ga:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;tig_experiments.c2a5a84f3978e83f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;tig_experiments_p2.9fcb129493bd83fc.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>machine week</title>
        <published>2023-12-06T00:00:00+00:00</published>
        <updated>2023-12-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/mechanical/"/>
        <id>https://blog.npry.dev/class/htm/mechanical/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/mechanical/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;mechanical&#x2F;bridge.tar.gz&quot;&gt;serial-nats bridge&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;mechanical&#x2F;COBSNATS.ts&quot;&gt;modular things nats client&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;mechanical&#x2F;install.sh&quot;&gt;raspi setup script&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;fab.cba.mit.edu&#x2F;classes&#x2F;863.23&#x2F;CBA&#x2F;machine&#x2F;&quot;&gt;cba section site&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gitlab.cba.mit.edu&#x2F;classes&#x2F;863.23&#x2F;CBA&#x2F;machine&quot;&gt;section repo&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We built a machine for producing video clips of a subject simultaneously from
multiple angles, and compositing these clips into a single video (set to
music).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;remote-modular-things&quot;&gt;remote modular things&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;system diagram (2 concepts)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;system_diagram.791c041ea8aa2261.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I wrote a bridge that enables you to centrally control modular things plugged
into many different devices from a single instance of the web interface.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;bridge_demo.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The bridge is a python script that you run on as many devices as you want. It
talks to a message broker (&lt;a href=&quot;https:&#x2F;&#x2F;nats.io&quot;&gt;NATS&lt;&#x2F;a&gt;). When you plug modular
things into a device with the bridge running, the bridge discovers the serial
connection, announces it on the broker, subscribes to a &lt;code&gt;write&lt;&#x2F;code&gt; topic for
the thing, and publishes any data sent by the thing to a &lt;code&gt;read&lt;&#x2F;code&gt; topic.&lt;&#x2F;p&gt;
&lt;p&gt;I adapted a version of the WebSerial connector in the modular-things frontend
to connect to the message broker instead of WebSerial and automatically
discover devices. You can then use the frontend as normal.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, we&#x27;re not using this bridge in the live system because I ran out
of time to debug some issues (discussed below).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-this-approach&quot;&gt;why this approach&lt;&#x2F;h3&gt;
&lt;p&gt;The point of this was to get rid of some wires. Currently, all of the modular
things need to be plugged into the single computer running the frontend because
they have to talk over webserial. This is annoying, and we have raspis on each
of the systems anyway to talk to the cameras, so I wanted to just move the
usb cables onto the raspis instead.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;socat&quot;&gt;&lt;code&gt;socat&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Originally, I wanted to use &lt;code&gt;socat&lt;&#x2F;code&gt; as a point-to-point bridge over TCP.
Something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; remote (with modular things plugged in)&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; socat&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;d&lt;&#x2F;span&gt; &#x2F;dev&#x2F;ttyACM0,raw,echo=0 TCP-LISTEN:0.0.0.0:1234&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; on host running modular things frontend&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; socat&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;d&lt;&#x2F;span&gt; TCP:remote:1234 PTY,link=&#x2F;dev&#x2F;ttyV1,raw,crnl&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I was hoping that Chrome would connect to &lt;code&gt;&#x2F;dev&#x2F;ttyV1&lt;&#x2F;code&gt; on the second host, but
it seems that the webserial implementation will &lt;em&gt;only&lt;&#x2F;em&gt; connect to devices that
the host kernel identifies as having serial drivers, so this doesn&#x27;t work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;issues&quot;&gt;issues&lt;&#x2F;h3&gt;
&lt;p&gt;I got the bridge implementation working with a single servo board initially, only
really testing the discovery mechanism by plugging and unplugging the thing, and
verifying that it showed up and disappeared from the frontend when I did that,
without throwing errors in js or python. Discovery requires bidirectional
packet transfer between the thing and the frontend, so I figured this would be
a good place to start.&lt;&#x2F;p&gt;
&lt;p&gt;This worked fine, but when I added more serial ports, I ran into problems.
Specifically, the python bridge started throwing exceptions when more than one
serial port was connected in quick succession (e.g. because a USB hub with
with multiple things was plugged in). I was pretty sure I had written
the bridge in a way that precluded race conditions (the obvious diagnosis for
this symptom), but I investigated this and a few other plausible causes.&lt;&#x2F;p&gt;
&lt;p&gt;Retrying the serial connection if it fails is eventually what fixed the
problem. I figured there was a deeper issue with my code (not releasing an
old port properly was the thread I was chasing for a long time), but based on
what I saw, I&#x27;m guessing that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The Linux usb serial driver creates the device node for the port immediately
when it sees a cdc-acm device on the bus&lt;&#x2F;li&gt;
&lt;li&gt;The dev node is created in an &#x27;unready&#x27; state, causing the exceptions I was
seeing in the Python code&lt;&#x2F;li&gt;
&lt;li&gt;There&#x27;s another configuration step in the driver that occurs after bus
discovery, which makes the dev node ready to act as a serial port. This
configuration step has some latency and happens serially, port-by-port.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This would explain the behavior and why retries resolve the issue -- a single
device won&#x27;t cause the problem because there&#x27;s very little latency between the
appearance of the device on the bus and the second configuration step, where
the dev node is &quot;ready&quot;. A bunch of devices at once lead to several of them
being unready while devices ahead of them in the queue are configured.&lt;&#x2F;p&gt;
&lt;p&gt;All inference made to fit this set of symptoms, so I don&#x27;t know for sure if
it&#x27;s right, but the fact that connection retry works makes me pretty confident
this actually isn&#x27;t a bug in my code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;24v-interface-boards&quot;&gt;24v interface boards&lt;&#x2F;h2&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;24v_alan.5a220558677fc3c2.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;We wanted the linear axes to move faster than the modular things boards could
do with their onboard power supplies. There&#x27;s an existing design for a 24v
power board that would give us this extra speed -- I soldered connectors onto
these boards.&lt;&#x2F;p&gt;
&lt;p&gt;
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;24v_disasm.9e18c3fc8f5fe19e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;


&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;24v_soldered.ee261ce41b19bf7e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;


&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;24vx4.917a0c36aae09397.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Spacers for interposing the 24v boards into the stackup:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;24v_spacer.20a8172c5cc472a8.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Alan 3d printed these spacers and I cleaned them up. This is approximately how
they looked stacked up with the modular things boards, though this image has a
different spacer part in it:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;24v_stackup.16f89e3a2fcf194a.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;raspi-setup&quot;&gt;raspi setup&lt;&#x2F;h2&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;flashing_raspis.9d0443dd00f77c52.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I helped configure the final raspis. Lancelot reflashed them near the end, and
I:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;helped him set them up with static IPs&lt;&#x2F;li&gt;
&lt;li&gt;set up my laptop as an optional router with NAT to its wifi network
&lt;ul&gt;
&lt;li&gt;this internet access wasn&#x27;t required for the final working configuration,
but was used for installing dependencies&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;wrote &lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;mechanical&#x2F;install&quot;&gt;a simple script&lt;&#x2F;a&gt; to install the basic dependencies&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;static-ips&quot;&gt;static ips&lt;&#x2F;h3&gt;
&lt;p&gt;Surprisingly, the static IP configuration had unanticipated problems. I
normally only need a static IP on a temporary basis, so I typically go with
something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ip link set dev ethz up&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ip a add xxx.xxx.xxx.xxx&#x2F;yy dev ethz&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We did this manually to be able to reach them over ssh, then Lancelot made this
a systemd unit so they&#x27;d have IPs on reboot, but it unfortunately didn&#x27;t work
properly -- two of the three raspis would lose their configuration
spontaneously. Most likely the problem was some combination of not having
disabled NetworkManager and that if the link ever went down (cable momentarily
unplugged), the settings would be lost.&lt;&#x2F;p&gt;
&lt;p&gt;So instead, since NetworkManager was running anyway, we used it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nmcli con mod ethz &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;    ipv4.addresses xxx.xxx.xxx.xxx&#x2F;yy &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;    ipv4.gateway www.www.www.www &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;    ipv4.dns 1.1.1.1 &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;    ipv4.method manual&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>apps and ui</title>
        <published>2023-11-29T00:00:00+00:00</published>
        <updated>2023-11-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/apps-ui/"/>
        <id>https://blog.npry.dev/class/htm/apps-ui/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/apps-ui/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;apps-ui&#x2F;main.py&quot;&gt;ui script&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;ui.884e7f57ac21a455.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I wrote this one using Python&#x27;s tkinter bindings. It&#x27;s a UI for my
&lt;a href=&quot;..&#x2F;input-devices&#x2F;&quot;&gt;previous&lt;&#x2F;a&gt; &lt;a href=&quot;..&#x2F;output-devices&#x2F;&quot;&gt;weeks&#x27;&lt;&#x2F;a&gt; Mifare Classic 1K
card cloner. Not doing anything special -- just I&#x2F;O over the text serial port
with regex &#x2F; string matching to determine what the board is doing, and direct
serial port writes in response to button clicks.&lt;&#x2F;p&gt;
&lt;p&gt;The button functionality mirrors what I describe in the &lt;a href=&quot;..&#x2F;output-devices&#x2F;&quot;&gt;output
devices&lt;&#x2F;a&gt; section re: modes.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;ui.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 200px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;(NB: for logistical filming reasons, these two videos aren&#x27;t simultaneous. Also
note the &quot;write&quot; button not causing a mode change with an empty key is an
intentional part of the embedded functionality.)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;physical_demo.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Another note: it was easier for me at the time to set this up on my breadboard
version — it works on the milled board just as well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tkinter&quot;&gt;tkinter&lt;&#x2F;h2&gt;
&lt;p&gt;I picked tkinter because it&#x27;s fast and extremely easy to hack something in --
far nicer than web (which requires a whole browser), and built-in to most headed
Python distributions.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s very old-fashioned -- everything is mutable state, there&#x27;s no asynchrony,
you drive the event loop manually, and there&#x27;s no markup language to make
design easier, but I really haven&#x27;t found anything better for rapidly building
small, dependency-free&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; cross-platform UI with a code size footprint of
kilobytes&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Up to requiring a tkinter-enabled Python install — obviously it has
this runtime dep, but no third-party packages that a user would have to install.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Again, discounting the size of the supporting Python distribution, but
even so, this is much much more minimal and resource-efficient than a browser.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>networking and communications</title>
        <published>2023-11-22T00:00:00+00:00</published>
        <updated>2023-11-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/networking-comms/"/>
        <id>https://blog.npry.dev/class/htm/networking-comms/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/networking-comms/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;networking-comms&#x2F;networking-design-files.tar.gz&quot;&gt;design files&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;networking-comms&#x2F;networking-elixir.tar.gz&quot;&gt;elixir projects&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;mcu som&lt;&#x2F;em&gt;: esp32c3 xiao&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;erlang vm&lt;&#x2F;em&gt;: &lt;a href=&quot;https:&#x2F;&#x2F;www.atomvm.net&#x2F;&quot;&gt;atomvm&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This week is an extension of the &lt;a href=&quot;..&#x2F;embedded&#x2F;&quot;&gt;first embedded assignment&lt;&#x2F;a&gt;, in
which I functionally completed the networking part of this week&#x27;s tasks. This
week, I designed and built a board to support the Erlang version of the firmware
I wrote (which ran on a breadboard previously), and extended the firmware to be
able to show new networking functionality for this week.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Erlang node running&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;running.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Boot sequence&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;bootseq.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Lights in order:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Booted&lt;&#x2F;li&gt;
&lt;li&gt;Wifi connected&lt;&#x2F;li&gt;
&lt;li&gt;IP acquired&lt;&#x2F;li&gt;
&lt;li&gt;NTP sync&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The blinking LED runs on an infinite loop independently.&lt;&#x2F;p&gt;
&lt;p&gt;The &quot;booted&quot; light can be controlled over UDP using the Erlang client I wrote
for the earlier assignment.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;firmware-improvements&quot;&gt;firmware improvements&lt;&#x2F;h2&gt;
&lt;p&gt;Beyond designing and milling a board, I added the following improvements to
the firmware:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Nonvolatile storage of a well-known remote ip. The device sends a UDP packet
to this address with its own IP every time it&#x27;s assigned one -- the idea is
that at some point you store your (hopefully somewhat stable IP) on the
device, and it notifies you so you can easily find it without needing to be
connected to it.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;A ping-pong mode -- if you send the node the atom &lt;code&gt;:ping&lt;&#x2F;code&gt;, it responds
&lt;code&gt;:pong&lt;&#x2F;code&gt;. Timing with both my laptop and the node on the same WiFi network
is bimodal -- half of the packets roundtrip in about 30ms, and the other
half take 225ms or so. &lt;strong&gt;This is the fresh networking functionality that I intended to on its own cover this week!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>output devices</title>
        <published>2023-11-15T00:00:00+00:00</published>
        <updated>2023-11-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/output-devices/"/>
        <id>https://blog.npry.dev/class/htm/output-devices/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/output-devices/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;output-devices&#x2F;cardcloner.ino&quot;&gt;arduino sketch (breadboard pins)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;output-devices&#x2F;cardcloner_milled.ino&quot;&gt;arduino sketch (milled board pins)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;..&#x2F;input-devices&#x2F;cardreader-design.tar.gz&quot;&gt;board design&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;mcu som: rp2040 xiao&lt;&#x2F;p&gt;
&lt;p&gt;Reader Module: &lt;a href=&quot;https:&#x2F;&#x2F;amazon.com&#x2F;dp&#x2F;B07VLDSYRW&quot;&gt;HiLetgo RFID Kit&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Test Cards: &lt;a href=&quot;https:&#x2F;&#x2F;amazon.com&#x2F;dp&#x2F;B0895Y5LGT&quot;&gt;LEXI UID PVC Blanks&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cardreader_on.d2ea7e567777d6e6.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cardreader_board.f2d04c021c6308dd.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This week, I upgraded the reader I made &lt;a href=&quot;..&#x2F;input-devices&#x2F;&quot;&gt;last week&lt;&#x2F;a&gt;. It now
supports cloning the UID of a Mifare Classic 1K card to a new card, wiping the card,
and unlocking certain cards for writing. The cloner mode can be changed with the
buttons, and the current mode is displayed on the colored LED, as well as over
serial.&lt;&#x2F;p&gt;
&lt;p&gt;This is an output device in the sense that we&#x27;re using the reader in a write mode,
or from a human interface perspective in the sense that the LED indicates the mode.&lt;&#x2F;p&gt;
&lt;p&gt;Colors:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;light blue: reader, no key or default key loaded&lt;&#x2F;li&gt;
&lt;li&gt;dark blue: reader, non-default key loaded&lt;&#x2F;li&gt;
&lt;li&gt;yellow: unlock mode&lt;&#x2F;li&gt;
&lt;li&gt;pink: writer mode&lt;&#x2F;li&gt;
&lt;li&gt;orange: write default key&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Button input scheme (1 to 3, top to bottom respectively):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1: read mode&lt;&#x2F;li&gt;
&lt;li&gt;2: unlock mode&lt;&#x2F;li&gt;
&lt;li&gt;3: write mode (fails if no key has been read)&lt;&#x2F;li&gt;
&lt;li&gt;1 + 2: clear stored key&lt;&#x2F;li&gt;
&lt;li&gt;2 + 3: write default key&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Milled board (read):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;..&#x2F;input-devices&#x2F;cardreader_board.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Milled board (write):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;cardcloner_board_write.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Milled board (unlock):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;cardcloner_board_unbrick.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Going through all the operations on the breadboard version:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;cardreader_demo.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;serial-output-event-trace&quot;&gt;serial output &#x2F; event trace&lt;&#x2F;h2&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;read card (sak: 0x08), uid: 0925263e
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[int] mode: write
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;overwriting card: 0925263e
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;wrote card
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;new serial: 0925263e
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[int] mode: unbrick
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;unbricked uid sector
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[int] mode: write
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[int] entered write-zero mode
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[int] mode: write
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;overwriting card: 01020304
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;wrote card
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;new serial: a5a5a5a5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[int] mode: write
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[int] erased key
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[int] mode: read
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;summary&quot;&gt;summary&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Read a card, storing the UID.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;a. Press the write button, entering write mode&lt;&#x2F;p&gt;
&lt;p&gt;b. Present the same card, reading the serial&lt;&#x2F;p&gt;
&lt;p&gt;c. Overwrite it with the same serial (no-op, for demo)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;a. Enter unbrick (unlock) mode&lt;&#x2F;p&gt;
&lt;p&gt;b. Present card, unbrick ok (no-op)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;a. Press write and unbrick buttons (write-zero mode)&lt;&#x2F;p&gt;
&lt;p&gt;b. Present card, overwrite UID with a5a5a5a5 (dummy sequence)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Press read button, returning to read mode&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;code&gt;[int]&lt;&#x2F;code&gt; lines are interrupt-triggered button presses.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;security-notes&quot;&gt;security notes&lt;&#x2F;h2&gt;
&lt;p&gt;In general, for &lt;em&gt;secured&lt;&#x2F;em&gt; card systems (those which store and use cryptographic
material onboard the cards), a capability which Mifare Classic 1K supports,
producing a card with a duplicate UID does not pose a security risk. Cards with
cloned UIDs have no capacity to authenticate the user without the key material.&lt;&#x2F;p&gt;
&lt;p&gt;That said, Mifare Classic 1K has been cracked -- it is possible to exfiltrate
key material and fully clone a card -- but this process takes time, as the card
must be attacked repeatedly, and my system does not attempt to do this.&lt;&#x2F;p&gt;
&lt;p&gt;If, however, an institution were to be so obtuse as to &lt;em&gt;only&lt;&#x2F;em&gt; use the world-readable
and trivially-writable UID as the sole source of authentication information, it
would be possible to use this device to functionally replicate user cards freely
and, for instance, share card access between potentially-unauthorized principals.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t know of an institution like that, though.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;board-design-notes&quot;&gt;board design notes&lt;&#x2F;h2&gt;
&lt;p&gt;I used 2x8 0.1&quot;-pitch SMD header sockets to accept both the card reader and the
MCU, in order to allow me to reuse them between board revisions, if required.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>input devices</title>
        <published>2023-11-08T00:00:00+00:00</published>
        <updated>2023-11-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/input-devices/"/>
        <id>https://blog.npry.dev/class/htm/input-devices/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/input-devices/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;input-devices&#x2F;cardreader.ino&quot;&gt;arduino sketch (breadboard pins)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;input-devices&#x2F;cardreader-design.tar.gz&quot;&gt;board design&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;mcu som: rp2040 xiao&lt;&#x2F;p&gt;
&lt;p&gt;Reader Module: &lt;a href=&quot;https:&#x2F;&#x2F;amazon.com&#x2F;dp&#x2F;B07VLDSYRW&quot;&gt;HiLetgo RFID Kit&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Test Cards: &lt;a href=&quot;https:&#x2F;&#x2F;amazon.com&#x2F;dp&#x2F;B0895Y5LGT&quot;&gt;LEXI UID PVC Blanks&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;First breadboard version:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cardreader_on.7ec3b3b884ef464b.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Milled board:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cardreader_board.3b6c1db944f73cc5.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This week, I made a reader for Mifare cards (of the type used by MIT) with a
COTS 13.56MHz card reader. The reader prints the UID of any card presented to it
over serial.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;cardreader_board.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Note that the LED changes color to a darker blue to indicate that it has
succeeded in reading a card.&lt;&#x2F;p&gt;
&lt;p&gt;My XIAO board runs a simple Arduino sketch communicating with the reader over
SPI, using the MFRC522v2 library.&lt;&#x2F;p&gt;
&lt;p&gt;Sample output when one of the test cards is presented:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;read card (sak: 0x08), uid: a5a5a5a5
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I have plans to add additional I&#x2F;O to the board, including supporting multiple
modes (such as writing cards), so I included buttons on the board that are wired
to unused pins.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cardreader_off.926e3f0319f3f3e5.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;There is an IRQ line on marked on the reader module. This is connected as well,
and I intend to use it to configure interrupt-driven card reads, though I didn&#x27;t
get to this this week. Notably, it seems to affect the function of the reader if
I let it float (detecting card presence when there isn&#x27;t one), though the
documentation suggests it should be an output from the reader IC. I pull it low
in the sketch and this appears to make everything work fine.&lt;&#x2F;p&gt;
&lt;p&gt;The RGB LED on the board blinks when it reads a card as feedback to the user, and
changes to a different shade of blue once it has read a valid card. It flashes red
if the read fails (card moving too quickly).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;milling&quot;&gt;milling&lt;&#x2F;h2&gt;
&lt;p&gt;I didn&#x27;t originally mill a board this week -- I came back to this later once I
had time to get the board milling process right. This and week was done with a
breadboard because development was much faster.&lt;&#x2F;p&gt;
&lt;p&gt;Please note: I did &lt;em&gt;design&lt;&#x2F;em&gt; a board for this week to fulfill this requirement --
the design files are available above.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>machining something big</title>
        <published>2023-11-01T00:00:00+00:00</published>
        <updated>2023-11-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/machining-something-big/"/>
        <id>https://blog.npry.dev/class/htm/machining-something-big/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/machining-something-big/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;machining-something-big&#x2F;something-big-design-files.tar.gz&quot;&gt;design files&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chair_complete.3f5e3f04805d9a7c.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;em&gt;cnc router&lt;&#x2F;em&gt;: ShopBot 5&#x27; x 10&#x27;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;cam&lt;&#x2F;em&gt;: vCarve Pro&lt;&#x2F;p&gt;
&lt;p&gt;In pursuit of my final project, I made a chair to calibrate sitting position
relative to my rudder pedals. I need several degrees of freedom (primarily
chair tilt and back tilt relative to seat base). I went through several design
iterations but ended up concerned about structural integrity for all of them,
so I just settled on a normal, but short chair that I could block up on the
front and the back.&lt;&#x2F;p&gt;
&lt;p&gt;The seat back I don&#x27;t anticipate to require too much iteration, so it&#x27;s
attached with screws and can be adjusted by unscrewing and reattaching.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cuts-complete&quot;&gt;cuts complete&lt;&#x2F;h2&gt;
&lt;p&gt;Here are the parts cut out on the ShopBot:&lt;&#x2F;p&gt;
&lt;p&gt;
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cuts_part1.fbb03b3b32278c38.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;


&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cuts_part2.6de4b27371b81f1b.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chip-out&quot;&gt;chip-out&lt;&#x2F;h2&gt;
&lt;p&gt;A huge chunk separated from the OSB aggregate during cutting:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chipout.3571e59b28775a94.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chipout_part.d82d3d7197584671.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I didn&#x27;t feel it affected structural integrity too much, so I didn&#x27;t recut the
part.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;autotabs&quot;&gt;autotabs&lt;&#x2F;h2&gt;
&lt;p&gt;I used autotabs in vCarve Pro, which made it easier to place my parts, but
several of the tabs ended up in annoying spots:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;autotabs.6b24a072cf67878d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;It was relatively easy to cut these out with the corner of the oscillating saw.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;complete&quot;&gt;complete&lt;&#x2F;h2&gt;
&lt;p&gt;The fitment ended up quite good -- most of the joints are quite tight. I used an
0.1mm offset on each of the joints.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chair_complete.3f5e3f04805d9a7c.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>machining, molding, and casting</title>
        <published>2023-10-25T00:00:00+00:00</published>
        <updated>2023-10-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/machining-casting/"/>
        <id>https://blog.npry.dev/class/htm/machining-casting/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/machining-casting/">&lt;p&gt;CNC: large-bed ShopBot&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;machining-casting&#x2F;machining_casting_design_files.tar.gz&quot;&gt;design files (tarball)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;complete_top.7bf96f4b5447c7ab.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I made a center scribe tool this week. It has a pair of pins with a hole at
their midpoint — you line it up on a part or piece of stock you want to
find center on and rotate it so the pins touch either side of the piece. Put a
pencil or scribe in the center and drag the whole assembly, and you&#x27;ll mark
center on the piece.&lt;&#x2F;p&gt;
&lt;p&gt;I did the assignment in two iterations to end up with a metal result that
couldn&#x27;t be produced with &amp;lt;= 3-axis machining. Steps:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CNCed wax positive&lt;&#x2F;li&gt;
&lt;li&gt;Cast two-part silicone mold&lt;&#x2F;li&gt;
&lt;li&gt;Cast plaster part&lt;&#x2F;li&gt;
&lt;li&gt;Cleaned up &#x2F; finished plaster part and drilled through-hole&lt;&#x2F;li&gt;
&lt;li&gt;Cast one-piece silicone cut mold around plaster part&lt;&#x2F;li&gt;
&lt;li&gt;Cast metal part in one-piece cut mold&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;milling&quot;&gt;milling&lt;&#x2F;h2&gt;
&lt;p&gt;The CAM software we trained on was ShopBot vCarve, using functionality to
cut a part in a half and CNC out each half. Initially, I tried to follow this
approach, using a baseplate with locating pins in it for each mold-half.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;partial_model.50b1c188c9d339e9.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Unfortunately, vCarve saw the whole item as the model and tried to route around
the border of the baseplate to separate it from the rest of the stock. I didn&#x27;t
want this — I just wanted the faceplate to sit in a pocket.&lt;&#x2F;p&gt;
&lt;p&gt;John and I worked on this and found that using my original assembly (from which
the plate models were derived) would work if we adjusted the vCarve settings.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;model.e7fdef1c8622e7df.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I used the large format ShopBot in the CBA shop to mill the design:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;milling.a26332fbeb7a80b9.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Partway through roughing, communications failed with the ShopBot:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;shopbot_error.e8506b9da2b70544.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;John and I wrote down the gcode line we were on and hoped we would be able to
resume the job, but the machine had lost its XY zero after restart. You can see
on the final result that it drove the endmill straight through the far wall after
we restarted:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;complete.0efff242059cb784.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;We rezeroed it in XY after that, and though that zero wasn&#x27;t perfect, the roughing
pass had left enough excess stock in most areas that the finishing cut was able to
recover the part well. The large pins had small bites taken out of them in one layer,
but this was okay for my purposes.&lt;&#x2F;p&gt;
&lt;p&gt;You can see that the ShopBot wasn&#x27;t able to cut the through-hole in the bottom part
above — I add that later manually.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;silicone&quot;&gt;silicone&lt;&#x2F;h2&gt;
&lt;p&gt;I cast a silicone mold from the wax positive:&lt;&#x2F;p&gt;
&lt;p&gt;
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;bottom.0d55f279e4286547.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;


&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;top.a2d622e12301ad81.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;In order to fill the mold, I made two of the handles into pour holes&#x2F;sprues:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cut_through.498f9738bd3031da.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;pour_spouts.d9e09ba1d2ebc5b5.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;To keep it together, I made a cardboard and tape holder with slight preload:&lt;&#x2F;p&gt;
&lt;p&gt;
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;mold_holder_top.8763e3cc29f8893a.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;


&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;mold_holder_high_side.07e8c21d3e474e19.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;h2 id=&quot;plaster&quot;&gt;plaster&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;attempt-1&quot;&gt;attempt 1&lt;&#x2F;h3&gt;
&lt;p&gt;Here is the mold filled with plaster:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;poured.34f561851e3f5502.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I weighted it down to try to minimize flash:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;weighted.c60f74130ff278fd.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The first pour had a huge bubble in it:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;bubble.e7f031c7398be769.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;And one of the bottom posts didn&#x27;t fill due to an air bubble:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;post_bubble.3a15829f839b866b.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;attempt-2&quot;&gt;attempt 2&lt;&#x2F;h3&gt;
&lt;p&gt;I repoured, this time directly filling the bottom posts before closing the mold.
I also left the mold on the vibratory plate for much longer and rotated it a
lot to try to ensure I got all the air out. I caught a small bubble on the top:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;clean_top_init.92e45bd80dc74942.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;And another few small ones on the bottom posts:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;clean_bottom_init.43a3b48d1fb4c474.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;But these were small enough not to bother me.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;touchups&quot;&gt;touchups&lt;&#x2F;h3&gt;
&lt;p&gt;I tried touching up both pours by filling the voids with additional plaster:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;retouched.29eb88129090d6be.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Clearly the first mold couldn&#x27;t be made functional (as the post was almost
entirely missing), but I wanted to see how well the large void on top would
fill and whether it would crack. I haven&#x27;t cleaned this up yet, but it seems
not to have cracked, somewhat to my surprise.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the nicer one after the touchups cured and I went over the whole piece
with some fine sandpaper:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;touched_up.4c0f8ab614844d06.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I then added the through-hole for the scribe with a dremel:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;hole_drilled.648d902b4d9b671c.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;one-piece-cut-mold&quot;&gt;one-piece cut mold&lt;&#x2F;h2&gt;
&lt;p&gt;I put the nicer plaster model on a cardboard base, then poured silicone around
it to produce a mold that captures the scribe-hole and all my retouching:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cut_mold_pour.89c4a065d313c111.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I used hot glue to attach the piece to the base, and I whittled a couple
of the actual hot glue sticks to make vents.&lt;&#x2F;p&gt;
&lt;p&gt;Cut it open to extract the positive:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cut_mold_open.8c2b38dafc139cf8.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The plaster survived but has little bits of silicone stuck in it everywhere:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;post_remold.06f30d0c277aa900.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Here&#x27;s the mold closed by hand with most of the parting lines vanishing:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cut_mold.aeab78c0e9748f7b.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Top-down view of the result (filled vent is obscuring the hole).&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;casting_fresh_top.7ff52e4484b7db82.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Side view:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;casting_fresh_side.a87b224115d143bd.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I cut off the bulk of the excess material with a hacksaw:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;cutoffs.852724e043192a3d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;And refinished the rest with a file in a pair of soft jaws:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;filing.a2f7af9ff17688f4.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Here&#x27;s the completed part:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;complete_top.7bf96f4b5447c7ab.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Unfortunately, the low-temperature alloy I cast with was softer than I
expected, and I squeezed one of the pins in the vice to file the top.
It deformed pretty badly:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;complete_bottom.f7bfa145fb49fb86.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>electronics production</title>
        <published>2023-10-18T00:00:00+00:00</published>
        <updated>2023-10-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/elec-production/"/>
        <id>https://blog.npry.dev/class/htm/elec-production/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/elec-production/">
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;board_complete.3d7d8f15be49f211.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;elec-production&#x2F;elec_production_design_files.tar.gz&quot;&gt;design files (tarball)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Recall that as part of my final project, I am making an I&#x2F;O board with
button-bearing daughterboards that will handle the buttons on an MFD:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;mfd.c40d6618c31a11af.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Daughterboard and I&#x2F;O master board designed last week:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;button_daughterboard.1204d6f7e57f0d3a.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;io_master.6256c938099e18b8.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I milled the I&#x2F;O master board this week in Reponsive Environments&#x27; PCB
router:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;pcb_router.ed5960ac7f9c0c86.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;partial-redesign&quot;&gt;partial redesign&lt;&#x2F;h2&gt;
&lt;p&gt;I redesigned the boards this week because I realized last week&#x27;s
was needlessly complicated — I wasn&#x27;t making use of the fact that the GPIOs
have pullups, which meant I routed power to each daughterboard and needed to
add resistors for current-limiting.&lt;&#x2F;p&gt;
&lt;p&gt;I removed that requirement, cutting out two wires per daughterboard connection
(I had rounded up to 8 wires using two grounds, since I didn&#x27;t want an odd
number of pins in my connector). More importantly, the lack of power going to
all connectors drastically simplified the single-layer routing topology
problem and allowed me to use larger traces (much nicer for PCB milling).&lt;&#x2F;p&gt;
&lt;p&gt;I also added SMD debounce capacitors (22μF — just what I could find around
ResEnv in quantity 25) to the I&#x2F;O master, as I&#x27;ve never implemented debouncing
in hardware before and wanted to try this. Unfortunately, these additional
footprints along with my desire to keep the design compact caused me to
&lt;em&gt;decrease&lt;&#x2F;em&gt; my trace width and spacing significantly. This would come back to
bite me later.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;debounce-verification&quot;&gt;debounce verification&lt;&#x2F;h3&gt;
&lt;p&gt;I built a prototype of the debounce circuit before I milled anything to verify
behavior:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;button_debounce.62f5bcd9dd2c3f42.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Here&#x27;s a plot of a button actuation at the measurement point on my scope, full
vertical range 0V - 3.3V, 10ms&#x2F;div:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;debounce_scope.401e24f120bc6738.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I tried a bunch and couldn&#x27;t produce a button press that was noticeably noisy.&lt;&#x2F;p&gt;
&lt;p&gt;Then I built the same circuit using the SMD caps I had on some protoboard — back:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;protoboard_debounce_back.9035907ab458c01e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;And front, with button:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;protoboard_debounce_front.6485cda97b2df734.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I saw similar performance with this protoboard version of the circuit,
validating the design.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aside-tantalum-caps&quot;&gt;aside: tantalum caps&lt;&#x2F;h3&gt;
&lt;p&gt;I believe the capacitors I found are tantalums. It&#x27;s hard to know for sure, as
they were in an unmarked reel-tape, but they do have a polarity marking.
Tantalums have the opposite polarity-marking convention as electrolytics, so
this makes deciding which way to orient them a dilemma.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Prima facie&lt;&#x2F;em&gt;, that they are in an SMT package suggests that the caps &lt;em&gt;are&lt;&#x2F;em&gt;
tantalums, as to my knowledge elecrolytic caps are not packaged for SMT this
way. However, I could be wrong, so I wanted to do some investiagion.&lt;&#x2F;p&gt;
&lt;p&gt;I used a multimeter to check the capacitance in both directions, hoping
something about their polarization would cause the reading to be obviously
different one way. This wasn&#x27;t the case — I got 22μF both ways.&lt;&#x2F;p&gt;
&lt;p&gt;I installed them in my test circuit under the assumption they were tantalums,
and nothing blew up, so that lends some credence. They&#x27;re marked 5V as well,
and my circuit is at 3.3V, so it&#x27;s not like they&#x27;re way under their rating.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand the resistor in this test circuit limits current to 2mA
maximum (at 3.3V), so let&#x27;s generously say the capacitor could convert 10mW to
heat under the worst conditions. This seems unlikely to generate enough
temperature differential to cause a catastrophic failure, supposing the caps
are of a different type.&lt;&#x2F;p&gt;
&lt;p&gt;So, altogether hard to say, though it seems circumstantially likely that they
are tantalums.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;milling&quot;&gt;milling&lt;&#x2F;h2&gt;
&lt;p&gt;I used FlatCAM as my CAM tool this week and Candle as my machine controller
(communicating to the router over USB serial).&lt;&#x2F;p&gt;
&lt;p&gt;I had a lot of trouble getting my boards to mill properly. Initially, I wasn&#x27;t
getting enough depth of cut — the first run didn&#x27;t make it through the
copper. A later run was well-enough calibrated (but still wrong) that it only
&lt;em&gt;burnished&lt;&#x2F;em&gt; the top surface of the copper without cutting.&lt;&#x2F;p&gt;
&lt;p&gt;I had difficulty debugging these problems because FlatCAM and Candle are both
new to me, so attribution of the behavior was difficult. I&#x27;d think I had solved
one problem, but it would surface another one, and I couldn&#x27;t tell e.g. if I
wasn&#x27;t cutting deep enough because I was zeroing the machine incorrectly (or
upsetting the zero, etc.) or because FlatCAM wasn&#x27;t setting a deep enough cut
depth in the first place.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually I understood what each tool wanted and got everything working,
including Candle&#x27;s heightmap feature:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;candle_heightmap.b3779aeffad09357.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Red areas are high, blue are low — for our PCB mill, the bed slopes down
to the right, so the zero is correct on the left, but drastically off on the
right.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;candle_heightmap_table.b6f193b7cc0f0b64.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This is the table of each probe point (in mm). Our depth of cut is only 0.15mm,
so we would expect to stop cutting entirely halfway across the bed. In
practice, this doesn&#x27;t actually happen, which (along with a tendency to mill
overly-wide paths with our v-bits) leads me to believe our zero process has
some bias. In any case, there is a lot of drop-off wrt. our depth-of-cut across
the bed, so this mesh bed-leveling process should be helpful.&lt;&#x2F;p&gt;
&lt;p&gt;Once I got to this point, I quickly realized my design wasn&#x27;t going to work. The
trace width and trace spacing reduction (both 0.25mm) I had made to accommodate
the debounce caps made the traces too narrow for our mill — they were
either very stringy (tending to get grabbed by the mill and ripped off) or
missing entirely.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;reredesign&quot;&gt;reredesign&lt;&#x2F;h2&gt;
&lt;p&gt;I redesigned again, this time omitting the debounce caps entirely and just
resolving to handle this in firmware. The I&#x2F;O master board is very simple now:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;new_io_master.439e040332892deb.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;It just forwards ground and 5 button IOs to a pin header connector. This is
at the very least nicer for my application than directly plugging the button IOs
into the Pico as we can share ground in groups of 5 IOs rather than 4.&lt;&#x2F;p&gt;
&lt;p&gt;NB: there is 1 extra button group of 5 IOs for auxiliary functions on the MFD
(day&#x2F;night, brightness encoder, contrast).&lt;&#x2F;p&gt;
&lt;p&gt;I increased the trace width to a full 1mm and minimum clearance to 0.5mm to
ensure we would mill cleanly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;milling-part-2&quot;&gt;milling, part 2&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;shifting&quot;&gt;shifting&lt;&#x2F;h3&gt;
&lt;p&gt;The last hurdle to clear was the board shifting during milling. I had seen this
several times, and am still not sure why, beyond potentially inconsistent
application of double-stick tape. I even tried my first attempt with halved
feedrate in an attempt to minimize tool force on the part, but it still shifted:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;shifting.bed8b90e975edab1.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;(This is on the back of my successful board — ignore the pins.)&lt;&#x2F;p&gt;
&lt;p&gt;The pads are all meant to be the same size as the six on the right, but you can
see that the last four get successively smaller as the double-stick tape started
to release and the board really started to move, at which point I killed the
job.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;success&quot;&gt;success&lt;&#x2F;h3&gt;
&lt;p&gt;The next attempt worked. I didn&#x27;t change anything beyond making sure I held firm
pressure on the board for 30-45 seconds to ensure it had the best bond with the
tape possible.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;drilling&quot;&gt;drilling&lt;&#x2F;h2&gt;
&lt;p&gt;Operationally, drilling proceeded smoothly. I could keep the same zero and
heightmap and just start it. I was conservative and started at 33% feedrate, and
slowly ramped to ensure nothing would break. It completed without shifting or
any other issues from the machine.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;drill-depth&quot;&gt;drill depth&lt;&#x2F;h3&gt;
&lt;p&gt;However, functionally, I did hit problems. First, I hadn&#x27;t set the drilling
depth deep enough (1.7mm, should have used 2mm), so the drill failed to pierce the
copper on the back side of my FR1. I hadn&#x27;t noticed this until I had pulled
the part off of the mill, or I would have just re-drilled it. Instead, I
finished the drilling manually with the same bit in a Dremel — the
existing holes made this easy.&lt;&#x2F;p&gt;
&lt;p&gt;The downside to doing this was that I  didn&#x27;t have a backer board, so I had
little copper tags attached to most of the holes. This was an issue because they
would almost certainly contact the header pins and short all of them to each other.
I removed them by hand using a drill bit as a deburring and slight countersink tool.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chamfer_bit.092e746269a72093.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This had the added benefit of relieving the copper at the edges of the holes, making
incidental contact between pins and the bottom plane of the board almost impossible.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chamfered_holes.4650341a9d14455e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;oversize-holes&quot;&gt;oversize holes&lt;&#x2F;h3&gt;
&lt;p&gt;The second problem was larger: the holes were oversize. Nominally, they
should have been 1mm, but the endmill I had measured 1.06mm. I didn&#x27;t think this
would be too much of an issue, as the thinnest annular width I had for any pads
was 0.35mm — the oversized endmill should have only affected this by
0.03mm per side, i.e. &amp;lt; 10%.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, I actually totally lost most of my small pads. If you recall, I
wasn&#x27;t able to mill traces at 0.25mm, so 0.03mm was 33% of the way from
our 0.35mm to a known non-working configuration — suddenly much more
significant. That&#x27;s not to say that a 1mm endmill would necessarily have done
the trick, but it&#x27;s likely we&#x27;re playing with the border of process stability,
so that small change was much more significant than I expected.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;soldering&quot;&gt;soldering&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;better known as: i sure wish i had some solder mask&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The result of this drilling mishap is that I spent several hours soldering and
continuity-testing the board. Perhaps a better term than soldering would be &quot;solder
sculpting&quot; — to get the solder to bridge only to the header pin I wanted
across a void where a pad should be and without solder mask (mostly: without
bridging to my ground pour), I had to develop some techniques.&lt;&#x2F;p&gt;
&lt;p&gt;It is first worth noting that I had all my trouble connecting the header pins,
which are the connectors for the daughterboards, and are through-hole. The
castellated edge on the Pico was very straightforward and took me all of two
minutes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;techniques&quot;&gt;techniques&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;General principles:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Solder &quot;likes&quot; heat — it tends to move towards the hot thing&lt;&#x2F;li&gt;
&lt;li&gt;Effective heat conduction increases nearly as a stepfunction when solder melts
— as a liquid, solder drastically increases its surface area with the
iron &lt;em&gt;and other solder&lt;&#x2F;em&gt;, meaning the iron is more heat-efficient and more
solder is exposed. This is a cascading effect.&lt;&#x2F;li&gt;
&lt;li&gt;Electrical nets are correlated to thermal nets&lt;&#x2F;li&gt;
&lt;li&gt;A hot board &#x2F; still-hot solder melts much more rapidly&lt;&#x2F;li&gt;
&lt;li&gt;In general, for &quot;atypical&quot; soldering techniques I&#x27;m discussing here: if
you don&#x27;t get the result you want, don&#x27;t keep trying — remove the
iron immediately, wait for the board to cool, and try again. It only gets
more difficult to be precise the hotter the board is.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&quot;Flicking&quot; solder: build up an oversized blob of solder on a trace, then lift
it with the point of the soldering iron. The bottom of the blob stays stuck to
the trace, and gravity keeps most of the mass there. You end up with a tail
of solder that you can lay on top of the pin you want to solder to and remove
the iron so as to elongate the tail. The joint with the pin (if any) will be
cold, so you will need to touch it up. It can help to build a blob, wait and let
it cool (not just to where it solidifies, but for 10 or 20 seconds so it loses
residual heat), and only then flick it — hotter solder is runnier, and we
want it to be viscous here.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&quot;Tapping&quot;: in most cases, the cascading increase in heat conduction due to
solder melting is helpful. However, if we want to touch up a joint, this effect
can lead to everything becoming one big contiguous puddle of solder very
quickly. With a well-timed application of the iron you can sometimes manage to
affect only part of a joint, or to quickly bridge two parts together without
wrecking the rest of the solder structure. Suppose we&#x27;ve &quot;flicked&quot; a tail near a
pin  (but not touching). We can connect the tail and the pin by flicking a tail
from the pin and tapping to weld them together. This works best if there is a
natural heat brake — a piece of (non-solder) metal in the conduction pathway
can stall other parts of the solder body from melting and give you some time to
work locally.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Preheating: for both flicking and tapping, if you can selectively preheat the part
you won&#x27;t be acting on, it makes it much easier to produce a solid joint — it
will tend to attract solder.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&quot;Towering&quot;: it&#x27;s possible to build a solder tower by tapping successive blobs
on top of each other. This is useful if you can establish a known-non-shorted
base blob on a trace and then tower up (usually once) to flick to a pin, because
it means you need much less of a large blob.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&quot;Pin blobbing&quot;: I discovered over time that this was the most consistent
approach for most pins. Rather than trying to flick from a trace, build up a
blob on a pin, ideally let it cool &lt;em&gt;somewhat&lt;&#x2F;em&gt;, and flick to the trace. Traces
are usually packed more closely to other traces and the ground plane than pins,
which have breathing room for the pad, so building a blob on the pin is
preferable. Flicking quickly and at the right timing after placing the blob
makes this work — a blob with some heat will tend to pull solder towards
it, and if you make the flick fast (i.e. cold), you will minimize risk of
bridging to an unintended net. Again, a preheated target trace will tend to
improve the chances of a nice joint without needing to touch up.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;ground-connections&quot;&gt;ground connections&lt;&#x2F;h3&gt;
&lt;p&gt;The ground connections were the absolute worst to solder. They have thermal relief
intentionally and a copper pathway for solder to spill to the ground plane, so it&#x27;s
impossible to keep a solder blob within the pad. I needed to tower for these, for
the most part. They also need to be done first, because the quantity of solder you
need to make these connections means that they will frequently bridge to other
already-complete pin connections and melt them into a big blob.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;connectivity&quot;&gt;connectivity&lt;&#x2F;h3&gt;
&lt;p&gt;I verified my joints with a multimeter and microscope. To my knowledge,
everything is electrically connected properly, except one GPIO that is shorted
to ground. I believe that issue must be underneath the Pico, as I&#x27;ve scoured
all along the visible parts of it and can&#x27;t find anything wrong.&lt;&#x2F;p&gt;
&lt;p&gt;I specifically checked every connection against bridging to ground and the
board&#x27;s nominally floating reverse plane. I didn&#x27;t do a pairwise pin-pin check
for shorts, and I haven&#x27;t checked against power, either. Each assigned GPIO on
the Pico &lt;em&gt;does&lt;&#x2F;em&gt; have continuity to its corresponding pin on the headers.&lt;&#x2F;p&gt;
&lt;p&gt;There is only one GPIO that is shorted to the reverse side&#x27;s copper plane, so
other than being a big antenna, it should work properly. The reverse plane is
not shorted to ground.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, there are 6 test points on the reverse of the Pico that I
didn&#x27;t account for in my design — I anticipate they are shorted together
and to ground. I haven&#x27;t checked the schematic for what they connect to, but I
would expect that it breaks the board.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;programming&quot;&gt;programming&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;NB: To the extent this matters for the grade, I did successfully program a nearly-equivalent board for my &lt;a href=&quot;..&#x2F;final-tracking&#x2F;&quot;&gt;final project&lt;&#x2F;a&gt; with almost exactly this firmware.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Unsurprisingly, given that I think the board wouldn&#x27;t power on, I didn&#x27;t program
the board for this week. It&#x27;s very basic firmware for what I need — could
just be a polling loop:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c++&quot; class=&quot;language-c++ z-code&quot;&gt;&lt;code class=&quot;language-c++&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; This firmware prototype intended for use with Arduino framework.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c++&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c++&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c++&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;Joystick.h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c++&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;Joystick_ &lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-c++&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c++&quot;&gt;joystick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-c++&quot;&gt;constexpr&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-stdint z-c&quot;&gt;uint8_t&lt;&#x2F;span&gt; N_BUTTON &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c++&quot;&gt;25&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-c++&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-c++&quot;&gt;static&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-stdint z-c&quot;&gt;uint8_t&lt;&#x2F;span&gt; PIN_MAP&lt;span class=&quot;z-meta z-brackets z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-c++&quot;&gt;[&lt;&#x2F;span&gt;N_BUTTON&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-c++&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c++&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; elided
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c++&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;void&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-c++&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c++&quot;&gt;setup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c++&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c++&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;auto&lt;&#x2F;span&gt; pin &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; PIN_MAP&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-variable z-function z-c++&quot;&gt;pinMode&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;pin&lt;span class=&quot;z-punctuation z-separator z-c++&quot;&gt;,&lt;&#x2F;span&gt; INPUT_PULLUP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;    joystick&lt;span class=&quot;z-punctuation z-accessor z-dot z-c++&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method-call z-c++&quot;&gt;&lt;span class=&quot;z-variable z-function z-member z-c++&quot;&gt;begin&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method-call z-c++&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c++&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;void&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-c++&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c++&quot;&gt;loop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c++&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c++&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;auto&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c++&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; N_BUTTON&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt; i&lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c++&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;        &lt;span class=&quot;z-storage z-type z-c&quot;&gt;auto&lt;&#x2F;span&gt; pin &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; PIN_MAP&lt;span class=&quot;z-meta z-brackets z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-c++&quot;&gt;[&lt;&#x2F;span&gt;i&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-c++&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;        &lt;span class=&quot;z-storage z-type z-c&quot;&gt;auto&lt;&#x2F;span&gt; state &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-variable z-function z-c++&quot;&gt;digitalRead&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;pin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;        joystick&lt;span class=&quot;z-punctuation z-accessor z-dot z-c++&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method-call z-c++&quot;&gt;&lt;span class=&quot;z-variable z-function z-member z-c++&quot;&gt;setButton&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;i&lt;span class=&quot;z-punctuation z-separator z-c++&quot;&gt;,&lt;&#x2F;span&gt; state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-c++&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c++&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ideally I&#x27;d make it work with interrupts, but this would be fine.&lt;&#x2F;p&gt;
&lt;p&gt;As I said, I would have tested this, but I&#x27;m pretty sure the board I have would
die if I plugged it into power, and I&#x27;m out of time for this week to debug it
or produce another.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;improvements&quot;&gt;improvements&lt;&#x2F;h2&gt;
&lt;p&gt;The easiest and most significant improvement I think would have been not using
through hole parts. I thought this would be interesting, but it really didn&#x27;t
work. Surface-mount connectors and I could have been done with the soldering in
less than 15 minutes, and I wouldn&#x27;t have needed to drill at all (not that this
took that long).&lt;&#x2F;p&gt;
&lt;p&gt;The better project this week would have been the daughterboards, as these are
simple and lend themselves much more readily to exploring milling a board, but
they&#x27;re larger than the capacity of resenv&#x27;s PCB mill, so I would have needed
to use the CBA one. Unfortunately, there were multiple people lined up to use it
every time I stopped by, so I couldn&#x27;t do it this week.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>electronics design</title>
        <published>2023-10-11T00:00:00+00:00</published>
        <updated>2023-10-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/elec-design/"/>
        <id>https://blog.npry.dev/class/htm/elec-design/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/elec-design/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;elec-design&#x2F;elec_design_files.tar.gz&quot;&gt;design files&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I used KiCad to design a pair of boards for my &lt;a href=&quot;..&#x2F;final-tracking&quot;&gt;final
project&lt;&#x2F;a&gt;. These will be button I&#x2F;O boards for the MFDs:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;mfd.6bd146b127bd488f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;daughterboards&quot;&gt;daughterboards&lt;&#x2F;h2&gt;
&lt;p&gt;First I designed 4 daughterboards, each of which handles one side of the MFD (5
buttons).&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;button_daughterboard.f4920673bfb58d58.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Each button is low-passed with a 1uF capacitor and a 10k resistor for debounce.
In theory, this should lead to rolloff starting at around 15Hz.&lt;&#x2F;p&gt;
&lt;p&gt;These boards will mount on the backside of the MFD bezel with screws. The hole
pattern is TBD based on the final MFD design.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;i-o-master&quot;&gt;i&#x2F;o master&lt;&#x2F;h2&gt;
&lt;p&gt;I designed the master board based on a Raspberry Pi Pico as a SoM:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;io_master.c52970f35087ab3f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;It interfaces with the daughterboards using 8-pin JST connectors, providing
3.3v, 2x ground, and 5x button outputs.&lt;&#x2F;p&gt;
&lt;p&gt;The Pico is soldered to the board using the castellated edge, though I&#x27;m
considering redoing the layout with a pair of header sockets to make it
swappable.&lt;&#x2F;p&gt;
&lt;p&gt;I chose the Raspberry Pi Pico for its high available GPIO count (26 available
pins), meaning each MFD can be serviced by one Pico.&lt;&#x2F;p&gt;
&lt;p&gt;I intend to have this board communicate with the host computer using the USB
port on the Pico.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>3d print</title>
        <published>2023-10-04T00:00:00+00:00</published>
        <updated>2023-10-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/3dprint/"/>
        <id>https://blog.npry.dev/class/htm/3dprint/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/3dprint/">&lt;p&gt;I designed and printed a captive pair of diagonal racks as a fidget toy.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;3dprint&#x2F;rack_design_files.tgz&quot;&gt;design files (tarball)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I used my own 3d printers for this week. I both wanted to try an SLA print here
(CBA shop training hasn&#x27;t covered this yet), and be able to take my time&#x2F;not
worry about blocking other people&#x27;s prints.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;finished_sla.797ba0db5a94395c.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The cage and each rack are separate parts, but the design has them printed in
place. The cage slides along both racks simultaneously, and each rack engages
with and slides along the teeth of the other.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video src=&#x27;rack_anim.webm&#x27; type=&quot;video&#x2F;webm&quot; loop muted autoplay style=&quot;width: 600px&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The design couldn&#x27;t be manufactured subtractively because the racks are captive
in the cage, and the cage is one piece. (Probably you could do this with very
careful application of wire EDM, but this design at least couldn&#x27;t be
&lt;em&gt;machined&lt;&#x2F;em&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Obviously, the difficult part of this is getting the print-in-place to work
without bridging the parts together. So far, I haven&#x27;t succeeded.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;attempt-1-sla&quot;&gt;attempt 1: sla&lt;&#x2F;h3&gt;
&lt;p&gt;The first attempt was on my Anycubic Photon S with a generic SLA resin I
bought on Amazon.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;anycubic_table.d1641b85c4d9dea2.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I printed the model at a 45 degree angle with the rack teeth oriented
vertically. I was hoping this would eliminate any directional bias &#x2F; sag due to
weight and keep the teeth separate.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;sla_slicer.873f13e185bdb184.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I designed the model with an 0.5mm gap between all the moving elements in order
to reduce the chances of unintended bridges between parts. I verified that this
gap was correctly sliced into the model:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;sla_layer_with_separation.60241bbf5d5e7257.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The above image is the core of the mechanism: the cage (outer green ring)
containing both racks, which are engaged with each other in this layer. The
notable thing is that all the parts are separated by several black pixels,
meaning that there should be free space between them.&lt;&#x2F;p&gt;
&lt;p&gt;In principle, I&#x27;m relying on the rigidity of the printed structure to maintain
the gaps in the model, at least sufficiently that the parts aren&#x27;t bridged
together.  Unfortunately, pre- or partially-cured resin is somewhat flexible,
and a structure that is intended to be three separate parts has almost no
rigidity.&lt;&#x2F;p&gt;
&lt;p&gt;Bow in one of the racks:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;sla_bow.89517be489ad448c.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The model can also be shifted by the contact with the tank membrane as it is
lowered back against the screen.&lt;&#x2F;p&gt;
&lt;p&gt;The printed structure bridged in many places. On this side, the cage bridged
directly to the bottom plane of the rack:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;sla_welded_cage_top.bc03ba44f32e9f1d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Note the top seam is too tight &#x2F; there is no gap, where there should be 0.5mm.&lt;&#x2F;p&gt;
&lt;p&gt;In this image, we&#x27;re showing a healthy gap between the side of the cage
and the rack, suggesting that the parts may have been free and independent
initially, before they eventually bridged:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;sla_gap.c9df08d22bbf0287.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Rack teeth bridged together:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;sla_welded_teeth.b6a3880d364c322d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I was not surprised that there was bridging, but I was hopeful that it would be
intermittent enough that I could break the bridges and get the mechanism to
move.  I tried flexing the part and pushing each rack both along its axis and
along the axis of its teeth, but I wasn&#x27;t able to break it loose. I&#x27;m fairly
confident, however, that both racks are fully or mostly bridged along their back
plane onto the cage, meaning it&#x27;d be unlikely I could ever get this apart
without very involved surgery.&lt;&#x2F;p&gt;
&lt;p&gt;If I were to do this again, I would pre-bridge all of the parts together in a
way that fixed and rigidified their intended relationships in the interfacing
region. I would design this bridging to be easy to remove and clean up after the
fact.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;attempt-2-fdm&quot;&gt;attempt 2: fdm&lt;&#x2F;h3&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;ender3_midprint.d9d57b862594ca92.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I didn&#x27;t have time to redesign and reprint the part before class, but I figured
I could try the same print in FDM, so I printed the same design (0.5mm
separation) on my Ender 3 in PLA+.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;fdm_sliced.74bf002d534d3fd5.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I chose to print with the cage flat against the bed. This required significant manual support
painting, as I exported the assembly (both racks + cage) as a single STL object
in order to maintain alignment -- PrusaSlicer had no way of knowing that I
didn&#x27;t want parts to rest or sag onto each other.&lt;&#x2F;p&gt;
&lt;p&gt;On reflection, I should probably have printed this standing up, as I think this
would have minimized surface area for tolerance-critical supports, though that
trades off against a less stable &#x2F; higher aspect-ratio print.&lt;&#x2F;p&gt;
&lt;p&gt;Painted supports on either side of the bottom rack, bridging over the bottom of
the cage (cutaway):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;fdm_slice_bridge.bc60c926bb9b80f1.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I chose to paint support material under the teeth within the cage, which couldn&#x27;t
be supported from the bed. I reasoned that having some low-density material here
that could be broken away would be better than potential hard bridges:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;fdm_slice_cutaway_supports.8663db334d6187e1.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Airgap between teeth:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;fdm_slice_airgap.de52ac4a6c212c9e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Unfortunately, the bridges here sagged too much and I didn&#x27;t have my supports
dialed in well enough -- I couldn&#x27;t get it apart.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;fdm_complete.9ccd465043b3832d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;scan&quot;&gt;scan&lt;&#x2F;h2&gt;
&lt;p&gt;I scanned an eraser and an RS232 programmer with the Leo:&lt;&#x2F;p&gt;
&lt;script type=&quot;module&quot; src=&quot;https:&#x2F;&#x2F;ajax.googleapis.com&#x2F;ajax&#x2F;libs&#x2F;model-viewer&#x2F;3.1.1&#x2F;model-viewer.min.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;p&gt;&lt;model-viewer src=&quot;remeshed.glb&quot;  shadow-intensity=&quot;1&quot; camera-controls touch-action=&quot;pan-y&quot; style=&quot;width: 640px; height: 480px;&quot;&gt;&lt;&#x2F;model-viewer&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;eraser.86f456076c26b727.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;programmer.2e7419dc69340d45.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>tourmaline</title>
        <published>2023-10-02T00:00:00+00:00</published>
        <updated>2025-10-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/tourmaline/"/>
        <id>https://blog.npry.dev/tourmaline/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/tourmaline/">&lt;p&gt;I started this project in response to my experience with &lt;a href=&quot;&#x2F;class&#x2F;htm&#x2F;embedded&quot;&gt;my how-to-make
embedded project&lt;&#x2F;a&gt;, which was an exercise in being disappointed
by &lt;a href=&quot;https:&#x2F;&#x2F;www.atomvm.net&#x2F;&quot;&gt;atomvm&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;tourmaline&lt;&#x2F;code&gt; is an attempt to port &lt;a href=&quot;https:&#x2F;&#x2F;erlang.org&quot;&gt;Erlang&lt;&#x2F;a&gt; to &lt;code&gt;#![no_std]&lt;&#x2F;code&gt;
Rust, split into several crates, presently: a BEAM file
serializer&#x2F;deserializer, an ETF serializer&#x2F;deserializer, BIF implementations,
interface traits, native term types, and a runtime.&lt;&#x2F;p&gt;
&lt;p&gt;I did a good chunk of work by the time I got pulled off into other things —
I was hoping to be able to evaluate some simple bytecode soon. I plan to get
back to this, but frankly the amount of mental RAM I need to page in from very
stale cache is daunting, so it may take a long time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;concept&quot;&gt;concept&lt;&#x2F;h2&gt;
&lt;p&gt;The short version is that I think it&#x27;d be neat and useful to be able to embed
Erlang into more contexts — as kind of a very-high-functioning scripting
language that could run in other software and on embedded devices. Joe Armstrong
got most of the primitives right.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>embedded</title>
        <published>2023-09-27T00:00:00+00:00</published>
        <updated>2023-09-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/embedded/"/>
        <id>https://blog.npry.dev/class/htm/embedded/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/embedded/">
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;blinky.29c7197f9e4df6c1.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;strong&gt;dev board&lt;&#x2F;strong&gt;: esp32-c3 xiao&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;note: reviewing this week, I realized I didn&#x27;t demonstrate a video of the board working in this documentation. Please see &lt;a href=&quot;..&#x2F;networking-comms&#x2F;&quot;&gt;networking&lt;&#x2F;a&gt; for a video of a later version of this board design working.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I took this week in the direction of doing two implementations in two different
languages.&lt;&#x2F;p&gt;
&lt;p&gt;Source code listings are included as a tarball &lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;embedded&#x2F;src.tgz&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rust&quot;&gt;rust&lt;&#x2F;h2&gt;
&lt;p&gt;I wrote a &lt;a href=&quot;https:&#x2F;&#x2F;rust-lang.org&quot;&gt;rust&lt;&#x2F;a&gt; implementation first using
Espressif&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;esp-rs&quot;&gt;esp-rs&lt;&#x2F;a&gt; tooling.&lt;&#x2F;p&gt;
&lt;p&gt;My first approach here was the &lt;code&gt;esp_idf_hal&lt;&#x2F;code&gt; crate&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, which is implemented on
top of Espressif&#x27;s C SDK (ESP-IDF). This was easy to get up and running -- I
was able to blink an LED and poll &lt;a href=&quot;https:&#x2F;&#x2F;httpbin.org&quot;&gt;httpbin&lt;&#x2F;a&gt; to verify WiFi
connectivity, while outputting to a terminal via the virtual USB serial port.&lt;&#x2F;p&gt;
&lt;p&gt;This took some doing, but the overhead was much lower than for the original
ESP32 or the S series, as the upstream Rust compiler has support for RISC-V,
but not for Xtensa. You still do need to install &lt;code&gt;esp-idf&lt;&#x2F;code&gt; itself in order
to build, which is annoying, because it&#x27;s a huge tentacle monster of git
submodules and custom build tooling. Rust build scripts in the &lt;code&gt;esp_idf_hal&lt;&#x2F;code&gt;
crate mostly handle this, but I run &lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&quot;&gt;NixOS&lt;&#x2F;a&gt;, so my system is
as a rule not amenable to random build processes being able to mutate the
system, install their own dependencies, and also assume that bash lives in
&lt;code&gt;&#x2F;bin&#x2F;&lt;&#x2F;code&gt;. I was able to hack it in eventually by excising several heuristic
checks in the esp-idf build scripts that didn&#x27;t believe that they weren&#x27;t
already in a virtualenv.&lt;&#x2F;p&gt;
&lt;p&gt;In other news, I discovered some nice tooling here -- &lt;code&gt;cargo-espflash&lt;&#x2F;code&gt; gives a
single-command compile-upload-and-monitor without also forcing you to live with
a whole monolithic blob of dead weight like PlatformIO. So nice to have tooling
developed by people who believe in clear, decoupled interfaces; Unix
philosophy, etc. etc.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;part-1-5-pure-rust&quot;&gt;part 1.5: pure rust&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;esp_idf_hal&lt;&#x2F;code&gt; was not particularly satisfying -- it is, for one thing, mostly
C. While much of the world is built on C, I prefer Rust if I can get it, and
there is a pure-Rust implementation of most everything &lt;code&gt;esp_idf_hal&lt;&#x2F;code&gt; gives you
in &lt;code&gt;esp32**_hal&lt;&#x2F;code&gt; (in our case &lt;code&gt;esp32c3_hal&lt;&#x2F;code&gt;, though there is a crate for each
Espressif MCU model). Furthermore, Rust has a burgeoning community of embedded
libraries and projects that actually attempt to interoperate with each other.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;esp_idf_hal&lt;&#x2F;code&gt; does make an attempt to participate, but I didn&#x27;t find it that
effective -- ideally, it would handle chip-specifics and then get out of your
way to make using the generic interfaces as usable as possible, but Espressif
seems more interested in implementing a whole HTTP stack from scratch on their
own instead, and then having you use that. Not really my cup of tea -- I am
desperately hoping for a world where I can use the same HTTP client on a Linux
environment as on an MCU.&lt;&#x2F;p&gt;
&lt;p&gt;Main, relevant open-source Rust projects:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;embedded-rust&lt;&#x2F;code&gt; is a github org with a set of interface crates that abstract
different parts of the computational stack&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;embedded-hal{,-async}&lt;&#x2F;code&gt; (abstracting hw peripherals)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;embedded-io{,-async}&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;embedded-nal{,-async}&lt;&#x2F;code&gt; (&lt;strong&gt;N&lt;&#x2F;strong&gt;etwork &lt;strong&gt;A&lt;&#x2F;strong&gt;bstraction &lt;strong&gt;L&lt;&#x2F;strong&gt;ayer)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;embedded-time&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;embassy&lt;&#x2F;code&gt;: embedded async runtime, notably including&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;embassy-executor&lt;&#x2F;code&gt; (async executor itself)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;embassy-sync&lt;&#x2F;code&gt; (synchronization primitives -- mutexes, channels)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;embassy-net&lt;&#x2F;code&gt; (network abstraction)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;smoltcp&lt;&#x2F;code&gt;: runtime-agnostic&#x2F;userspace network stack&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The holy grail is to be easily able to develop a portable embedded program (as
in: nearly the whole body of the program is &lt;em&gt;entirely&lt;&#x2F;em&gt;, character-by-character,
identical on an ESP32 and an RP2040) that uses an async executor to schedule
network I&#x2F;O, disk&#x2F;flash I&#x2F;O, &lt;em&gt;and&lt;&#x2F;em&gt; peripheral access.&lt;&#x2F;p&gt;
&lt;p&gt;In the scheme of things, we&#x27;re close, with Rust. &lt;code&gt;smoltcp&lt;&#x2F;code&gt; is parametric over
both its physical medium (Ethernet, IP packets (virtual medium), etc.) &lt;em&gt;and&lt;&#x2F;em&gt;
the implementation -- I can write a new raw socket interface and it will work
fine. &lt;code&gt;embassy-net&lt;&#x2F;code&gt; and &lt;code&gt;embedded-nal&lt;&#x2F;code&gt; are themselves generic over their tcp
and udp socket types -- even the DNS implementation. &lt;code&gt;embedded-hal&lt;&#x2F;code&gt; gets us
peripheral bus access that is abstracted from the MCU -- you can actually write
a generic driver in Rust against a clearly- and well-defined interface.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I mention all of this because I received a painstakingly clear picture of where
things stand for the ESP32C3. Things &lt;em&gt;are&lt;&#x2F;em&gt; close, but the edges are still very
rough. It is posssible to write a program that uses an asynchronous executor to
do HTTP requests and blink LEDs and at least try to connect to an MQTT broker
all at the same time. However, the HTTP requests take tens of seconds each,
TLS doesn&#x27;t work, and I never did get the MQTT broker to connect.&lt;&#x2F;p&gt;
&lt;p&gt;The fact that it works at all, however, gives me hope -- that such a thing
works at all means that this highly distributed and mutually-abstracted
implementation is &lt;em&gt;mostly right&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, some other things I ran into:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;64&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1024&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;static&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP_MEM&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-numeric z-rust&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;global_allocator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;static&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; Heap &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Heap&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;empty&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;, &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;init&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP_MEM&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;as_ptr&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP_MEM&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;len&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; elided
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We&#x27;re looking at the initialization of my heap data structure and its backing
memory. I expected this to work, but in fact I was getting clear memory
corruption (behavior-dependent, occasional-crashes, store&#x2F;load exception
messages, etc.). Thought it could be the stack, but it didn&#x27;t actually seem to
be.&lt;&#x2F;p&gt;
&lt;p&gt;The actual solution to the problem was this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ld&quot; class=&quot;language-ld z-code&quot;&gt;&lt;code class=&quot;language-ld&quot; data-lang=&quot;ld&quot;&gt;&lt;span class=&quot;z-source z-linker&quot;&gt;&lt;span class=&quot;z-keyword z-control z-linker&quot;&gt;SECTIONS&lt;&#x2F;span&gt; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-linker&quot;&gt;    &lt;span class=&quot;z-variable z-other z-linker&quot;&gt;.heap&lt;&#x2F;span&gt; (&lt;span class=&quot;z-variable z-other z-linker&quot;&gt;NOLOAD&lt;&#x2F;span&gt;) : &lt;span class=&quot;z-keyword z-control z-linker&quot;&gt;ALIGN&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-integer z-linker&quot;&gt;4&lt;&#x2F;span&gt;) {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-linker&quot;&gt;        &lt;span class=&quot;z-variable z-other z-linker&quot;&gt;__heap_start&lt;&#x2F;span&gt; = &lt;span class=&quot;z-variable z-language z-linker&quot;&gt;.&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-linker&quot;&gt;        &lt;span class=&quot;z-variable z-language z-linker&quot;&gt;.&lt;&#x2F;span&gt; += &lt;span class=&quot;z-constant z-numeric z-integer z-linker&quot;&gt;128K&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-linker&quot;&gt;        &lt;span class=&quot;z-variable z-other z-linker&quot;&gt;__heap_end&lt;&#x2F;span&gt; = &lt;span class=&quot;z-variable z-language z-linker&quot;&gt;.&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-linker&quot;&gt;    } &amp;gt; &lt;span class=&quot;z-variable z-other z-linker&quot;&gt;RWDATA&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-linker&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-linker&quot;&gt;&lt;span class=&quot;z-variable z-other z-linker&quot;&gt;INSERT&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-linker&quot;&gt;AFTER&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-linker&quot;&gt;.stack_end&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;extern&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;C&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;static&lt;&#x2F;span&gt; __heap_start&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;static&lt;&#x2F;span&gt; __heap_end&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;global_allocator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;static&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; Heap &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Heap&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;empty&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;, &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; start &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;__heap_start&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;as_ptr&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; end &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;__heap_end&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;as_ptr&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-constant z-other z-rust&quot;&gt;HEAP&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;init&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;start&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; end &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;-&lt;&#x2F;span&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; elided
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Theoretically, &lt;code&gt;HEAP_MEM&lt;&#x2F;code&gt; in my first example should have statically allocated
the space I requested, meaning no other symbol should have intruded upon it. If
the problem was running out of space, the heap data structure would fail
mallocs, and I&#x27;d seen that in the logs for other reasons before, so I had been
fairly confident that wasn&#x27;t happening.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, I&#x27;m pretty sure this was UB -- there was nowhere &lt;code&gt;HEAP_MEM&lt;&#x2F;code&gt; was
actually getting &lt;em&gt;used&lt;&#x2F;em&gt; for anything, so the Rust compiler wasn&#x27;t able to
reason about it and simply didn&#x27;t reserve the memory in &lt;code&gt;.bss&lt;&#x2F;code&gt;. Specifically,
&lt;code&gt;HEAP_MEM.as_ptr() as usize&lt;&#x2F;code&gt; totally erases any association to the backing
array by degrading to an integer type. Hence, &lt;code&gt;malloc&lt;&#x2F;code&gt;s were stomping over
other memory.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m fairly confident in this because after using the linker to reserve the
space, the problem went away -- no more corruption.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;defmt&quot;&gt;&lt;code&gt;defmt&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;This is a nice embedded logging utility available in Rust that I discovered as
part of this implementation. It&#x27;s essentially a very aggressive string-interner
that shoves the interned strings &lt;em&gt;into a debug section&lt;&#x2F;em&gt; and replaces them in
the actual binary with their indices -- when the binary gets flashed, there&#x27;s
very little overhead from logging (code size, or runtime memory&#x2F;I&#x2F;O). You need
the original binary in order to decode the logs, but &lt;code&gt;defmt&lt;&#x2F;code&gt; comes with a tool
&lt;code&gt;defmt-print&lt;&#x2F;code&gt; that you can pipe them through. It supports interpolation and
does compression on top of that, too.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;elixir-erlang-on-atomvm&quot;&gt;elixir &#x2F; erlang on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;atomvm&#x2F;AtomVM&quot;&gt;atomvm&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I have mixed feelings about erlang&#x2F;elixir because of their typing-indecisiveness.
They don&#x27;t give you many tools, as languages, to prove correctness -- in an
environment like erlang that&#x27;s intentionally designed to encourage dynamism of
behavior, this spooks me more than a little bit.&lt;&#x2F;p&gt;
&lt;p&gt;However, I also in my heart believe that actor systems are essentially correct
as a way to build distributed systems (at least up to hard performance
requirements). WiFi-enabled microcontrollers represent an environment that is
not terribly computationally demanding (if you really cared about power (hence
computational overhead), you wouldn&#x27;t be using WiFi) and could benefit from
this model.&lt;&#x2F;p&gt;
&lt;p&gt;Maybe most attractive here is that all data in Erlang is represented as a
single inductive type (&lt;code&gt;term&lt;&#x2F;code&gt;), which can be binary-encoded and decoded with a
single function call (&lt;code&gt;:erlang.term_to_binary&lt;&#x2F;code&gt;, &lt;code&gt;:erlang.binary_to_term&lt;&#x2F;code&gt;) --
you get this for free, for all data, always -- so the overhead of communicating
to remote nodes is very low. Similarly it&#x27;s two function calls to send a UDP
packet:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; class=&quot;language-elixir z-code&quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-tuple z-elixir&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-elixir&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-constant z-elixir&quot;&gt;:&lt;&#x2F;span&gt;ok&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-elixir&quot;&gt;,&lt;&#x2F;span&gt; sock&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-elixir&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-elixir&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-constant z-elixir&quot;&gt;:&lt;&#x2F;span&gt;gen_udp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-method z-elixir&quot;&gt;.&lt;&#x2F;span&gt;open&lt;span class=&quot;z-punctuation z-section z-function z-elixir&quot;&gt;(&lt;&#x2F;span&gt;port&lt;span class=&quot;z-punctuation z-section z-function z-elixir&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-constant z-elixir&quot;&gt;:&lt;&#x2F;span&gt;gen_udp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-method z-elixir&quot;&gt;.&lt;&#x2F;span&gt;send&lt;span class=&quot;z-punctuation z-section z-function z-elixir&quot;&gt;(&lt;&#x2F;span&gt;sock&lt;span class=&quot;z-punctuation z-separator z-object z-elixir&quot;&gt;,&lt;&#x2F;span&gt; ip&lt;span class=&quot;z-punctuation z-separator z-object z-elixir&quot;&gt;,&lt;&#x2F;span&gt; port&lt;span class=&quot;z-punctuation z-separator z-object z-elixir&quot;&gt;,&lt;&#x2F;span&gt; data&lt;span class=&quot;z-punctuation z-section z-function z-elixir&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The socket then even &lt;em&gt;sends data to your processes as messages&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; class=&quot;language-elixir z-code&quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;&lt;span class=&quot;z-meta z-module z-elixir&quot;&gt;&lt;span class=&quot;z-keyword z-control z-module z-elixir&quot;&gt;defmodule&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-class z-elixir&quot;&gt;MyModule&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-module z-elixir&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-elixir&quot;&gt;use&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-class z-elixir&quot;&gt;GenServer&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-elixir&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-comment z-elixir&quot;&gt;#&lt;&#x2F;span&gt; ... elided ...
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;&lt;span class=&quot;z-meta z-function z-elixir&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-module z-elixir&quot;&gt;def&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-public z-elixir&quot;&gt;handle_info&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-elixir&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-sequence z-tuple z-elixir&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-elixir&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-symbol z-elixir&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-constant z-elixir&quot;&gt;:&lt;&#x2F;span&gt;udp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-elixir&quot;&gt;,&lt;&#x2F;span&gt; sock&lt;span class=&quot;z-punctuation z-separator z-sequence z-elixir&quot;&gt;,&lt;&#x2F;span&gt; addr&lt;span class=&quot;z-punctuation z-separator z-sequence z-elixir&quot;&gt;,&lt;&#x2F;span&gt; port&lt;span class=&quot;z-punctuation z-separator z-sequence z-elixir&quot;&gt;,&lt;&#x2F;span&gt; packet&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-elixir&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-function z-elixir&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-module z-elixir&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-elixir&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-comment z-elixir&quot;&gt;#&lt;&#x2F;span&gt; ... elided ...
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-elixir&quot;&gt;end&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-elixir&quot;&gt;&lt;span class=&quot;z-keyword z-control z-elixir&quot;&gt;end&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The model is really so straightforward -- it captures something deep.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;atomvm&quot;&gt;atomvm&lt;&#x2F;h3&gt;
&lt;p&gt;I had come across AtomVM probably a couple of years ago looking at embedded
projects and wanted to try it but never found a fit. I saw it supported ESP32
and figured I&#x27;d give it a shot for this week.&lt;&#x2F;p&gt;
&lt;p&gt;This was not easy. AtomVM is alpha-readiness, open-source software and to my
knowledge not commercially-supported. It builds off of esp-idf (discussed
above), which I luckily already had installed. Notionally, it also supports
esp32c3 (even though they mostly explicitly talk about the original esp32), but
the installer images don&#x27;t work if you follow their instructions directly.&lt;&#x2F;p&gt;
&lt;p&gt;For some background, AtomVM is a binary firmware image that you can load into
flash. It won&#x27;t do anything, though, unless you put a &lt;code&gt;.avm&lt;&#x2F;code&gt; (AtomVM
precompiled Erlang bytecode) image at a different flash offset. Then (after a
reboot) the base image loads the bytecode and runs it -- you&#x27;re off to the
races.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have this context, we can get to the incorrect instructions. You
may imagine it&#x27;s critical that you load each of these images at the correct
offset so that the first one is picked up by the Espressif bootloader and the
second one is picked up by the first. The base offset for the esp32 is 0x1000.
For all other models of esp (as far as I can tell) there is no offset -- load
to 0x0. The default tooling and all the instruction say to put the image at
0x1000.&lt;&#x2F;p&gt;
&lt;p&gt;I didn&#x27;t figure out this was the problem until I had cloned atomvm and fully
scratch-rebuilt freshest master, where the &lt;code&gt;flashimage.sh&lt;&#x2F;code&gt; script for the
esp32c3 platform actually shows (once you build it) that its offset is 0x0.&lt;&#x2F;p&gt;
&lt;p&gt;After I did this I was able to run erlang&#x2F;elixir on the MCU. This was nice, but
it was followed up by several hours of tracing back exactly how AtomVM differs
from BEAM&#x2F;OTP (the canonical erlang distribution, runtime, and standard
library).&lt;&#x2F;p&gt;
&lt;p&gt;There were many subtle features I discovered here, like that the AtomVM folks
didn&#x27;t implement &lt;code&gt;:gen_server.start_link&#x2F;4&lt;&#x2F;code&gt;, but they &lt;em&gt;did&lt;&#x2F;em&gt; implement
&lt;code&gt;:gen_server.start_link&#x2F;3&lt;&#x2F;code&gt; and the name registry. You can call
&lt;code&gt;:gen_server.start_link&#x2F;3&lt;&#x2F;code&gt; and then call &lt;code&gt;:erlang.register&#x2F;2&lt;&#x2F;code&gt; with the same
name you would have passed to &lt;code&gt;start_link&#x2F;4&lt;&#x2F;code&gt;, and it&#x27;s as if you had called
&lt;code&gt;start_link&#x2F;4&lt;&#x2F;code&gt;. Why there isn&#x27;t just a &lt;code&gt;start_link&#x2F;4&lt;&#x2F;code&gt; perhaps I&#x27;ll never know.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;elixir&quot;&gt;elixir&lt;&#x2F;h3&gt;
&lt;p&gt;Elixir seems to mostly have been added to AtomVM as an afterthought. There&#x27;s
almost no overhead to doing so, as the bytecode is the same, but almost none of
the Elixir standard library works. This is fine, as it turns out, as most of
the Elixir standard library is just an opinionated wrapper around the Erlang
core.&lt;&#x2F;p&gt;
&lt;p&gt;In the abstract, I knew this, but I hadn&#x27;t been so aware of how little
extra Elixir gives you until I had to go without most of it. It&#x27;s mostly trying
to be magical and that ends up being confusing -- I gained a much clearer
appreciation for what the &quot;actual&quot; Erlang API looks like as a part of this.&lt;&#x2F;p&gt;
&lt;p&gt;I did some patching by copy-pasting parts of the Elixir standard library into
my project, then stripping out anything not supported by the AtomVM runtime. As
a result, I have my own &lt;code&gt;GenServer&lt;&#x2F;code&gt; and &lt;code&gt;Supervisor&lt;&#x2F;code&gt; that work on AtomVM,
though I ended up just using &lt;code&gt;:supervisor&lt;&#x2F;code&gt; directly from erlang because the
implementation is really not complete on the AtomVM side -- there&#x27;s a lot
hard-coded -- so adapting &lt;code&gt;Supervisor&lt;&#x2F;code&gt; to all possible use-cases is a pain.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;result&quot;&gt;result&lt;&#x2F;h3&gt;
&lt;p&gt;The final functional result for this implementation are some indicator LEDs
that show the WiFi status (and NTP -- AtomVM will grab this for you as part of
the network configuration), plus one that&#x27;s controlled over a UDP socket. I
wrote a UDP client also in Elixir (it&#x27;s pretty much the 2 lines from above) and
they just pass terms directly via binary. Really the easiest RPC I&#x27;ve ever
done, and it&#x27;d be trivial to wire more actors into the system.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;blinky.29c7197f9e4df6c1.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;em&gt;crate&lt;&#x2F;em&gt; = Rust package.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Note: by contrast, I do &lt;em&gt;not&lt;&#x2F;em&gt; consider Arduino to be clean or well-defined.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>final project concept</title>
        <published>2023-09-20T00:00:00+00:00</published>
        <updated>2023-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/final-project-concept/"/>
        <id>https://blog.npry.dev/class/htm/final-project-concept/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/final-project-concept/">
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chair.183debeec9fad55d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Current idea for my final project is a flight simulator cockpit (&quot;simpit&quot;). I
enjoy flying in flight sims, both military (e.g., &lt;a href=&quot;https:&#x2F;&#x2F;www.digitalcombatsimulator.com&#x2F;en&#x2F;&quot;&gt;DCS
World&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;vtolvr.bdynamicsstudio.com&#x2F;&quot;&gt;VTOL
VR&lt;&#x2F;a&gt;) and civilian (&lt;a href=&quot;https:&#x2F;&#x2F;www.flightsimulator.com&#x2F;&quot;&gt;MSFS
2020&lt;&#x2F;a&gt;). I already have gear from
&lt;a href=&quot;https:&#x2F;&#x2F;virpil-controls.us.com&#x2F;&quot;&gt;Virpil Controls&lt;&#x2F;a&gt; -- specifically a flight
stick, throttle, and rudder pedals. I also have a &lt;a href=&quot;https:&#x2F;&#x2F;store.steampowered.com&#x2F;valveindex&quot;&gt;Valve
Index&lt;&#x2F;a&gt; VR headset (flight
sims are in my opinion one of the best applications for VR currently).&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;flightstick.369326e58a4d85bb.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;em&gt;Flight stick&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;throttle.b42615d0e66fe92d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;em&gt;Throttle&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;rudder_pedals.7e7f6f6acaa6d410.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;em&gt;Rudder pedals&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;vr_headset.eef48c95c8673776.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;em&gt;VR Headset&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;major-limitations&quot;&gt;major limitations&lt;&#x2F;h2&gt;
&lt;p&gt;I don&#x27;t fly sims as much as I would like because:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;setup and teardown overhead is high&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;clamp flight stick and throttle to my desk&lt;&#x2F;li&gt;
&lt;li&gt;secure rudder pedals with paracord&lt;&#x2F;li&gt;
&lt;li&gt;get VR headset back out, plugged in, and snake umbilical so it&#x27;s out of
the way&lt;&#x2F;li&gt;
&lt;li&gt;this totally interferes with my normal usage of my desk, so i need to
tear the whole setup down after every time i use it&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;my chair is the opposite of ergonomic for VR and flight sims&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;wheels are not helpful for maintaining consistent body positioning in VR
and relative to controls&lt;&#x2F;li&gt;
&lt;li&gt;anatomics of rudder pedals raised off of the floor combined with a normal
chair mean I end up closer to balancing on my tailbone than sitting flat&lt;&#x2F;li&gt;
&lt;li&gt;I sometimes need to use a mouse and keyboard for input and I have to lean
over my controls and sit on the edge of my seat to do this. Not ergonomic
-- causes muscle aches &#x2F; mild strains if I do it a lot.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;controls positioning isn&#x27;t quite correct&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;rudder pedals move on me all the time &#x2F; I can&#x27;t push very hard on them&lt;&#x2F;li&gt;
&lt;li&gt;controls shift a bit each time I set it up -- big deal in VR&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;addressing-limitations&quot;&gt;addressing limitations&lt;&#x2F;h3&gt;
&lt;p&gt;The core of the project (what I need most) would address these limitations
with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;an ergonomic seat (reclined, probably adjustable, correct relationship to
all controls, ideally easy to get in and out of)&lt;&#x2F;li&gt;
&lt;li&gt;solid control mounts that don&#x27;t move relative to the seat&lt;&#x2F;li&gt;
&lt;li&gt;a spot to keep my VR headset that is easily accessible while sitting, but
isn&#x27;t in the way&lt;&#x2F;li&gt;
&lt;li&gt;should fit in one spot I have picked out in my room next to my PC
(measurement pending)&lt;&#x2F;li&gt;
&lt;li&gt;a spot for a mouse and keyboard that&#x27;s easily accessible from the seat &lt;em&gt;and&lt;&#x2F;em&gt;
doesn&#x27;t interfere with the controls&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;additional-desiderata&quot;&gt;additional desiderata&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;more-physical-controls&quot;&gt;more physical controls&lt;&#x2F;h3&gt;
&lt;p&gt;VR is great for visualization and immersion. It gives a much better feel for
the dynamics of flight when you can see the whole world moving around you
(including some peripheral vision) and you&#x27;re not just staring through a
clunky-to-move player camera PoV. A VR perspective enables you to take glances
and quickly scan the ground or a part of the sky.&lt;&#x2F;p&gt;
&lt;p&gt;However, &lt;em&gt;controlling&lt;&#x2F;em&gt; planes using VR interaction metaphors is a poor
experience. Typically, VR flight sim controls involve pointing at virtual
targets with the hand controllers and clicking. This is difficult in flight
sims because the cockpits being simulated are very dense -- it takes careful
aim and a steady hand to select exactly the button you wanted to click. Some
form of haptic feedback is usually provided when your controller target changes
(slight bump), but this falls drastically short of the real-world ability to
find physical controls by touch memory and relative position only.&lt;&#x2F;p&gt;
&lt;p&gt;For these reasons, I bind as much as possible onto the physical controls I
already have, but there are still a lot of inputs remaining that I have to
actuate using VR controls. Illustratively, a typical startup sequence involves
5 minutes of carefully lining up my controller at half of the buttons in the
cockpit and trying to get only the relevant virtual switches and buttons to
actuate.&lt;&#x2F;p&gt;
&lt;p&gt;High-button-density controls like OSBs (on-screen buttons) around
multi-function displays (MFDs):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;mfd.c0739f1aec95b8fe.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;are also not worth mapping to HOTAS controls both because there are a lot of
them (typ. 20 per MFD, x 2 or 3 MFDs) and because they rely on their physical
position around the display to supply semantic context, which is totally absent
if you move the buttons to a different control.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m planning on making two or three MFDs with dummy screens (for VR use --
buttons only, functional screens not required). I intend to make the dummy
screen a modular swap for a 7&quot; square screen (typical of these MFDs) in case I
want this in the future.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m considering adding one or two additional boxes with button and switch
arrays to augment what I already have.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;portability&quot;&gt;portability&lt;&#x2F;h3&gt;
&lt;p&gt;I am aiming to make this setup portable. As a result, I want it to break down
into small modular pieces interconnected with consistent power and data buses.
If possible, I will do everything with USB-C (using USB-PD if required).&lt;&#x2F;p&gt;
&lt;p&gt;However, I still want it to feel solid -- I will be investigating significant
use of tensile members to keep the structure rigid.&lt;&#x2F;p&gt;
&lt;p&gt;I expect it will be straightforward to produce low-part-count control mounts
that bolt directly to the rest of the setup, so the main concern here is the
chair. Design ideas are still percolating, but probably I will make it possible
to fully disassemble the joints that make the chair adjustable, which will let
it break down in relatively small pieces.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;prior-art&quot;&gt;prior art&lt;&#x2F;h2&gt;
&lt;p&gt;There is &lt;em&gt;extensive&lt;&#x2F;em&gt; prior art amongst the flight sim hobbyist community for
building simpits. While I will draw at a high level here for inspiration and
possible approaches, I will most likely directly make use of several existing
systems host-side to get external signals into the flight sims. Most notably:
&lt;a href=&quot;https:&#x2F;&#x2F;dcs-bios.readthedocs.io&#x2F;en&#x2F;latest&#x2F;&quot;&gt;DCS-BIOS&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;renders&quot;&gt;renders&lt;&#x2F;h2&gt;
&lt;p&gt;Below is a render of what this project might look like as a combined system:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;chair.183debeec9fad55d.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This image was produced directly from the CAD assembly (linked below), exported
as an STL and rendered in Blender using Cycles.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design-files&quot;&gt;design files&lt;&#x2F;h2&gt;
&lt;p&gt;Design files can be found &lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;final-project-concept&#x2F;design_files.zip&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>laser</title>
        <published>2023-09-20T00:00:00+00:00</published>
        <updated>2023-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/laser/"/>
        <id>https://blog.npry.dev/class/htm/laser/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/laser/">&lt;p&gt;Laser cutter: 30W GCC&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;box_multiple_sizes.6365c56bd965a63a.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;em&gt;Final result&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;settings&quot;&gt;settings&lt;&#x2F;h2&gt;
&lt;p&gt;Using the suggested settings as a baseline, I arrived at the following refined
numbers for 1&#x2F;8&quot; cardboard:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;speed&lt;&#x2F;th&gt;&lt;th&gt;2.3%&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;power&lt;&#x2F;td&gt;&lt;td&gt;100&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ppi&lt;&#x2F;td&gt;&lt;td&gt;220&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The largest item causing variance in cut quality was focus -- my cardboard
sheet was bowed up, causing me to lose focus in the middle of the sheet,
leading to a black burn on the upper surface blooming from the cut location and
loss of effective cut power. I noticed this by comparison as I was watching
Cayden and Lancelot cut their projects.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kerf-characterization-part-1&quot;&gt;kerf characterization (part 1)&lt;&#x2F;h2&gt;
&lt;p&gt;I initially tried to measure kerf with arrays of interlocking fingers of
increasing kerf compensations.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;fit_test_2.b88a9fa67ef67d2e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;fit_test.a53441f6e4c448ff.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I measured the thickness of the cardboard using a set of calipers and found
that it was approximately 4.15mm thick. The finger widths thus started at
4.15mm and increased in 0.2mm increments. I anticipated that this would make
the first two indices too small, as Neil told us that the beam waist was in the
ballpark of 0.010&quot;. 0.1mm is approximately 0.004&quot;, so I would have expected an
interference fit between indices 2 and 3. However, index 1 fit perfectly (no
kerf compensation).&lt;&#x2F;p&gt;
&lt;p&gt;I realized the error of my ways after the fact as I was building my project:
the precision of my measurement was reliant on my ability to measure cardboard
thickness precisely with calipers, and on cardboard having a consistent
thickness in the first place. I remedied this later.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;project-summary-or-kerf-characterization-part-2&quot;&gt;project summary (or: kerf characterization part 2)&lt;&#x2F;h2&gt;
&lt;p&gt;I made parametric cardboard holders. Their function is simply to elevate an
object. I started out making small boxes using box-jointed edges and realized
that (obviously) they would not hold with just a box joint (I&#x27;m used to using
adhesive).&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;kerf_good_fit.2008fd13b0090e20.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This, however, let me dial in my kerf, as the precision in the box joint is
entirely in the vertical axis and not dependent on the thickness of the
cardboard at all. I binary searched, printing repeated joints, and arrived at a
kerf compensation of 0.15mm (= approx 0.006&quot;), giving an interference fit
inasmuch as one can be said to exist in cardboard.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wedged-joints&quot;&gt;wedged joints&lt;&#x2F;h2&gt;
&lt;p&gt;Given that the joint was not going to hold as-is, I added a joint (topmost on
the edge) that could accept a wedge.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;small_box_no_wedge.93123f54e60165b6.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Wedges installed:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;box_wedge_final.711957b177d94065.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The complete support is relatively sturdy for what it is. Holding a power
supply on my desk:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;box_holding_power_supply.5cebbd540415ca45.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I don&#x27;t believe the wedges are actually in any significant shear loading while
the structure is bearing weight -- I think the increased friction of the joint
as a result of this construction is actually what&#x27;s providing most of the
stability.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cutting-wedges&quot;&gt;cutting wedges&lt;&#x2F;h2&gt;
&lt;p&gt;The wedges were difficult to cut, small as they were:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;wedge_wrong_axis.c5b53c6d7836cb1f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The above wedge failed because it was cut &lt;em&gt;along&lt;&#x2F;em&gt; the axis of the cardboard
corrugations and could easily twist off of the single line of glue. I soon
realized this and changed them to be cut across the corrugations.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;wedge_good_axis.866c57af3f78fb6e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I still had some failures this way due to delamination, but under 20%.&lt;&#x2F;p&gt;
&lt;p&gt;Originally, I was cutting the wedges one-by-one in left-over areas on the
cardboard between the walls, but I decided to develop a way to pack them more
densely.&lt;&#x2F;p&gt;
&lt;p&gt;First, I simply went for a dense packing in an array:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;wedges_array.574705ad27c7046f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Then I built a &quot;sprue tree&quot; out of cardboard to retain several wedges as one
complete unit that could be extracted from the laser cutter more easily.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;wedges_sprue.49962245e6b6db24.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Surprisingly for how thin the connecting member is, these came out without
tearing any of the &quot;sprues&quot; very consistenly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;parametricity&quot;&gt;parametricity&lt;&#x2F;h2&gt;
&lt;p&gt;Adjustable parameters:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Height&lt;&#x2F;li&gt;
&lt;li&gt;Width&lt;&#x2F;li&gt;
&lt;li&gt;Leg height&lt;&#x2F;li&gt;
&lt;li&gt;Number of box fingers&lt;&#x2F;li&gt;
&lt;li&gt;Cardboard thickness&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The cross-member thickness is a proportion of the width or height of the
relevant direction.&lt;&#x2F;p&gt;
&lt;p&gt;A small box and a big box patterned from the same design file:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;box_multiple_sizes.6365c56bd965a63a.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;corel-draw-tricks&quot;&gt;corel draw tricks&lt;&#x2F;h2&gt;
&lt;p&gt;The best way I could figure out to use Corel Draw was as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Set the &quot;paper&quot; as the full size of the bed&lt;&#x2F;li&gt;
&lt;li&gt;Pick a color that is your no-cut color (I picked blue) and configure the
printer not to cut it (uncheck vector, raster in the color configuration)&lt;&#x2F;li&gt;
&lt;li&gt;Draw a rectangle within the bed outline that is the size of your cardboard
(colored no-cut) as a reference&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Keep working off of this one file&lt;&#x2F;em&gt;: each time you print a part, mark it
no-cut but leave it in-place. Now you know what parts of the sheet you&#x27;ve
used and can squeeze in other parts quite precisely.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Additional note: there is a palette of recent colors in the bottom left.
Right-click a color to set the currrently-selected curve to that color
(left-click is fill).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design-files&quot;&gt;design files&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;laser&#x2F;laser_design_files.zip&quot;&gt;Here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>vinyl</title>
        <published>2023-09-20T00:00:00+00:00</published>
        <updated>2023-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/class/htm/vinyl/"/>
        <id>https://blog.npry.dev/class/htm/vinyl/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/class/htm/vinyl/">
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;window.a4501e5589ff5f82.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I cut this window sticker with the Roland vinyl cutter. The pattern I used was
the last stanza of The Lord of the Rings&#x27; Ring Poem:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;One ring to rule them all, one ring to bind them&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;One ring to bring them all and in the darkness bind them&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;or as more directly rendered in the Black Speech:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Ash nazg durbatulûk, ash nazg gimbatul&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Ash nazg thrakatulûk agh burzum-ishi krimpatul&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;or finally the Black Speech in the Sindarin &lt;em&gt;tengwar&lt;&#x2F;em&gt; alphabet (actual
cut pattern):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;pattern.e019944681b1d8ce.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;The circular Ring Poem pattern is common in Lord of the Rings art, but rather
than use something preexisting, I made the figure myself in Adobe Illustrator
using the venerable &lt;a href=&quot;https:&#x2F;&#x2F;www.dafont.com&#x2F;tengwar-annatar.font&quot;&gt;Tengwar Annatar
font&lt;&#x2F;a&gt; (input method documented
&lt;a href=&quot;https:&#x2F;&#x2F;www.elfico.com.br&#x2F;wp-content&#x2F;uploads&#x2F;2013&#x2F;12&#x2F;tngandoc.pdf&quot;&gt;here&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Tengwar&lt;&#x2F;em&gt; notes&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;em&gt;tengwa&lt;&#x2F;em&gt; is a single character (&lt;em&gt;tengwar&lt;&#x2F;em&gt; being the plural) representing a
consonant&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Tehtar&lt;&#x2F;em&gt; (singular &lt;em&gt;tehta&lt;&#x2F;em&gt;) are diacritics that appear above and below
&lt;em&gt;tengwar&lt;&#x2F;em&gt; representing vowels&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Typography notes&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Vertical character stems are known as &lt;em&gt;ascenders&lt;&#x2F;em&gt; or &lt;em&gt;descenders&lt;&#x2F;em&gt; (depending
on direction)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;corel-draw-import&quot;&gt;corel draw import&lt;&#x2F;h2&gt;
&lt;p&gt;I followed the instructions for the Roland vinyl cutter and ran into two
issues.&lt;&#x2F;p&gt;
&lt;p&gt;First, DXF v2018, the default DXF export option for current versions of
Illustrator is (unsurprisingly) not valid in our version of Corel Draw (2017).
Exporting as v2013 solved this problem.&lt;&#x2F;p&gt;
&lt;p&gt;Secondly, my image contained self-intersecting segments from overlapping
characters:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;
&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;intersect.cfa19dcfb673cb5f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Selected &lt;em&gt;tehta&lt;&#x2F;em&gt; (blue) overlaps unselected (black).&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Cutting the image with these self-intersections would have produced undesired
segmentation in the final pattern. I eliminated these intersections by using
the path union tool in Illustrator.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sample-pattern&quot;&gt;sample pattern&lt;&#x2F;h2&gt;
&lt;p&gt;I cut a sample piece first to test my process using a section of the final
pattern. I selected the sample pattern to intentionally include many of the
elements I expected would be most recalcitrant (thin, long ascenders,
disconnected &lt;em&gt;tehtar&lt;&#x2F;em&gt;, looping&#x2F;spiral elements), to build confidence that the
full pattern would be feasible.&lt;&#x2F;p&gt;
&lt;p&gt;I cut at 20 mm&#x2F;second and 80 grams-force of pressure (default recommendation on
the Roland). I found that 80 grams-force was slightly too light -- I was having
to fight to shear the vinyl in some sections as I was weeding it. As a result,
I increased the pressure to 85 grams-force for the final cut.&lt;&#x2F;p&gt;
&lt;p&gt;Just as I was starting to weed:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;weeding.1b96602c79c5b992.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;You can see that I subdivided the vinyl I needed to weed using a mat knife in
order to enable smaller, individually-completable weeding actions in which I
could control.&lt;&#x2F;p&gt;
&lt;p&gt;Weeding complete:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;weeded.17be27cfbe7b0b0f.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I lost a portion of the &#x2F;a&#x2F; &lt;em&gt;tehta&lt;&#x2F;em&gt; on the left -- it should look like the one
in the middle (three approximately-vertical marks). I wasn&#x27;t careful touched
the adhesive with my finger -- it lost enough stick as a result that it moved
significantly when I placed it back down and loosely stuck to the middle mark.
I didn&#x27;t want to lose this one too, so I left them stuck together.&lt;&#x2F;p&gt;
&lt;p&gt;On the transfer:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;transferred.20b1caa245246719.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I peeled the backing right after applying it to ensure I had applied enough
pressure and that there wouldn&#x27;t be any issues with the difficult pattern
elements. There weren&#x27;t, but I should have either taken the sample to
completion and applied it to glass or not removed the backing to preserve the
adhesive. I went halfway instead, and regret doing so (though it didn&#x27;t result
in any adverse consequences in this case).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;full-pattern&quot;&gt;full pattern&lt;&#x2F;h2&gt;
&lt;p&gt;At this point I started on the complete pattern. As far as I could find, the
shop was out of black vinyl (the color I wanted) except for a few strips and a
~300x400mm sheet with a crease in it that caused the vinyl to bulge. You can
see this crease&#x2F;bulge here (after I cut the pattern):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;bulge.51d03cea7f964e98.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I knew this would cause some difficulties, but I tried it anyway. An additional
feature of this full cut that I didn&#x27;t see on the sample pattern was scoring
apparently due to the knife dragging on the vinyl between pattern elements. I
suspect this is because the vinyl was not very flat.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;scoring.62f9f4b3b25f5031.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;In the previous two images you can see that I had started to segment the
non-pattern vinyl to make easier peels as I had done in the sample. This image
provides some more detail on how I did this:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;segmentations.a861e32e43a7822e.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I cut a ring inside the &lt;em&gt;tengwar&lt;&#x2F;em&gt; descenders, then I separated the outside
excess vinyl from the inside but cutting between characters. I made an cut from
the tip of each descender and ascender to the inner ring or the outer edge of
the vinyl, respectively. This was to ensure that I could pull each vinyl
segment as much aligned with the axis of each ascender &#x2F; descender as possible,
to avoid these high aspect-ratio elements tearing or deforming.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;tehtar_cutouts.f70de3d105ac4849.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;This image shows the weeding partially done, and showcases protective cells I
cut around each &lt;em&gt;tehta&lt;&#x2F;em&gt;. This technique allowed me to peel the bulk of the
vinyl fairly quickly by avoiding these delicate, high-detail areas. I peeled
them at the very end.&lt;&#x2F;p&gt;
&lt;p&gt;Here is a more zoomed out shot of the state of the weeding at this point
(interior mostly complete):&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;weeding_mostly_done.80e9b7f94bf50dac.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I had weeded my sample using a pair of tweezers, but I discovered as I was
weeding the complete pattern that I prefer to use the sharp corner of a mat
knife to catch the vinyl. This gave me much more dexterity, and I almost never
peeled anything I didn&#x27;t mean to.&lt;&#x2F;p&gt;
&lt;p&gt;Fully weeded:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;weeding_done.93e6d404d5c9d82b.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Transfer applied:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;transfer.b9bd1d642cb2550b.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I used the side of the mat knife (retracted) to apply heavy pressure on the
whole pattern to ensure it would all pull off of the backing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sample-pattern-window-application&quot;&gt;sample pattern window application&lt;&#x2F;h2&gt;
&lt;p&gt;At this point, I still had the sample pattern with its backing removed. I went
to the window I wanted to transfer to and made a first try with the sample
pattern on the other pane.&lt;&#x2F;p&gt;
&lt;p&gt;Sample applied:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;window_transfer.474987e95bc520af.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;I also rubbed this with the side of the mat knife to ensure the vinyl was as
well-adhered as possible to the window.&lt;&#x2F;p&gt;
&lt;p&gt;I had no issues peeling the transfer -- I went very slowly and used the mat
knife to catch anything that wanted to lift. I varied my peel angle to minimize
lifting torque (generally aiming to peel &lt;em&gt;along&lt;&#x2F;em&gt; the axis of the typographic
elements).&lt;&#x2F;p&gt;
&lt;p&gt;Sample transfer peeled:&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;window.cb4bd09945c040dd.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;full-pattern-window-application&quot;&gt;full pattern window application&lt;&#x2F;h2&gt;
&lt;p&gt;I then prepped the window for the full pattern by cleaning the application area
with isopropyl alcohol in an attempt to improve adhesion.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;window_cleaning.c81d167782d6d237.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;Approach was the same as the sample -- I went slow and carefully ensured each
pattern element released from the transfer cleanly.&lt;&#x2F;p&gt;

&lt;div class=&quot;centered_image&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;blog.npry.dev&amp;#x2F;processed_images&amp;#x2F;window.a4501e5589ff5f82.jpg&quot;&gt;

    
&lt;&#x2F;div&gt;
&lt;p&gt;To my knowledge, I didn&#x27;t lose any of the tiny &lt;em&gt;tehtar&lt;&#x2F;em&gt;, and the
ascenders&#x2F;descenders are in-place mostly unmolested.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design-files&quot;&gt;design files&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.npry.dev&#x2F;class&#x2F;htm&#x2F;vinyl&#x2F;vinyl_design_files.zip&quot;&gt;Here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    
    
    <entry xml:lang="en">
        <title>antrelay</title>
        <published>2023-01-20T00:00:00+00:00</published>
        <updated>2024-08-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            Nathan Perry
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.npry.dev/resenv/antrelay/"/>
        <id>https://blog.npry.dev/resenv/antrelay/</id>
        
        <content type="html" xml:base="https://blog.npry.dev/resenv/antrelay/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;ironman-007.github.io&#x2F;FZ-portfolio&#x2F;astroant.html&quot;&gt;Fangzheng&#x27;s
AstroAnt&lt;&#x2F;a&gt; is going to
the moon:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Aboard &lt;a href=&quot;https:&#x2F;&#x2F;www.lunaroutpost.com&#x2F;rovers&quot;&gt;Lunar Outpost&#x27;s MAPP Rover&lt;&#x2F;a&gt;:
&lt;ul&gt;
&lt;li&gt;Aboard Intuitive Machines&#x27; &lt;a href=&quot;https:&#x2F;&#x2F;www.intuitivemachines.com&#x2F;missions&quot;&gt;IM-2 lander
mission&lt;&#x2F;a&gt;:
&lt;ul&gt;
&lt;li&gt;Launched by a &lt;a href=&quot;https:&#x2F;&#x2F;www.spacex.com&#x2F;vehicles&#x2F;falcon-9&#x2F;&quot;&gt;Falcon 9&lt;&#x2F;a&gt;
near the end of 2024&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I wrote a software payload called &lt;code&gt;antrelay&lt;&#x2F;code&gt; which runs onboard the MAPP-1
rover to control the AstroAnt&#x27;s motion, decode its telemetry downlink, and
ensure recovery from unexpected errors.&lt;&#x2F;p&gt;
&lt;p&gt;Block diagram and more complete descrption forthcoming.&lt;&#x2F;p&gt;
&lt;!-- TODO: block diagram !--&gt;
</content>
        
    </entry>
    
</feed>
