<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://fnune.com/atom.xml" rel="self" type="application/atom+xml" /><link href="https://fnune.com/" rel="alternate" type="text/html" /><updated>2026-06-26T20:31:05+00:00</updated><id>https://fnune.com/atom.xml</id><title type="html">Fausto Núñez Alberro’s blog</title><subtitle>I am a software engineer based in Berlin. I work for Pulumi, where we build developer tools for companies shipping to the cloud. I work across the stack, from frontends to backends, systems engineering, and infrastructure tooling.
</subtitle><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><entry><title type="html">Fausto’s code review process</title><link href="https://fnune.com/collaboration/2025/10/16/faustos-code-review-process/" rel="alternate" type="text/html" title="Fausto’s code review process" /><published>2025-10-16T09:59:00+00:00</published><updated>2025-10-16T09:59:00+00:00</updated><id>https://fnune.com/collaboration/2025/10/16/faustos-code-review-process</id><content type="html" xml:base="https://fnune.com/collaboration/2025/10/16/faustos-code-review-process/"><![CDATA[<h2 id="guiding-principles">Guiding principles</h2>

<h3 id="unblock-the-author">Unblock the author</h3>

<p>My goal in code review is not to be a gatekeeper, but to be a collaborative partner in improving code quality while maintaining team velocity. This process is built on trust. I trust my teammates to make good decisions and address feedback appropriately.</p>

<p>A quick, high-quality code review keeps everyone motivated about their work. It prevents context changes, and it leads to a better team that produces work quicker and in higher quality. I try to review pull requests as soon as possible, without breaking my own context too much, by setting aside time that does not break my day in two: for example, before or after lunch, at the beginning of the day, or at the end. For simple changes, 6 hours is too much time for a pull request to go unreviewed. For complex changes, two days is too much time.</p>

<h3 id="reviews-must-be-actionable">Reviews must be actionable</h3>

<p>Pull request reviews should always give the author a clear next step. It’s not acceptable for a review to open up a broad discussion without explicitly making a decision about whether the pull request should be blocked until the discussion is resolved.</p>

<p>Comments-only reviews without a clear conclusion are not good: I can’t merge because it’s not approved, but I’m also not sure if the comments are blocking. I don’t know what to do. The author is left unsure whether to address feedback, wait for more input, or proceed with merging.</p>

<p>Almost every review I leave will either approve the pull request or request changes. If I lack the context to make that decision, I redirect to someone who can. This ensures the author always knows their next action.</p>

<h2 id="the-process">The process</h2>

<div class="mermaid-frame" style="--mermaid-aspect: 973 / 1391; --mermaid-max-width: 973px">
<pre class="mermaid">
flowchart TD
    Start([PR Ready for Review]) --&gt; Review[Review PR &amp; leave comments]

    Review --&gt; ConfidentCheck{Feel confident to approve or request changes?}

    ConfidentCheck --&gt;|No| Redirect["Tag someone with context 'I don't feel confident to review this properly. Would ask @person to take a look.'"]
    Redirect --&gt; End([Done, waiting for a better reviewer])

    ConfidentCheck --&gt;|Yes| ReReviewCheck{Expect to need re-review after changes?}

    ReReviewCheck --&gt;|No - DEFAULT 95% of cases| ApproveComments[Approve with comments]
    ApproveComments --&gt; AuthorChoice[Author decides: merge now or after fixes]

    ReReviewCheck --&gt;|Yes| RequestChanges[Request changes, used liberally]
    RequestChanges --&gt; ClearComments[Clear communication of what needs fixing: this is now top of my queue to unblock author ASAP, other reviewers can dismiss to override]
    ClearComments --&gt; ReReview[Author fixes, dismisses, or gets another approval]

    AuthorChoice --&gt; Merge([PR can be merged])
    ReReview --&gt; Review

    class Start nodeStart
    class Merge nodeSuccess
    class End nodeDanger
    class ApproveComments nodeApprove
    class RequestChanges nodeWarning
</pre>
</div>

<h3 id="default-action-approve">Default action: approve</h3>

<p>To promote what I believe is a healthy team environment, <strong>I default to approving with comments about 95% of the time</strong>. This signals trust and keeps work flowing. The question isn’t “is this perfect?” but rather “is this good enough to merge, and can any issues be addressed afterward or through normal iteration?”.</p>

<p>To be very clear: I will sometimes approve a pull request even if I think it worsens the quality of the codebase. If I see a structural problem or a pervasive bad practice, I will raise the issue elsewhere and cross-link. I approve even when there are bugs, as long as they’re understood, and the intent of the PR is clear.</p>

<p>Context matters: feature-flagged work that users won’t see yet warrants a lighter touch and faster merging, while changes to public contracts or APIs deserve more thorough consideration given their broader impact.</p>

<h3 id="use-request-changes-liberally">Use request changes liberally</h3>

<p>I only choose request changes when I am sure I will need to come back to the pull request to review it again, because I expect that after the changes it’ll look very different. This might be when the changes are architectural or complex enough that I want to see the implementation, or I have concerns about the approach that need discussion.</p>

<p>“Request changes” is a communication tool: other reviewers can <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/dismissing-a-pull-request-review">dismiss change requests</a> if they have the necessary context, which means I feel comfortable requesting changes in the rare case I believe I need to see the code again after a rework, without fear of becoming a bottleneck. Both requesting changes and dismissing a change request are completely OK given clear and thoughtful communication.</p>

<p>If I request changes, however, I’m <strong>making a commitment to the author</strong>: I communicate clearly what needs to change and why, I prioritize re-reviewing (this goes to the top of my queue), and I unblock the author ASAP once they’ve addressed my concerns.</p>

<h3 id="not-feeling-confident-to-review">Not feeling confident to review?</h3>

<p>If I’m unfamiliar with the codebase area, don’t understand the business requirements, or the PR touches complex systems I haven’t worked with, I redirect to someone with appropriate context. I don’t approve what I can’t properly evaluate. I will nevertheless comment with any thoughts I have, but I will make it clear that I’m not the right person to review.</p>

<h2 id="comment-categories">Comment categories</h2>

<p>To set clear expectations and help authors prioritize feedback, I prefix my comments with one of these labels where applicable:</p>

<h3 id="nit">Nit</h3>

<p>Label: <code class="language-plaintext highlighter-rouge">Nit: </code></p>

<p>Minor nit-picks about style, naming, small improvements, or behavior that don’t critically affect functionality. These are “take it or leave it” suggestions. The weight of my own convictions should not make me lose sight of the main purpose: to unblock the author. A team can align on common preferences, but that should be a separate conversation.</p>

<p>Note: spelling or grammar mistakes visible to users are not labeled as nits, as they’re more like bugs if users will see them.</p>

<p>Examples:</p>

<ul>
  <li>“Nit: this variable could be named <code class="language-plaintext highlighter-rouge">userId</code> instead of <code class="language-plaintext highlighter-rouge">uid</code> for clarity.”</li>
  <li>“Nit: this comment explains what the code below is doing, but it does not say anything about the ‘why’, what do you think about (…).”</li>
</ul>

<h3 id="super-nit">Super-nit</h3>

<p>Label: <code class="language-plaintext highlighter-rouge">Super-nit: </code></p>

<p>Extremely nit-picky comments that are truly optional. I use this for things that are purely personal preference or very minor consistency issues.</p>

<p>Example: “Super-nit: we could use a function that returns this test’s dependencies instead of declaring them at the top as nullable variables and setting them up later”</p>

<h3 id="would-like-to-see--questions">“Would like to see” / questions</h3>

<p>Label: none (use natural phrasing)</p>

<p>Comments that are worth discussing. I may sense that there is an underlying assumption and want to confirm that. Or maybe I have an idea of how something could have been done differently and want to hear the author’s opinion.</p>

<p>Examples:</p>

<ul>
  <li>“Could we add error handling here for the case where the API returns an error?”</li>
  <li>“Question: why did we choose approach X over Y? Just trying to understand the tradeoffs.”</li>
</ul>

<h3 id="off-topic">Off-topic</h3>

<p>Label: <code class="language-plaintext highlighter-rouge">Off-topic: </code></p>

<p>Discussions that are only tangentially related to the PR. I use this for systemic issues, technical debt, or improvements that should happen separately from this PR.</p>

<p>Example: “Off-topic: looks like we could be using a linting rule for X here. We should probably add that to our linter config in a separate PR. I’ve opened an issue here (…), let’s discuss there.”</p>

<h4 id="off-topic-product-decision">Off-topic: product decision</h4>

<p>Label: <code class="language-plaintext highlighter-rouge">Off-topic (product decision): </code></p>

<p>A specific subclass of off-topic for when the code correctly implements a product decision, but you disagree with the underlying product decision itself. The PR author is just implementing what was decided elsewhere, so this shouldn’t block the PR.</p>

<p>Example: “Off-topic (product decision): this feature defaults to opt-in, but I think opt-out would have better adoption. Not a code issue, as the implementation is correct, but worth discussing with the product team separately. I’ve opened a thread about this here (…).”</p>

<p>Tip: for off-topic discussions, especially product decisions, consider opening a Slack thread and cross-linking it with the GitHub comment. This keeps the PR focused while ensuring the discussion happens in the right forum.</p>

<h3 id="logic-issue--bug">Logic issue / bug</h3>

<p>Label: None (be direct and clear)</p>

<p>I use this when I believe the code has a logic error or will produce unexpected behavior. This is not a style issue or architectural preference but I’m flagging that the code won’t work as intended.</p>

<p>I’m clear and specific about what I think will happen versus what should happen. These comments only warrant “request changes” if the bug is not yet understood by both the author and me. I keep in mind that there may be a case of asymmetrical knowledge or I may have misunderstood the intent of the change, in which case it may be worth improving the pull request description or adding explanatory code comments.</p>

<p>Example: “Logic issue: this function returns early when <code class="language-plaintext highlighter-rouge">count === 0</code>, but I think we still need to update the timestamp in that case. As written, zero-count events won’t be tracked.” In this case, I approve anyway.</p>

<h3 id="celebratory--thanks">Celebratory / thanks</h3>

<p>Label: None (be genuine and specific)</p>

<p>I call out clever solutions, good refactoring, thorough testing, or helpful documentation. I thank authors for addressing tricky issues or improving code quality.</p>

<p>Examples:</p>

<ul>
  <li>“This is a really elegant solution to the caching problem!”</li>
  <li>“Thanks for adding those test cases, they caught an edge case I hadn’t thought of”</li>
  <li>“Love how this simplifies the error handling”</li>
</ul>

<h2 id="cross-linking">Cross-linking</h2>

<p>For off-topic discussions, especially those involving product decisions or broader architectural questions, I open a separate thread in the appropriate channel (Slack, the issue tracker, or wherever the team discusses such topics) to discuss the matter there. I always make it clear in my PR comment that it’s non-blocking when moving discussion elsewhere. I post my initial comment on the GitHub PR stating it’s non-blocking, then open a thread in the appropriate channel with context, link to that thread in my GitHub comment, and link back to the GitHub comment from the thread for full context. This keeps the PR focused on the code changes while ensuring important discussions happen in the right forum with the right stakeholders.</p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><category term="collaboration" /><summary type="html"><![CDATA[I try to review code quickly and in a standard manner: my goal is to enable colleagues and improve velocity.]]></summary></entry><entry><title type="html">NixOS on a TUXEDO InfinityBook Pro 14 Gen9 AMD laptop</title><link href="https://fnune.com/hardware/2025/07/20/nixos-on-a-tuxedo-infinitybook-pro-14-gen9-amd/" rel="alternate" type="text/html" title="NixOS on a TUXEDO InfinityBook Pro 14 Gen9 AMD laptop" /><published>2025-07-20T14:47:00+00:00</published><updated>2025-07-20T14:47:00+00:00</updated><id>https://fnune.com/hardware/2025/07/20/nixos-on-a-tuxedo-infinitybook-pro-14-gen9-amd</id><content type="html" xml:base="https://fnune.com/hardware/2025/07/20/nixos-on-a-tuxedo-infinitybook-pro-14-gen9-amd/"><![CDATA[<blockquote>
  <p>I link to TUXEDO a lot in this blog post. These links are not affiliate links, and this post is not sponsored (duh).</p>
</blockquote>

<p><a href="https://www.tuxedocomputers.com/">TUXEDO Computers</a> is a laptop manufacturer based in Augsburg, Germany, who are special to Linux users because they’re one of the few manufacturers developing specifically for Linux.</p>

<p>They ship with their own <a href="https://www.tuxedocomputers.com/en/TUXEDO-OS_1.tuxedo">TUXEDO OS</a>, which comes with KDE Plasma by default. For my new job, I actually wanted a Framework laptop with an AMD chip, but they were temporarily out of stock so I opted for a TUXEDO laptop, which would have been my second choice. I picked <a href="https://www.tuxedocomputers.com/en/TUXEDO-InfinityBook-Pro-14-Gen9-AMD.tuxedo">their TUXEDO InfinityBook Pro 14 Gen9 AMD model</a>.</p>

<p>In this blog post, I’ll go over how I set up my NixOS computer to work on this TUXEDO laptop. NixOS is <a href="https://www.tuxedocomputers.com/en/TUXEDO-Support-Guidelines.tuxedo"><strong>not among the supported operating systems</strong></a>, so I was expecting having to do some digging.</p>

<h2 id="the-result">The result</h2>

<p>Here are the changes you’d need to make. I’d recommend reading the rest of the post to understand some trade-offs.</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
  <span class="nv">pkgs</span><span class="p">,</span>
  <span class="nv">config</span><span class="p">,</span>
  <span class="o">...</span>
<span class="p">}:</span> <span class="p">{</span>
  <span class="nv">boot</span> <span class="o">=</span> <span class="p">{</span>
    <span class="c"># Motorcomm YT6801 LAN drivers</span>
    <span class="nv">extraModulePackages</span> <span class="o">=</span> <span class="kn">with</span> <span class="nv">config</span><span class="o">.</span><span class="nv">boot</span><span class="o">.</span><span class="nv">kernelPackages</span><span class="p">;</span> <span class="p">[</span><span class="nv">yt6801</span><span class="p">];</span>
    <span class="nv">kernelParams</span> <span class="o">=</span> <span class="p">[</span>
      <span class="s2">"acpi.ec_no_wakeup=1"</span> <span class="c"># Fixes ACPI wakeup issues</span>
      <span class="s2">"amdgpu.dcdebugmask=0x10"</span> <span class="c"># Fixes Wayland slowdowns/freezes</span>
    <span class="p">];</span>
  <span class="p">};</span>

  <span class="c"># Requires a system module from this flake:</span>
  <span class="c"># https://github.com/sund3RRR/tuxedo-nixos?tab=readme-ov-file#option-2-nix-flake</span>
  <span class="nv">hardware</span> <span class="o">=</span> <span class="p">{</span>
    <span class="nv">tuxedo-drivers</span><span class="o">.</span><span class="nv">enable</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="nv">tuxedo-control-center</span><span class="o">.</span><span class="nv">enable</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
  <span class="p">};</span>

  <span class="c"># Let TUXEDO Control Center handle CPU frequencies</span>
  <span class="nv">services</span><span class="o">.</span><span class="nv">power-profiles-daemon</span><span class="o">.</span><span class="nv">enable</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Include these changes in your <code class="language-plaintext highlighter-rouge">/etc/nixos/configuration.nix</code> in some way. In my case, I use <a href="https://github.com/fnune/home.nix/blob/main/flake.nix#L60">a system flake</a> that includes <a href="https://github.com/fnune/home.nix/blob/main/os/configuration.melian.nix">a laptop-specific configuration module</a>.</p>

<h2 id="drivers-and-the-tuxedo-control-center">Drivers and the TUXEDO Control Center</h2>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Requires a system module from this flake:</span>
<span class="c"># https://github.com/sund3RRR/tuxedo-nixos?tab=readme-ov-file#option-2-nix-flake</span>
<span class="nv">hardware</span> <span class="o">=</span> <span class="p">{</span>
  <span class="nv">tuxedo-drivers</span><span class="o">.</span><span class="nv">enable</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
  <span class="nv">tuxedo-control-center</span><span class="o">.</span><span class="nv">enable</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>The NixOS Wiki has <a href="https://nixos.wiki/wiki/TUXEDO_Devices">an article on TUXEDO devices</a>. It points at the fact that, as of July 2025, there is no package in <code class="language-plaintext highlighter-rouge">nixpkgs</code> that can install the official TUXEDO Control Center. It looks like the reasons include implementation attempts including <a href="https://github.com/sund3RRR/tuxedo-nixos/blob/master/pkgs/tuxedo-control-center/node-packages.nix">thousands of generated Nix code to declare the dependencies of the Angular frontend</a>, and the frontend requiring Electron 11, which was <a href="https://www.electronjs.org/blog/electron-11-0">released in 2020</a> and is deemed ancient. It also points at a community flake that has been abandoned, and that makes this module available outside of <code class="language-plaintext highlighter-rouge">nixpkgs</code>.</p>

<p>The other option suggested by the Wiki is to use <a href="https://github.com/AaronErhardt/tuxedo-rs"><code class="language-plaintext highlighter-rouge">tuxedo-rs</code></a>, which exists because “TCC and its tccd service rely on Node.js which makes it slow, memory hungry and hard to package”. I agree in principle, but it lacks certain features that I found useful in the TUXEDO Control Center:</p>

<ul>
  <li>A system tray applet that lets me manually select a power profile (<code class="language-plaintext highlighter-rouge">tuxedo-rs</code> has a small GTK application but no system tray applet)</li>
  <li>An option to select which profile should activate when my laptop is plugged to electricity or working off of battery</li>
</ul>

<p>So, even though I don’t love going with a community flake for such a critical feature of my laptop, I went for the TUXEDO Control Center option, and I found this flake which is alive: <a href="https://github.com/sund3RRR/tuxedo-nixos"><code class="language-plaintext highlighter-rouge">sund3RRR/tuxedo-nixos</code></a>. Thanks <code class="language-plaintext highlighter-rouge">sund3RRR</code>!</p>

<h2 id="getting-ethernet-to-work">Getting Ethernet to work</h2>

<p>Although I’d enabled <code class="language-plaintext highlighter-rouge">hardware.tuxedo-drivers</code>, my Ethernet port was still not working. After some digging, I found that I needed to enable a driver for it:</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">boot</span> <span class="o">=</span> <span class="p">{</span>
  <span class="c"># Motorcomm YT6801 LAN drivers</span>
  <span class="nv">extraModulePackages</span> <span class="o">=</span> <span class="kn">with</span> <span class="nv">config</span><span class="o">.</span><span class="nv">boot</span><span class="o">.</span><span class="nv">kernelPackages</span><span class="p">;</span> <span class="p">[</span><span class="nv">yt6801</span><span class="p">];</span>
<span class="p">};</span>
</code></pre></div></div>

<p>This is, in fact, mentioned in <a href="https://www.tuxedocomputers.com/en/FAQ-TUXEDO-InfinityBook-Pro-14-Gen9-AMD.tuxedo">the TUXEDO FAQ for this laptop</a>, but at this point I had not read this resource yet.</p>

<h2 id="fixing-laptop-wake-ups-while-shut">Fixing laptop wake-ups while shut</h2>

<p>While shut, the laptop would wake up and spin the fans periodically. This was very annoying. To solve this one, I messaged their support. They were very welcoming to my question even though it was related to an unsupported OS, and advised that I add these two kernel parameters:</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">kernelParams</span> <span class="o">=</span> <span class="p">[</span>
  <span class="s2">"acpi.ec_no_wakeup=1"</span> <span class="c"># Fixes ACPI wakeup issues</span>
  <span class="s2">"amdgpu.dcdebugmask=0x10"</span> <span class="c"># Fixes Wayland slowdowns/freezes</span>
<span class="p">];</span>
</code></pre></div></div>

<p>I have not tested the second one, but rebooting after adding <code class="language-plaintext highlighter-rouge">acpi.ec_no_wakeup=1</code> proved that it solved the random wake-ups.</p>

<p>The <code class="language-plaintext highlighter-rouge">acpi.ec_no_wakeup=1</code> param <a href="https://www.tuxedocomputers.com/en/FAQ-TUXEDO-InfinityBook-Pro-14-Gen9-AMD.tuxedo">was also mentioned in their FAQ</a>. Oops…</p>

<h2 id="powerdevil-vs-tuxedo-control-center">PowerDevil vs. TUXEDO Control Center</h2>

<p>The addition of TUXEDO Control Center left me confused as to which widget to use to manage CPU frequencies and governors. KDE Plasma’s PowerDevil provides integration, such as a slider under the system tray battery icon, and (as of recently) the battery icon changes to indicate which power profile is in use.</p>

<p>Changing the profile using TUXEDO Control Center does not reflect in a change in the KDE Plasma widget, so <del>Claude wrote</del> I wrote a script to monitor different system properties as I changed the TUXEDO Control Center and KDE Plasma options:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="k">while </span><span class="nb">true</span><span class="p">;</span> <span class="k">do
  </span><span class="nv">freq</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 2&gt;/dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"0"</span><span class="si">)</span>
  <span class="nv">min_freq</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq 2&gt;/dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"0"</span><span class="si">)</span>
  <span class="nv">max_freq</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 2&gt;/dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"0"</span><span class="si">)</span>
  <span class="nv">gov</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2&gt;/dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"N/A"</span><span class="si">)</span>
  <span class="nv">epp</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference 2&gt;/dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"N/A"</span><span class="si">)</span>
  <span class="nv">boost</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> /sys/devices/system/cpu/cpufreq/boost 2&gt;/dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"N/A"</span><span class="si">)</span>

  <span class="nb">printf</span> <span class="s2">"%s | %-10s | %-9s | %-12s | %-14s | %s</span><span class="se">\n</span><span class="s2">"</span> <span class="se">\</span>
    <span class="s2">"</span><span class="si">$(</span><span class="nb">date</span> +%H:%M:%S<span class="si">)</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$gov</span><span class="s2">"</span> <span class="s2">"</span><span class="k">$((</span>freq <span class="o">/</span> <span class="m">1000</span><span class="k">))</span><span class="s2">"</span> <span class="s2">"</span><span class="k">$((</span>min_freq <span class="o">/</span> <span class="m">1000</span><span class="k">))</span><span class="s2">-</span><span class="k">$((</span>max_freq <span class="o">/</span> <span class="m">1000</span><span class="k">))</span><span class="s2">"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">epp</span>:0:14<span class="k">}</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$boost</span><span class="s2">"</span>
  <span class="nb">sleep </span>1
<span class="k">done</span>
</code></pre></div></div>

<p>Here’s a log of what was happening. I’ve redacted away a lot of lines so that you can see just the changes:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1: TCC set to TUXEDO Defaults
 2: Plasma widget set to power saver
 3: 15:27:37 | powersave  | 1559  | 400-3801  | balance_perfor | 1
 4:
 5: TCC changed from TUXEDO Defaults to "Default" (I believe no change)
 6: 15:27:55 | powersave  | 2452  | 400-3801  | balance_perfor | 1
 7:
 8: TCC changed from "Default" to "Cool and breezy"
 9: 15:28:03 | powersave  | 1459  | 400-1900  | balance_perfor | 1
10:
11: TCC changed from "Cool and breezy" to "Powersaver extreme"
12: 15:28:08 | powersave  | 548   | 400-400   | balance_perfor | 1
13:
14: TCC changed from "Powersaver extreme" to "TUXEDO Defaults"
15: 15:28:25 | powersave  | 1297  | 400-3801  | balance_perfor | 1
16:
17: Plasma widget from power saver to balanced
18: 15:28:30 | powersave  | 1098  | 1098-3801 | balance_power  | 1
19: 15:28:35 | powersave  | 1540  | 400-5137  | balance_perfor | 1
20:
21: Plasma widget from balanced to performance
22: 15:28:44 | performance | 1098 | 1098-5137 | performance    | 1
23: 15:28:52 | powersave   | 1331 | 400-5137  | balance_perfor | 1
</code></pre></div></div>

<p>The interesting bits here are that both are apparently ultimately modifying the minimum and maximum CPU frequencies. They probably do this through different means, and I’m not an expert here, but I believe what’s happening is that KDE Plasma is talking to <code class="language-plaintext highlighter-rouge">power-profiles-daemon</code> and setting a set of preferences (governor to <code class="language-plaintext highlighter-rouge">powersave</code>, energy performance preference (EPP) to <code class="language-plaintext highlighter-rouge">balance_performance</code>), and that results in something lower-level updating the minimum and maximum CPU frequencies.</p>

<p>You’ll notice that in the two last changes, where I’m using the KDE Plasma widget, I included two log lines per change. It looks like TUXEDO Control Center is periodically monitoring the value of these settings and correcting them to what it wants:</p>

<ul>
  <li>Governor set to <code class="language-plaintext highlighter-rouge">performance</code>: corrected to <code class="language-plaintext highlighter-rouge">powersave</code> after a few seconds</li>
  <li>EPP set to <code class="language-plaintext highlighter-rouge">performance</code>: corrected to <code class="language-plaintext highlighter-rouge">balance_performance</code> after a few seconds</li>
</ul>

<p>I also did not like that the maximum CPU frequency would be set to <code class="language-plaintext highlighter-rouge">3801</code> or <code class="language-plaintext highlighter-rouge">5137</code> depending on which KDE Plasma option was picked last. TUXEDO Control Center tries to update things back to TUXEDO Defaults (which has a max of <code class="language-plaintext highlighter-rouge">5137</code>) but only manages <code class="language-plaintext highlighter-rouge">3801</code>, and I believe this is because the selected KDE Plasma option was <code class="language-plaintext highlighter-rouge">powersave</code>.</p>

<p>After seeing all of these interactions (or interruptions) I decided to use the TUXEDO Control Center exclusively:</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Let TUXEDO Control Center handle CPU frequencies</span>
<span class="nv">services</span><span class="o">.</span><span class="nv">power-profiles-daemon</span><span class="o">.</span><span class="nv">enable</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</code></pre></div></div>

<p>I lose the KDE Plasma integration with the battery widget, but that’s OK.</p>

<h2 id="remaining-annoyances">Remaining annoyances</h2>

<p>There are just a couple of remaining nit-picks.</p>

<p>On boot, I get some ACPI-related warnings à la:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[    0.305246] ACPI BIOS Error (bug): Failure creating named object [\_SB.PCI0.GPP6.WLAN._DSM], AE_ALREADY_EXISTS (20240827/dswload2-326)
</code></pre></div></div>

<p>These seem innocuous. I contacted TUXEDO to see what could be done, and they mentioned they’d <a href="https://www.tuxedocomputers.com/en/Infos/Help-Support/Frequently-asked-questions/ACPI-Error-Reports.tuxedo">updated their FAQ to mention that these messages do not affect operation</a>.</p>

<p>The other thing is that when the laptop wakes from sleep, the fans spin at full speed for a couple of seconds. I have a hunch that this is default behavior, and wanted, but it would be lovely if the laptop were quieter when opening the lid.</p>

<h2 id="thoughts">Thoughts</h2>

<p>Altogether, NixOS has had me fight a lot more fights than I would have fought on another distribution. I’ve been learning a lot, but I begin to question whether the benefits are worth the effort. I have had trouble setting up, for example, <a href="https://github.com/fnune/home.nix/blob/main/packages/vanta.nix">Vanta</a> for work (a compliance monitoring agent), <a href="https://github.com/search?q=repo%3Afnune%2Fhome.nix+playwright&amp;type=commits">Playwright</a> for browser end-to-end tests, and I simply cannot run some software unless I make the effort of packaging it for Nix and NixOS, for example <a href="https://github.com/NixOS/nixpkgs/pull/425755">using KWallet as a <code class="language-plaintext highlighter-rouge">pinentry</code> program</a> or <a href="https://github.com/TablePlus/TablePlus-Linux/issues/122#issuecomment-2499906970">installing a database client I’d like to try out</a>.</p>

<p>With the <a href="https://www.debian.org/releases/trixie/releasenotes">release of Debian 13 Trixie</a> looming, I may try to move my setup to a Debian stable base and keep most of my Home Manager setup so that I can use Nix for anything that’s not my basic system, while still enjoying the mainstream support provided by Debian. We’ll see!</p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><category term="hardware" /><summary type="html"><![CDATA[Setting up NixOS on a TUXEDO InfinityBook Pro 14 Gen9 AMD laptop, including driver configuration, power management, and troubleshooting common issues.]]></summary></entry><entry><title type="html">TypeScript – Record and the satisfies operator</title><link href="https://fnune.com/typescript/2022/11/15/typescript-series-5-record-and-the-satisfies-operator/" rel="alternate" type="text/html" title="TypeScript – Record and the satisfies operator" /><published>2022-11-15T19:16:00+00:00</published><updated>2022-11-15T19:16:00+00:00</updated><id>https://fnune.com/typescript/2022/11/15/typescript-series-5-record-and-the-satisfies-operator</id><content type="html" xml:base="https://fnune.com/typescript/2022/11/15/typescript-series-5-record-and-the-satisfies-operator/"><![CDATA[<blockquote>
    <p>
      This post is part of an ongoing series on TypeScript. In it, I try to explain in a detailed way
      different situations I've faced while building relatively big React applications using TypeScript,
      and moving them from JavaScript. Here's a list of other posts I've written about TypeScript:
    </p>
    <ul>
      
        
      
        
          <li>
            <a href="/typescript/2020/07/31/typescript-series-4-poor-mans-async-await-in-typescript-using-generators/">
              <span>TypeScript – Poor man's async await using generators</span>
            </a>
            <span> · </span>
            <time datetime="2020-07-31T15:37:25+00:00">July 31, 2020</time>
          </li>
        
      
        
          <li>
            <a href="/typescript/2019/08/12/typescript-series-3-structuring-type-dependencies-in-frontend-applications/">
              <span>TypeScript – Structuring type dependencies in frontend applications</span>
            </a>
            <span> · </span>
            <time datetime="2019-08-12T17:55:00+00:00">August 12, 2019</time>
          </li>
        
      
        
          <li>
            <a href="/typescript/2019/02/27/typescript-series-2-beware-the-type-guards/">
              <span>TypeScript – Beware the user-defined type guards</span>
            </a>
            <span> · </span>
            <time datetime="2019-02-27T16:15:00+00:00">February 27, 2019</time>
          </li>
        
      
        
          <li>
            <a href="/typescript/2019/01/30/typescript-series-1-record-is-usually-not-the-best-choice/">
              <span>TypeScript – Using Record is usually not the best choice</span>
            </a>
            <span> · </span>
            <time datetime="2019-01-30T09:03:00+00:00">January 30, 2019</time>
          </li>
        
      
    </ul>
  </blockquote>

<p>In a previous entry I argued that <a href="/typescript/2019/01/30/typescript-series-1-record-is-usually-not-the-best-choice/">the use of the <code class="language-plaintext highlighter-rouge">Record</code> type is dangerous</a> in some circumstances and suggested using a <code class="language-plaintext highlighter-rouge">Dictionary</code> type to solve that. The goal of the <code class="language-plaintext highlighter-rouge">Dictionary</code> type is to make sure the type of values from property access returns <code class="language-plaintext highlighter-rouge">T | undefined</code> as opposed to just <code class="language-plaintext highlighter-rouge">T</code> (which would suggest that we have a <code class="language-plaintext highlighter-rouge">T</code> for any <code class="language-plaintext highlighter-rouge">K</code> in the dictionary).</p>

<p><a href="https://devblogs.microsoft.com/typescript/announcing-typescript-4-9/">The release of TypeScript 4.9</a> includes a new operator called <code class="language-plaintext highlighter-rouge">satisfies</code>. It can be used to solve the situation I presented in that other post:</p>

<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">type</span> <span class="nx">Breed</span> <span class="o">=</span> <span class="kr">string</span>

<span class="kr">interface</span> <span class="nx">Dog</span> <span class="p">{</span>
  <span class="nl">name</span><span class="p">:</span> <span class="kr">string</span>
<span class="p">}</span>

<span class="kd">const</span> <span class="nx">dogsByBreed</span><span class="p">:</span> <span class="nb">Record</span><span class="o">&lt;</span><span class="nx">Breed</span><span class="p">,</span> <span class="nx">Dog</span><span class="p">[]</span><span class="o">&gt;</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">akita</span><span class="p">:</span> <span class="p">[{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Walter</span><span class="dl">'</span> <span class="p">},</span> <span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Gracie</span><span class="dl">'</span> <span class="p">}],</span>
  <span class="na">dachshund</span><span class="p">:</span> <span class="p">[{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Charlie</span><span class="dl">'</span> <span class="p">}],</span>
<span class="p">}</span>

<span class="nx">dogsByBreed</span><span class="p">.</span><span class="nx">poodle</span> <span class="c1">// Type is Dog[], value is undefined.</span>
</code></pre></div></div>

<p>Instead of introducing a <code class="language-plaintext highlighter-rouge">Dictionary</code> type, you can now simply do this:</p>

<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">dogsByBreed</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">akita</span><span class="p">:</span> <span class="p">[{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Walter</span><span class="dl">'</span> <span class="p">},</span> <span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Gracie</span><span class="dl">'</span> <span class="p">}],</span>
  <span class="na">dachshund</span><span class="p">:</span> <span class="p">[{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Charlie</span><span class="dl">'</span> <span class="p">}],</span>
<span class="p">}</span> <span class="kd">satisfies </span><span class="nb">Record</span><span class="o">&lt;</span><span class="nx">Breed</span><span class="p">,</span> <span class="nx">Dog</span><span class="p">[]</span><span class="o">&gt;</span>

<span class="nx">dogsByBreed</span><span class="p">.</span><span class="nx">poodle</span> <span class="c1">// Type error!</span>
</code></pre></div></div>

<p>TypeScript gives us a static type-check with the message:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Property 'poodle' does not exist on type '{ akita: { name: string; }[]; dachshund: { name: string; }[]; }'.
</code></pre></div></div>

<p>Which is absolutely correct and gives us the best of both worlds:</p>

<ul>
  <li>We made sure that <code class="language-plaintext highlighter-rouge">dogsByBreed</code> satisfies our <code class="language-plaintext highlighter-rouge">Record&lt;Breed, Dog[]&gt;</code> constraint.</li>
  <li>We lost no type information at all about the <code class="language-plaintext highlighter-rouge">dogsByBreed</code> variable, and TypeScript was able to tell us that <code class="language-plaintext highlighter-rouge">poodle</code> is not one of its keys.</li>
</ul>

<p>I’m happy to be able to update the previous post to link to this one. Until next time!</p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><category term="typescript" /><summary type="html"><![CDATA[TypeScript 4.9 introduces the satisfies operator. It can be used together with the Record type to solve a problem I posted about some years ago.]]></summary></entry><entry><title type="html">Learning about program execution in Linux from the output of strace</title><link href="https://fnune.com/2022/09/17/learning-about-program-execution-in-linux-from-the-output-of-strace/" rel="alternate" type="text/html" title="Learning about program execution in Linux from the output of strace" /><published>2022-09-17T15:13:51+00:00</published><updated>2022-09-17T15:13:51+00:00</updated><id>https://fnune.com/2022/09/17/learning-about-program-execution-in-linux-from-the-output-of-strace</id><content type="html" xml:base="https://fnune.com/2022/09/17/learning-about-program-execution-in-linux-from-the-output-of-strace/"><![CDATA[<!-- Excalidraw link: https://excalidraw.com/#room=7fc1d184366e00caefa8,5GwLrhjOzsbXm3yWHyZEyw -->

<p>I recently started reading Michael Kerrisk’s <a href="https://man7.org/tlpi/">The Linux Programming Interface</a>. So far, I’ve been enjoying it thoroughly. Inspired by it, I took a look at what <code class="language-plaintext highlighter-rouge">strace</code> outputs for a very simple “hello world” program, with the hopes of understanding what’s in it.</p>

<p>Relatively early in the book, Kerrisk introduces the concept of system calls:</p>

<blockquote>
  <p>A <em>system call</em> is a controlled entry point into the kernel, allowing a process to request that the kernel perform some action on the process’s behalf. The kernel makes a range of services accessible to programs via the system call application programming interface (API). These services include, for example, creatig a new process, performing I/O, and creating a pipe for interprocess communication. (The <em>syscalls(2)</em> manual page lists the Linux system calls.)</p>
</blockquote>

<p>The <code class="language-plaintext highlighter-rouge">strace</code> program traces system calls and signals, and can attach to a running process or be specified a command to run. In this exercise, I’m going to write a simple “hello world” program in C and run <code class="language-plaintext highlighter-rouge">strace</code> with the compiled output.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Hello world!"</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I compile it with GCC:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gcc <span class="nt">-o</span> hello.out ./hello.c
</code></pre></div></div>

<p>Now we can run it like so:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./hello.out
Hello world!%
</code></pre></div></div>

<p>Let’s take a first look at the output of <code class="language-plaintext highlighter-rouge">strace</code> without any special flags:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>strace ./hello.out
execve<span class="o">(</span><span class="s2">"./hello.out"</span>, <span class="o">[</span><span class="s2">"./hello.out"</span><span class="o">]</span>, 0x7fffcc590420 /<span class="k">*</span> 113 vars <span class="k">*</span>/<span class="o">)</span> <span class="o">=</span> 0
brk<span class="o">(</span>NULL<span class="o">)</span>                               <span class="o">=</span> 0x55f7df1ee000
arch_prctl<span class="o">(</span>0x3001 /<span class="k">*</span> ARCH_??? <span class="k">*</span>/, 0x7fff59ff3fe0<span class="o">)</span> <span class="o">=</span> <span class="nt">-1</span> EINVAL <span class="o">(</span>Invalid argument<span class="o">)</span>
access<span class="o">(</span><span class="s2">"/etc/ld.so.preload"</span>, R_OK<span class="o">)</span>      <span class="o">=</span> <span class="nt">-1</span> ENOENT <span class="o">(</span>No such file or directory<span class="o">)</span>
openat<span class="o">(</span>AT_FDCWD, <span class="s2">"/etc/ld.so.cache"</span>, O_RDONLY|O_CLOEXEC<span class="o">)</span> <span class="o">=</span> 3
newfstatat<span class="o">(</span>3, <span class="s2">""</span>, <span class="o">{</span><span class="nv">st_mode</span><span class="o">=</span>S_IFREG|0644, <span class="nv">st_size</span><span class="o">=</span>75074, ...<span class="o">}</span>, AT_EMPTY_PATH<span class="o">)</span> <span class="o">=</span> 0
mmap<span class="o">(</span>NULL, 75074, PROT_READ, MAP_PRIVATE, 3, 0<span class="o">)</span> <span class="o">=</span> 0x7fba4a414000
close<span class="o">(</span>3<span class="o">)</span>                                <span class="o">=</span> 0
openat<span class="o">(</span>AT_FDCWD, <span class="s2">"/lib/x86_64-linux-gnu/libc.so.6"</span>, O_RDONLY|O_CLOEXEC<span class="o">)</span> <span class="o">=</span> 3
<span class="nb">read</span><span class="o">(</span>3, <span class="s2">"</span><span class="se">\1</span><span class="s2">77ELF</span><span class="se">\2\1\1\3\0\0\0\0\0\0\0\0\3\0</span><span class="s2">&gt;</span><span class="se">\0\1\0\0\0\2</span><span class="s2">40</span><span class="se">\2</span><span class="s2">06</span><span class="se">\2\0\0\0\0\0</span><span class="s2">"</span>..., 832<span class="o">)</span> <span class="o">=</span> 832
pread64<span class="o">(</span>3, <span class="s2">"</span><span class="se">\6\0\0\0\4\0\0\0</span><span class="s2">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s2">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s2">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s2">"</span>..., 784, 64<span class="o">)</span> <span class="o">=</span> 784
pread64<span class="o">(</span>3, <span class="s2">"</span><span class="se">\4\0\0\0</span><span class="s2"> </span><span class="se">\0\0\0\5\0\0\0</span><span class="s2">GNU</span><span class="se">\0\2\0\0\3</span><span class="s2">00</span><span class="se">\4\0\0\0\3\0\0\0\0\0\0\0</span><span class="s2">"</span>..., 48, 848<span class="o">)</span> <span class="o">=</span> 48
pread64<span class="o">(</span>3, <span class="s2">"</span><span class="se">\4\0\0\0\2</span><span class="s2">4</span><span class="se">\0\0\0\3\0\0\0</span><span class="s2">GNU</span><span class="se">\0</span><span class="s2">+H)</span><span class="se">\2</span><span class="s2">27</span><span class="se">\2</span><span class="s2">01T</span><span class="se">\2</span><span class="s2">14</span><span class="se">\2</span><span class="s2">33</span><span class="se">\3</span><span class="s2">04R</span><span class="se">\3</span><span class="s2">52</span><span class="se">\3</span><span class="s2">06</span><span class="se">\3</span><span class="s2">379</span><span class="se">\2</span><span class="s2">20%"</span>..., 68, 896<span class="o">)</span> <span class="o">=</span> 68
newfstatat<span class="o">(</span>3, <span class="s2">""</span>, <span class="o">{</span><span class="nv">st_mode</span><span class="o">=</span>S_IFREG|0755, <span class="nv">st_size</span><span class="o">=</span>1983576, ...<span class="o">}</span>, AT_EMPTY_PATH<span class="o">)</span> <span class="o">=</span> 0
mmap<span class="o">(</span>NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, <span class="nt">-1</span>, 0<span class="o">)</span> <span class="o">=</span> 0x7fba4a412000
pread64<span class="o">(</span>3, <span class="s2">"</span><span class="se">\6\0\0\0\4\0\0\0</span><span class="s2">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s2">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s2">@</span><span class="se">\0\0\0\0\0\0\0</span><span class="s2">"</span>..., 784, 64<span class="o">)</span> <span class="o">=</span> 784
mmap<span class="o">(</span>NULL, 2012056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0<span class="o">)</span> <span class="o">=</span> 0x7fba4a226000
mmap<span class="o">(</span>0x7fba4a24c000, 1486848, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000<span class="o">)</span> <span class="o">=</span> 0x7fba4a24c000
mmap<span class="o">(</span>0x7fba4a3b7000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x191000<span class="o">)</span> <span class="o">=</span> 0x7fba4a3b7000
mmap<span class="o">(</span>0x7fba4a403000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1dc000<span class="o">)</span> <span class="o">=</span> 0x7fba4a403000
mmap<span class="o">(</span>0x7fba4a409000, 33688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, <span class="nt">-1</span>, 0<span class="o">)</span> <span class="o">=</span> 0x7fba4a409000
close<span class="o">(</span>3<span class="o">)</span>                                <span class="o">=</span> 0
mmap<span class="o">(</span>NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, <span class="nt">-1</span>, 0<span class="o">)</span> <span class="o">=</span> 0x7fba4a224000
arch_prctl<span class="o">(</span>ARCH_SET_FS, 0x7fba4a413580<span class="o">)</span> <span class="o">=</span> 0
mprotect<span class="o">(</span>0x7fba4a403000, 12288, PROT_READ<span class="o">)</span> <span class="o">=</span> 0
mprotect<span class="o">(</span>0x55f7dd843000, 4096, PROT_READ<span class="o">)</span> <span class="o">=</span> 0
mprotect<span class="o">(</span>0x7fba4a45f000, 8192, PROT_READ<span class="o">)</span> <span class="o">=</span> 0
munmap<span class="o">(</span>0x7fba4a414000, 75074<span class="o">)</span>           <span class="o">=</span> 0
newfstatat<span class="o">(</span>1, <span class="s2">""</span>, <span class="o">{</span><span class="nv">st_mode</span><span class="o">=</span>S_IFCHR|0620, <span class="nv">st_rdev</span><span class="o">=</span>makedev<span class="o">(</span>0x88, 0x1<span class="o">)</span>, ...<span class="o">}</span>, AT_EMPTY_PATH<span class="o">)</span> <span class="o">=</span> 0
brk<span class="o">(</span>NULL<span class="o">)</span>                               <span class="o">=</span> 0x55f7df1ee000
brk<span class="o">(</span>0x55f7df20f000<span class="o">)</span>                     <span class="o">=</span> 0x55f7df20f000
write<span class="o">(</span>1, <span class="s2">"Hello world!"</span>, 12<span class="o">)</span>            <span class="o">=</span> 12
exit_group<span class="o">(</span>0<span class="o">)</span>                           <span class="o">=</span> ?
+++ exited with 0 +++
</code></pre></div></div>

<p>At first, I’m surprised that there are so many system calls for such a simple program. The system calls executed the most were <code class="language-plaintext highlighter-rouge">mmap</code> (8 times) and <code class="language-plaintext highlighter-rouge">pread64</code> (4 times).</p>

<p>Output from <code class="language-plaintext highlighter-rouge">strace</code> (prior to the use of any flags) is in the format:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>syscall<span class="o">(</span>...arguments<span class="o">)</span> <span class="o">=</span> return_value
</code></pre></div></div>

<p>The first lines are about loading our program for execution, so let’s take a look at that!</p>

<h2 id="initializing-program-execution-execve">Initializing program execution: <code class="language-plaintext highlighter-rouge">execve</code></h2>

<p>The first system call <code class="language-plaintext highlighter-rouge">execve</code> executes our program, whose executable can be found at its first argument <code class="language-plaintext highlighter-rouge">pathname</code>, and indicates some additional info:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#        pathname       arguments        &amp;env[]            env[].length</span>
1 execve<span class="o">(</span><span class="s2">"./hello.out"</span>, <span class="o">[</span><span class="s2">"./hello.out"</span><span class="o">]</span>, 0x7fffcc590420 /<span class="k">*</span> 113 vars <span class="k">*</span>/<span class="o">)</span> <span class="o">=</span> 0
</code></pre></div></div>

<p>In the arguments array, the first is simply the name of the program, and I didn’t pass any more arguments. By default, only a pointer to the environment variables array is printed, together with a number indicating how many environment variables are defined. The <code class="language-plaintext highlighter-rouge">strace</code> flag <code class="language-plaintext highlighter-rouge">-v</code> makes the output verbose by dereferencing pointers such as the one for <code class="language-plaintext highlighter-rouge">env[]</code>, and <code class="language-plaintext highlighter-rouge">-s</code> lets us set the maximum length of the string representation of these values.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>strace <span class="nt">-s</span> 10000 <span class="nt">-v</span> ./hello.out
execve<span class="o">(</span><span class="s2">"./hello.out"</span>, <span class="o">[</span><span class="s2">"./hello.out"</span><span class="o">]</span>, <span class="o">[</span><span class="s2">"ENV_VAR_1=VALUE"</span>, <span class="s2">"ENV_VAR_2=VALUE"</span><span class="o">])</span> <span class="o">=</span> 0
...
</code></pre></div></div>

<p>So what exactly is meant by “executes our program”? The <code class="language-plaintext highlighter-rouge">man</code> page for <code class="language-plaintext highlighter-rouge">execve</code> states the following:</p>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">execve()</code> executes the program referred to by pathname. This causes the program that is currently being run by the calling process to be replaced with a new program, with newly initialized stack, heap, and (initial‐ ized and uninitialized) data segments.</p>
</blockquote>

<p>This leaves us with the question: which currently-running program is <code class="language-plaintext highlighter-rouge">execve</code> replacing? I called <code class="language-plaintext highlighter-rouge">./hello.out</code> from a shell. Presumably, if my program were to substitute the shell process, then I wouldn’t have a shell to come back to when my program ends, and the terminal would exit.</p>

<h2 id="creating-a-child-process-fork">Creating a child process: <code class="language-plaintext highlighter-rouge">fork</code></h2>

<p>Programs in Linux are executed by means of a mechanism called <a href="https://en.wikipedia.org/wiki/Fork%E2%80%93exec">fork-exec</a>. The <code class="language-plaintext highlighter-rouge">fork</code> system call creates a child process by duplicating the calling process.</p>

<svg class="excalidraw" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 487.21050049662585 411.74482531780495" width="487.21050049662585" height="411.74482531780495">
  <!-- svg-source:excalidraw -->

  <defs>
    <style>
      @font-face {
        font-family: "Virgil";
        src: url("https://excalidraw.com/Virgil.woff2");
      }
      @font-face {
        font-family: "Cascadia";
        src: url("https://excalidraw.com/Cascadia.woff2");
      }
    </style>
  </defs>
  <rect x="0" y="0" width="487.21050049662585" height="411.74482531780495" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(11 42.5) rotate(0 87.5 53)"><path d="M1.09 -0.84 C63.65 2.29, 123.33 2.73, 172.88 -2.11 M0.06 -1.72 C45.38 -2.54, 91.11 -0.71, 176.63 0.61 M174.9 -3.1 C175.23 36.27, 172.16 70.1, 175.32 102.24 M174.03 -0.17 C176.06 24.04, 172.76 49.45, 175.73 104.01 M175.71 109.43 C133.15 103.89, 84.24 105.46, -3.62 103.94 M175.91 106.69 C133.53 103.56, 92.84 105.6, -1.86 107.17 M-2.87 104.76 C-0.01 74.12, -1.81 33.96, -2.56 3.46 M-1.5 104.69 C0.78 85.86, -1.93 61.79, -1.84 -0.7" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(218.5 42.5) rotate(0 87.5 52.5)"><path d="M0.67 -0.77 C62.27 -2.52, 124.98 -6.12, 174.01 1.09 M177.61 1.87 C174.61 27.19, 175.05 59.36, 178.05 105.12 M176.59 108.91 C140.81 106.44, 101.63 106.45, 1.31 104.9 M-3.49 103.43 C0.54 77.89, -2.25 56.89, 3.04 -1.93" stroke="#000000" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g transform="translate(15 10) rotate(0 63 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">shell process</text></g><g transform="translate(225 11.5) rotate(0 104 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">copy of shell process</text></g><g stroke-linecap="round"><g transform="translate(68.64313852626913 150.67777964623224) rotate(0 138.7179709232347 31.942831006938263)"><path d="M0.9 0.22 C11.21 9.47, 27.19 46.75, 61.21 56.47 C95.23 66.19, 169.01 67.73, 205.03 58.53 C241.05 49.33, 265.29 10.98, 277.33 1.28 M-0.09 -0.71 C10.08 9.26, 25.86 48.45, 60.01 57.99 C94.16 67.54, 168.57 65.8, 204.82 56.55 C241.08 47.3, 265.71 11.88, 277.52 2.5" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(68.64313852626913 150.67777964623224) rotate(0 138.7179709232347 31.942831006938263)"><path d="M265.22 28.89 C267.69 24.71, 272 16.08, 277.9 2.21 M264.44 29.24 C268.77 23.25, 271.41 16.65, 277.13 3.47" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(68.64313852626913 150.67777964623224) rotate(0 138.7179709232347 31.942831006938263)"><path d="M250.7 14.38 C256.86 13.65, 264.74 8.59, 277.9 2.21 M249.93 14.73 C257.59 12.25, 263.68 9.09, 277.13 3.47" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(179 175.5) rotate(0 21 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">fork</text></g><g stroke-linecap="round" transform="translate(10 295.74482531780495) rotate(0 87.5 53)"><path d="M2.08 3.3 C36.71 -2.39, 76.78 3.07, 174.07 -1.11 M0.26 -0.69 C42.05 -1.13, 83.54 -2.11, 174.76 -0.94 M176.98 3.52 C174.19 34.05, 176.38 65.33, 171.68 109.98 M174.65 0.98 C172.25 22.58, 174.69 43.59, 176.68 107.45 M171.61 108.44 C136.86 107.37, 104.46 108.96, -0.5 105.52 M173.08 105.66 C133.07 108.9, 90.89 105.29, 1.26 105.19 M-2.99 102.82 C-2.47 82.2, 1.2 66.13, 2.54 -3.99 M0.99 107.61 C2.16 84.03, -0.74 60.26, 1.57 0.05" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(217.5 295.74482531780495) rotate(0 87.5 52.5)"><path d="M3.3 -2.26 C62.11 -2.98, 133.41 -2.75, 173.89 -2.55 M-0.69 0.69 C42.18 0.37, 81.99 -0.7, 174.06 0.5 M178.52 -0.98 C174.37 33.53, 171.19 61.32, 178.98 101.42 M175.98 -1.25 C174.62 25.27, 173.31 49.85, 176.45 103.15 M177.44 103.21 C111.99 104.17, 51.79 101.53, -0.48 102.72 M174.66 105.6 C124.77 102.59, 69 102.9, -0.81 103.11 M-3.18 103.16 C-2.29 72.21, 3.41 38.31, -3.99 -3.3 M1.61 106.62 C-0.52 74.87, -1.24 48.87, 0.05 1.13" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(14 263.24482531780495) rotate(0 63 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">shell process</text></g><g transform="translate(224 263.74482531780495) rotate(0 39 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">hello.out</text></g><g stroke-linecap="round"><g transform="translate(402 93.5) rotate(0 32.55205669779792 131.30607887550258)"><path d="M1.07 0.7 C12.3 8.57, 56.11 7.13, 66.9 47.23 C77.7 87.32, 78.62 206.21, 65.82 241.25 C53.03 276.29, 2.66 254.78, -9.89 257.48 M0.18 0.01 C11.28 7.51, 55.11 4.86, 65.91 45.22 C76.7 85.58, 77.63 206.66, 64.97 242.17 C52.3 277.69, 1.98 255.74, -10.11 258.31" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(402 93.5) rotate(0 32.55205669779792 131.30607887550258)"><path d="M20.19 251.02 C11.84 253, 2.64 253.66, -10.98 257.5 M19.37 250.99 C11.28 253.95, 4.79 255.44, -10.56 258.25" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(402 93.5) rotate(0 32.55205669779792 131.30607887550258)"><path d="M17.96 271.42 C10.19 268.08, 1.57 263.44, -10.98 257.5 M17.14 271.39 C9.47 269.16, 3.55 265.46, -10.56 258.25" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(410 213.5) rotate(0 23.5 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">exec</text></g><g stroke-linecap="round"><g transform="translate(18 233.5) rotate(0 187.0766393646598 -0.6412285074591182)"><path d="M-1.22 -1.98 C61.38 -1.81, 313.08 0.15, 375.38 0.69" stroke="#d1d1d1" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g></g><g transform="translate(226 46.705725647183726) rotate(0.6030911943805374 67.5 10.5)"><text x="0" y="15" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#495057" text-anchor="start" style="white-space: pre;" direction="ltr">Address 55cf3...</text></g><g transform="translate(223.9999999999999 300.7057256471837) rotate(0.6030911943805374 67.5 10.5)"><text x="0" y="15" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#495057" text-anchor="start" style="white-space: pre;" direction="ltr">Address 55cf3...</text></g></svg>

<p>This means when <code class="language-plaintext highlighter-rouge">execve</code> gets called, it’s substituting the cloned instance of our shell in memory, so that the shell process doesn’t cease to exist. You can try opening a new terminal and running a program using <code class="language-plaintext highlighter-rouge">exec</code> (as in <code class="language-plaintext highlighter-rouge">exec ./hello.out</code>), and you’ll see your terminal closes afterwards!</p>

<p>At the end of <code class="language-plaintext highlighter-rouge">execve</code> our process for <code class="language-plaintext highlighter-rouge">hello.out</code> has received a newly initialized stack, heap and data segments as fresh new virtual address space. In memory, it looks a little bit like this:</p>

<svg class="excalidraw" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 538.5 327.5" width="538.5" height="327.5">
  <!-- svg-source:excalidraw -->

  <defs>
    <style>
      @font-face {
        font-family: "Virgil";
        src: url("https://excalidraw.com/Virgil.woff2");
      }
      @font-face {
        font-family: "Cascadia";
        src: url("https://excalidraw.com/Cascadia.woff2");
      }
    </style>
  </defs>
  <rect x="0" y="0" width="538.5" height="327.5" fill="#ffffff"></rect><g transform="translate(60.00000000000004 162.5) rotate(0 23.5 26)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">text</text><text x="0" y="44" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"></text></g><g stroke-linecap="round" transform="translate(166.50000000000003 193.5) rotate(0 87.5 60)"><path d="M30 0 M30 0 C53.88 3.01, 86.61 -3.29, 145 0 M145 0 C162.23 1.66, 177.5 11.34, 175 30 M175 30 C172.74 51.98, 177.73 70.46, 175 90 M175 90 C173.35 108.55, 167.64 121.09, 145 120 M145 120 C101.53 123.35, 58.28 123.18, 30 120 M30 120 C10.61 118.95, -0.36 114, 0 90 M0 90 C2.4 66.59, 3.51 53.75, 0 30 M0 30 C0.35 12.41, 11.88 2.56, 30 0" stroke="#000000" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g stroke-linecap="round" transform="translate(411.50000000000006 194) rotate(0 58.5 60)"><path d="M29.25 0 M29.25 0 C44.15 2.29, 63.22 4.6, 87.75 0 M87.75 0 C103.56 -0.16, 116.2 12.86, 117 29.25 M117 29.25 C118.27 52.31, 121 65.38, 117 90.75 M117 90.75 C119.32 111.94, 104.19 121.65, 87.75 120 M87.75 120 C67.59 122.6, 54.56 124.69, 29.25 120 M29.25 120 C8.26 120.76, 0.98 113.66, 0 90.75 M0 90.75 C1.62 67.84, 2.07 41.11, 0 29.25 M0 29.25 C-2.06 12.22, 13.53 2.73, 29.25 0" stroke="#000000" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g stroke-linecap="round" transform="translate(133.00000000000003 192) rotate(0 13 61)"><path d="M1.76 0.61 C9.5 -0.44, 16.61 -0.9, 25.8 -1.2 M25.4 -1.03 C24.64 43.71, 24.65 85.96, 26.85 123.63 M24.38 121.51 C15.18 120.08, 6.37 120.09, 0.7 122.66 M1.96 120.77 C-0.59 91, 0.21 62.21, 0.4 -1.58" stroke="#000000" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g transform="translate(231.00000000000003 164) rotate(0 22.5 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">heap</text></g><g stroke-linecap="round"><g transform="translate(342.50000000000006 251.65053170408692) rotate(0 12.988895905017841 -2.1816982091843045)"><path d="M1.14 -1.89 C5.62 -2.64, 21.13 -2.47, 24.84 -2.41" stroke="#000000" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g transform="translate(342.50000000000006 251.65053170408692) rotate(0 12.988895905017841 -2.1816982091843045)"><path d="M11.28 1.58 C15.32 -0.78, 18.82 1.77, 23.5 -0.16" stroke="#000000" stroke-width="1.5" fill="none"></path></g><g transform="translate(342.50000000000006 251.65053170408692) rotate(0 12.988895905017841 -2.1816982091843045)"><path d="M11.36 -7.02 C15.51 -7.42, 18.99 -2.91, 23.5 -0.16" stroke="#000000" stroke-width="1.5" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(410.00000000000006 249) rotate(0 -11.415614598989464 1.668319870519639)"><path d="M-0.06 2.6 C-3.84 2.7, -19.14 1.75, -22.77 0.74" stroke="#000000" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g transform="translate(410.00000000000006 249) rotate(0 -11.415614598989464 1.668319870519639)"><path d="M-9.36 -1.37 C-13.41 0.04, -20.22 -0.38, -24.36 3.03" stroke="#000000" stroke-width="1.5" fill="none"></path></g><g transform="translate(410.00000000000006 249) rotate(0 -11.415614598989464 1.668319870519639)"><path d="M-10.52 6.42 C-14.23 5.51, -20.7 2.78, -24.36 3.03" stroke="#000000" stroke-width="1.5" fill="none"></path></g></g><g transform="translate(443.00000000000006 166) rotate(0 28 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">stack</text></g><g stroke-linecap="round" transform="translate(38.00000000000004 189) rotate(0 43 62.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M0.34 5.3 C2.77 3.72, 3.07 0.91, 5.57 1.66 M0.51 6.34 C1.51 4, 3.46 1.71, 5.51 0.91 M-1.45 13.17 C5.21 8.73, 2.33 8.04, 9.81 -0.09 M0.38 10.74 C4.3 8.59, 9.41 3.7, 11.75 -0.5 M-2.79 19.9 C2.78 13.94, 12.76 3.9, 16.84 0.74 M-0.93 20.4 C3.99 12.07, 7.52 11.34, 17.53 2.25 M1.41 27.86 C4.38 14.57, 10.4 13.51, 25.1 0.06 M-0.71 24.47 C9.27 14.38, 14.69 4.12, 22.07 1.59 M-0.39 31.81 C11.38 21.83, 13.17 11.01, 23.17 -0.62 M0.48 30.16 C8 17.7, 17.24 8.42, 27.56 -1.12 M1.03 36.48 C9.29 21.36, 20.59 13.26, 34.89 3.77 M1.25 37.93 C7.24 28.75, 17.47 17.37, 32.81 -1.17 M-0.64 45.21 C10.17 27.51, 28.17 16.42, 39.88 -2.13 M-1.46 42.49 C10.82 29.57, 21.42 15.15, 37.3 -1.65 M0.74 48.12 C11.69 35.33, 32.71 12.87, 40.88 -2.14 M-1.45 50.01 C14.96 32.45, 26.76 14.77, 43.41 -0.42 M2.39 50.92 C12.06 38.42, 30.23 20.48, 48.39 3.52 M-1.57 55.86 C11.81 38.66, 25.92 23.43, 48.17 -1.13 M1.31 58.87 C21.78 34.02, 43.5 11.3, 52.01 2.16 M1.95 61.66 C15.42 43.4, 30.11 23.22, 53.52 -0.21 M-3.05 65.54 C23.35 47.32, 42.03 22.67, 61.12 0.67 M1.15 68.98 C12.14 53.15, 25.86 35.59, 58.08 2.14 M3.16 73.05 C16.03 56, 29.03 41.17, 60.19 -2.51 M-0.65 72.6 C13.38 59.07, 27.24 45.19, 63.33 -1.07 M-3.71 80.37 C17.43 57.58, 32.02 41.57, 65.48 -1.36 M-1.81 77.8 C22.39 53.27, 44.24 26.01, 69.44 1.39 M-2.28 88 C26.18 55.45, 59.96 21.47, 72.34 -2.31 M-0.82 86.04 C23.16 60.62, 42.98 36.96, 73.48 -0.05 M2.66 90.01 C25.69 61.09, 50.24 30.87, 79.91 -0.23 M-0.46 92.04 C22.76 66.92, 46.66 43.81, 81.17 1.31 M-1.26 94.78 C24.57 68.52, 44.44 41.76, 86.4 1.58 M1.69 97.45 C31.81 58.78, 65.01 22.14, 85.15 1.33 M2 105.27 C32.29 63.45, 70.36 24.57, 87.86 1.64 M0.37 104.16 C19.48 81.38, 38.22 64.75, 86.72 0.39 M-3.04 107.23 C22.44 82.84, 40.02 56.36, 92.06 9.29 M1.61 111.53 C18.75 87.79, 40.6 62.6, 88.78 9.31 M3.22 113.99 C26.05 85.25, 48.37 62.99, 91.18 16.13 M0.36 114.12 C32.33 79.42, 60.4 42.47, 87.44 13.87 M-3.84 118.43 C13.76 95.02, 40.01 79.04, 89.18 17.12 M0.2 122.73 C21.38 98.39, 42.38 76.93, 90.47 20.83 M-0.45 127.49 C20.05 107, 39.93 88.48, 89.83 22.76 M0.96 127.87 C35.25 87.43, 68.82 46.06, 88.27 27.18 M6.3 130.16 C39.04 91.95, 67.72 64.04, 91.31 31.88 M6.43 124.74 C33.03 97.59, 55.82 69.01, 87.5 33.85 M13.8 126.53 C33.47 103.54, 54.53 76.94, 90.23 35.86 M10.73 127.31 C40.97 96.27, 66.45 64.18, 90.12 39 M19.2 123.76 C35.15 109.45, 52.99 83.22, 85.68 46.89 M16.58 125.27 C41.27 98.37, 67.6 69.85, 88.37 43.29 M26.7 128.52 C47 97.1, 66.95 73.83, 89.8 46.74 M21.63 125.48 C48.93 95.48, 74.73 65.51, 90.41 51.56 M24.32 123.09 C47.55 108.12, 61.07 88.43, 88.55 58.74 M26.15 125.06 C42.18 107.59, 58.89 90.09, 88.07 57.89 M35.16 125.27 C50.06 100.87, 71.71 80.01, 84.31 64.51 M35.33 124.33 C50.06 106.98, 67.32 87.65, 86.41 63.32 M38.11 124.48 C55.69 107.92, 68.65 88.33, 91.86 72.24 M39.04 127.83 C53.11 108.07, 70.88 90.11, 86.77 69.1 M42.46 126.38 C58.7 110.25, 71.48 96.27, 86.49 72.96 M45.35 126.08 C57.5 113.77, 67.2 98.05, 89.82 73.98 M51.97 125.25 C57.45 115.32, 62.9 108.94, 86.52 77.24 M47.66 124.79 C63.01 109.48, 72.75 96.95, 89.13 79.89 M52.83 124.16 C63.49 113.5, 75.81 106.6, 90.1 91.2 M55.66 126.18 C67.93 109.9, 80.57 96.86, 86.92 89.01 M56.33 123.74 C67.24 120.83, 73.54 115.5, 85.79 97.3 M60.93 126.65 C67.64 117.62, 76.17 104.32, 87.66 93.47 M67.54 130.2 C72.85 119.19, 77.86 111.09, 88.58 98.54 M64.75 125.85 C74.22 116.66, 79.45 107.97, 89.11 100.62 M72.61 127.28 C78.33 118.03, 82.8 113.48, 87.92 106.75 M72.27 127.62 C73.58 118.76, 79.44 114.64, 89.34 106.29 M71.51 124.31 C78.95 119.17, 84.17 119.86, 90.34 115.32 M76.31 125.04 C77.65 122.55, 81.64 118.48, 88.31 112.51 M81.19 127.28 C85.37 123.78, 86.67 120.23, 88.24 116.39 M80.28 125.75 C84.83 122.56, 87.4 120.04, 87.97 117.15 M-0.01 125 C-0.01 125, -0.01 125, -0.01 125 M-0.01 125 C-0.01 125, -0.01 125, -0.01 125 M7.14 125.92 C6.07 124.29, 4.17 122.34, 0.74 121.01 M7.01 124.89 C5.37 124.48, 3.49 123.01, 0.69 119.75 M9.76 126.95 C8.01 122.16, 6.67 117.62, 2.77 114.31 M11.41 125.55 C9.02 123.36, 4.84 118.9, -0.81 115.93 M20.26 127.44 C9.38 119.13, 7.49 113.78, -2.6 112.7 M20.37 126.8 C11.13 119.45, 6.28 114.18, 1.16 108.25 M25.87 126.71 C19.4 121.71, 10.29 116.63, -0.56 100.67 M22.59 126.16 C18.71 117.98, 9.67 112.8, 1.54 103.68 M31.86 124.33 C18.22 113.28, 8.39 112.48, -2.64 102.34 M29.52 124.22 C19.28 117.72, 11.56 109.04, -0.73 99.99 M34.25 123.99 C27.67 121.31, 23.36 114.12, -1.63 91.79 M36.79 125.63 C27.62 118.56, 15.9 106.98, 1.76 93.17 M43.49 121.91 C31.08 115.92, 24.7 109.39, 1.12 88.27 M43.3 124.29 C25.99 109.62, 8.26 94.22, -0.31 90.03 M52.74 126.84 C31.64 110.92, 16.71 99.09, 3.69 80.98 M50.51 124.28 C33.18 112.07, 14.04 96.53, -1.95 82 M54.57 125.49 C39.44 117.08, 32.91 106.74, -0.39 76.31 M54.13 126.25 C41.83 112.68, 29.4 102.09, -0.91 77.33 M61.02 121.74 C44.05 106.25, 21.77 91.86, 1.83 70.58 M59.18 123.72 C46.14 109.62, 26.33 96.88, 1.34 70.89 M64.28 126.07 C47.46 110.54, 33.44 98.39, -1.25 65.3 M67.68 125.44 C42.18 101.15, 13.33 76.56, -1.37 68.36 M69.01 127.52 C58.35 112.23, 37.44 89.44, 2.2 63.91 M73.96 124.41 C48.23 102.93, 25.47 83.3, -0.96 60.04 M76.54 121.67 C48.74 105.38, 26.48 78.48, 3.46 55.05 M79.86 126.78 C56.96 103.53, 32.52 82.51, -0.03 57.07 M85.63 124.01 C60.25 97.2, 27.93 75.74, -2.78 49.29 M86.51 126.31 C53.94 97.4, 18.78 67.72, -0.94 49.17 M85.49 118.63 C56.82 96.63, 34.8 69.39, 1.65 46.4 M90.3 122 C56.44 98.74, 25.19 72.27, 1.27 44.92 M85.75 116.16 C63.91 97.85, 49.19 80.17, 2.33 40.07 M87.93 117.02 C62.57 94.58, 33.65 71.99, -2.19 41.49 M88.53 113.05 C70.4 93.93, 50.51 84.25, -3.73 33.18 M87.4 111.06 C68.31 96.09, 49.38 80.92, 1.21 36.88 M90.33 107.05 C57.97 81.71, 25.99 54.91, -0.07 26.56 M88.94 104.75 C62.99 83.68, 40.52 60.18, 0.22 27.7 M89.13 99.12 C55.56 72.46, 21.4 39.78, -2.78 26.21 M87.11 102.56 C66.89 82.63, 47.89 66.44, -1.06 25.4 M85.06 98.79 C66.55 78.67, 44.26 57, 3.45 16.09 M90.47 95.22 C59.86 71.22, 29.54 46.97, -0.31 18.02 M88.71 88.17 C68.89 72.1, 42.82 50.79, -2.58 13.33 M88.86 88.69 C63.94 67.67, 37.33 44.19, -1.87 14.45 M89.36 81.89 C72.99 70.54, 54.05 49.61, 2.08 9.65 M88.67 85.1 C66.6 66.72, 45.71 49.21, -1.1 6.83 M87.7 76.53 C70.91 65.38, 47.54 46.04, -3.19 -0.65 M88.55 81.18 C64.62 60.6, 41.93 39.5, -1.06 3.49 M91.9 73.84 C56.67 45.45, 16.14 14.96, -1.54 -0.09 M90.46 76.5 C61.19 50.14, 30.5 24.97, -0.5 -1.34 M85.52 69.53 C56.45 41.73, 22.64 10.52, 9.84 -3.32 M86.6 67.23 C59.7 44.8, 33.04 21.22, 5.59 -1.96 M87.6 60.47 C57.89 38.46, 31.22 14.06, 14.36 -0.96 M90.51 62.38 C62.51 40.16, 34.05 18.94, 11.72 0.07 M88.59 57.49 C71.86 47.67, 57.94 31.86, 23.43 1.5 M87.94 57.55 C60.88 35.93, 33.53 12.53, 20.22 -2.06 M86.39 52.6 C68.8 36.26, 47.73 19.75, 23.86 0.52 M87.97 55.2 C63.13 31.47, 39.73 12.68, 23.67 -2.56 M86.33 47.74 C70.17 28.12, 47.61 6.1, 29.96 1.72 M89.96 46.36 C65.63 28.06, 45.28 10.7, 31.96 -2.79 M89.18 46.06 C76.39 27.79, 61.89 17.39, 36.16 1.34 M90.52 42.92 C74.03 27.09, 56.58 16.83, 36 -0.87 M91.16 40.62 C75.07 21.81, 60.95 14.93, 41.35 -1.83 M86.58 35.36 C77.59 27.46, 69.88 18.58, 42.98 -2.7 M87.91 29.68 C72.51 24.11, 66.13 5.86, 49.14 -2.48 M90.32 33 C75.14 22.39, 61.09 7.63, 51.63 -0.97 M90.51 29.45 C81.39 22.49, 72.91 14.16, 52.54 0.67 M88.22 25.77 C76.04 19.3, 66.52 9.67, 55.95 -0.8 M89.49 25.29 C83.56 17.11, 70.97 11.45, 62.01 -3.96 M88.04 20.41 C77.35 13.78, 68.8 3.39, 60.22 0.52 M86.79 16.55 C86.2 15.86, 77.83 5.39, 66.19 -3.3 M89.79 14.29 C79.95 8.69, 75.25 6.79, 66.77 0 M91.66 7.89 C86.56 7.27, 83.81 4.56, 72.26 -3.65 M88.8 11.58 C84.54 7.09, 77.05 1.97, 75.14 -2.15 M88.74 5.34 C86.95 3.8, 84.78 3.45, 81.1 -2.18 M87.37 5.28 C86.22 3.53, 81.88 0.63, 81.05 -1.39" stroke="#ced4da" stroke-width="0.5" fill="none"></path><path d="M3.52 2.7 C16.32 1.6, 32.74 -0.07, 89.9 -0.63 M1.12 1.67 C25.11 0.53, 47.67 -0.82, 85.17 -1.14 M82.42 -2.5 C89.4 31.63, 87.08 69.43, 85.13 126.13 M85.23 0.14 C86.55 35.49, 84.81 66.96, 85.36 124.33 M86.13 121.7 C62.84 126.93, 35.49 127.3, -0.57 128.88 M87.02 125.98 C60.51 125.48, 32.7 126.39, -1.51 124.73 M-3.83 124.87 C0.45 77.22, -2.61 31.73, -1.75 2.26 M0.5 126.9 C1.19 80.64, 0.88 34.46, -0.9 1.75" stroke="#495057" stroke-width="1" fill="none"></path></g><g transform="translate(122.00000000000004 243.5) rotate(269.0122396003602 24 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#495057" text-anchor="start" style="white-space: pre;" direction="ltr">data</text></g><g transform="translate(51.00000000000004 20) rotate(0 33 18)"><text x="0" y="25" font-family="Virgil, Segoe UI Emoji" font-size="28px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">exec</text></g><g transform="translate(49.00000000000004 98) rotate(0 39 13)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">hello.out</text></g><g stroke-linecap="round"><g transform="translate(95.81703495479513 66.9194004116317) rotate(0 -0.3683767629733836 12.324744312753076)"><path d="M0.83 -0.12 C0.66 4.16, -0.77 21.76, -1.11 25.87 M-0.2 -1.22 C-0.43 2.7, -1.34 19.69, -1.56 24.17" stroke="#000000" stroke-width="2" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(90.3253690781925 130.16224060654642) rotate(0 0.7884953287272793 14.239518685969529)"><path d="M0.79 -0.1 C1.19 4.97, 1.71 24.7, 1.83 29.68 M-0.25 -1.2 C0.06 3.61, 0.82 23.13, 0.98 27.99" stroke="#000000" stroke-width="2" fill="none"></path></g><g transform="translate(90.3253690781925 130.16224060654642) rotate(0 0.7884953287272793 14.239518685969529)"><path d="M-4.58 14.83 C-2.17 17.81, -0.66 22.29, 1.98 27.4 M-4.77 15.19 C-2.19 19.12, -0.51 24.51, 0.82 27.73" stroke="#000000" stroke-width="2" fill="none"></path></g><g transform="translate(90.3253690781925 130.16224060654642) rotate(0 0.7884953287272793 14.239518685969529)"><path d="M5.3 14.47 C5.21 17.6, 4.23 22.17, 1.98 27.4 M5.11 14.82 C4.01 18.84, 2.02 24.37, 0.82 27.73" stroke="#000000" stroke-width="2" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(126.99259749681204 37.27061937390957) rotate(0 174.8738056598291 57.794462985619994)"><path d="M2.16 2.68 C119.72 -1.63, 238.56 -0.72, 310.34 3.34 M306.42 -1.76 C322.45 38.61, 330.16 69.73, 347.59 117.35" stroke="#495057" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g transform="translate(126.99259749681204 37.27061937390957) rotate(0 174.8738056598291 57.794462985619994)"><path d="M331.68 97.74 C335.34 100.47, 340.93 109.77, 348.37 119.37" stroke="#495057" stroke-width="1.5" fill="none"></path></g><g transform="translate(126.99259749681204 37.27061937390957) rotate(0 174.8738056598291 57.794462985619994)"><path d="M351.07 91.02 C347.18 96.41, 345.24 108.31, 348.37 119.37" stroke="#495057" stroke-width="1.5" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(130.81212323047737 45.31045941810709) rotate(2.028386558906463 62.3213208189962 50.271865003265106)"><path d="M-2.38 0.56 C29.15 1.54, 52.75 0.92, 127.02 -5.29 M122.95 -8.1 C126.93 26.93, 125.51 62.39, 126.22 108.65" stroke="#495057" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g transform="translate(130.81212323047737 45.31045941810709) rotate(2.028386558906463 62.3213208189962 50.271865003265106)"><path d="M113.39 81.6 C119.75 89.5, 117.71 96.74, 129.45 110.48" stroke="#495057" stroke-width="1.5" fill="none"></path></g><g transform="translate(130.81212323047737 45.31045941810709) rotate(2.028386558906463 62.3213208189962 50.271865003265106)"><path d="M133.91 81.46 C135.63 89.22, 128.94 96.49, 129.45 110.48" stroke="#495057" stroke-width="1.5" fill="none"></path></g></g><g transform="translate(199.00000000000003 10) rotate(0 72 10.5)"><text x="0" y="15" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#495057" text-anchor="start" style="white-space: pre;" direction="ltr">assigns addresses</text></g><g transform="translate(52.00000000000004 75.5) rotate(0 43 10.5)"><text x="0" y="15" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#495057" text-anchor="start" style="white-space: pre;" direction="ltr">loads text</text></g><g stroke-linecap="round"><g transform="translate(127.89818073975597 50.08289241482731) rotate(0 13.035146108927577 60.66539416169199)"><path d="M1.29 1.21 C8.84 2.43, 13.98 1.03, 21.45 4.48 M24.78 6.56 C22.14 52.14, 19.92 95.85, 20.04 120.13" stroke="#000000" stroke-width="1.5" fill="none" stroke-dasharray="8 9"></path></g><g transform="translate(127.89818073975597 50.08289241482731) rotate(0 13.035146108927577 60.66539416169199)"><path d="M11.57 92.96 C15.06 101.35, 16.18 107.1, 18.39 120" stroke="#000000" stroke-width="1.5" fill="none"></path></g><g transform="translate(127.89818073975597 50.08289241482731) rotate(0 13.035146108927577 60.66539416169199)"><path d="M32.09 93.33 C29.41 101.65, 24.37 107.29, 18.39 120" stroke="#000000" stroke-width="1.5" fill="none"></path></g></g><g transform="translate(-46.999999999999986 239.5) rotate(270 67.5 10.5)"><text x="0" y="15" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#495057" text-anchor="start" style="white-space: pre;" direction="ltr">Address 55cf3...</text></g></svg>

<p>To see what exactly the kernel is doing with the memory of your process, you can run <code class="language-plaintext highlighter-rouge">pmap $PID</code> or examine the contents of the files in <code class="language-plaintext highlighter-rouge">/proc/$PID/maps</code>, where <code class="language-plaintext highlighter-rouge">$PID</code> is the process ID of the process you want to investigate.</p>

<p>At the end of <code class="language-plaintext highlighter-rouge">execve</code>, a function called <a href="https://github.com/torvalds/linux/blob/3d742d4b6ebb3348e1d478047cfb18b9b337b8df/fs/exec.c#L1698"><code class="language-plaintext highlighter-rouge">search_binary_handler</code></a> gets called. It checks the <code class="language-plaintext highlighter-rouge">hello.out</code> for a matching magic number (a few bits at the start of the file) to find a handler. The binary handler that matches our program is <a href="https://github.com/torvalds/linux/blob/2388777a0a5957a10b3d78677216530a9b3bd09f/fs/binfmt_aout.c#L117"><code class="language-plaintext highlighter-rouge">binfmt_aout.c</code></a>, which handles <code class="language-plaintext highlighter-rouge">.out</code>-style ELF files as produced by GCC. Then, <a href="https://github.com/torvalds/linux/blob/5bfc75d92efd494db37f5c4c173d3639d4772966/fs/exec.c#L1239"><code class="language-plaintext highlighter-rouge">binfmt_aout::load_aout_binary</code></a> ends up calling <a href="https://github.com/torvalds/linux/blob/5bfc75d92efd494db37f5c4c173d3639d4772966/fs/exec.c#L1234-L1239"><code class="language-plaintext highlighter-rouge">begin_new_exec</code></a>, marked as the “point of no return” in the Linux kernel source, after which any failure results in a fatal signal.</p>

<p>From then on, the kernel takes care of memory-mapping anything required by the executable. The code for this is architecture-dependent (see, for example, different implementations of <a href="https://github.com/torvalds/linux/search?q=activate_mm"><code class="language-plaintext highlighter-rouge">activate_mm</code></a> in the kernel). Ultimately, the kernel configures the CPU context to kickstart execution of our process.</p>

<p><em>P.S. You may be wondering why <code class="language-plaintext highlighter-rouge">fork</code> didn’t show up in the output of <code class="language-plaintext highlighter-rouge">strace</code>. The answer is simply that <code class="language-plaintext highlighter-rouge">strace</code>’s tracing begins after it has forked in order to execute the program passed in as an argument. Thanks, <a href="https://unix.stackexchange.com/a/267223">Kenster on StackOverflow</a>.</em></p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><summary type="html"><![CDATA[While reading Michael Kerrisk's The Linux Programming Interface, I take a look at some strace output for a simple "hello world" program in order to fully understand it.]]></summary></entry><entry><title type="html">Binding devices with libusbip – usairb devlog #2</title><link href="https://fnune.com/devlog/usairb/2022/03/18/binding-devices-with-libusbip-usairb-devlog-2/" rel="alternate" type="text/html" title="Binding devices with libusbip – usairb devlog #2" /><published>2022-03-18T12:56:00+00:00</published><updated>2022-03-18T12:56:00+00:00</updated><id>https://fnune.com/devlog/usairb/2022/03/18/binding-devices-with-libusbip-usairb-devlog-2</id><content type="html" xml:base="https://fnune.com/devlog/usairb/2022/03/18/binding-devices-with-libusbip-usairb-devlog-2/"><![CDATA[<blockquote>
    <p>
      This is a development log of <a href="https://github.com/fnune/usairb"><code>usairb</code></a>, a
      project I'm building to learn embedded Linux. The goal is to transform any
      embedded Linux device with access to the Internet into a multiplexing
      transmitter for USB hubs.
    </p>

    <p>See other posts here:</p>
    <ul>
      
        
      
        
          <li>
            <a href="/devlog/usairb/2022/02/05/listening-to-devices-with-libudev-usairb-devlog-1/">
              <span>Listening to devices with libudev – usairb devlog #1</span>
            </a>
            <span> · </span>
            <time datetime="2022-02-05T10:43:00+00:00">February 5, 2022</time>
          </li>
        
      
    </ul>

  </blockquote>

<p>Second development entry. On the <a href="/devlog/usairb/2022/02/05/listening-to-devices-with-libudev-usairb-devlog-1/">first day</a>, I implemented a simple
busy loop that prints to the console whenever a USB device connects or
disconnects, using a <code class="language-plaintext highlighter-rouge">udev</code> monitor. Today, I’ll implement binding those
devices using <a href="http://usbip.sourceforge.net">USB/IP</a>, and try to attach to them from a client
device.</p>

<p>A <strong>spoiler</strong> and a word of warning: this didn’t go so well and I ended up
giving up on <code class="language-plaintext highlighter-rouge">libusbip</code> and reverting the changes described in this post,
opting instead for calling the <code class="language-plaintext highlighter-rouge">usbip</code> CLI directly from my program using pipes
(<code class="language-plaintext highlighter-rouge">popen</code>). The next entry will be about that. Nevertheless, I learned a little
bit more about sockets, file descriptors and <code class="language-plaintext highlighter-rouge">libudev</code> as part of this attempt.
Stick around if you’d like to read that!</p>

<h2 id="introduction">Introduction</h2>

<p>From the <a href="http://usbip.sourceforge.net">USB/IP site</a>:</p>

<blockquote>
  <p>USB/IP Project aims to develop a general USB device sharing system over IP
network. To share USB devices between computers with their full
functionality, USB/IP encapsulates “USB I/O messages” into TCP/IP payloads
and transmits them between computers.</p>
</blockquote>

<p>It looks like the <a href="https://github.com/torvalds/linux/blob/master/tools/usb/usbip/README">Linux kernel source</a> does not include a
library for USB/IP. I’m resorting to this <a href="https://github.com/forensix/libusbip">community <code class="language-plaintext highlighter-rouge">libusbip</code></a> for
now.</p>

<p>After spending some time reading its source code, it looks like I have a plan:</p>

<ul>
  <li>Get a device vendor ID and product ID from each connecting device from my
<code class="language-plaintext highlighter-rouge">udev</code> monitor.
    <ul>
      <li>Handling two physical devices with the same vendor ID and product ID is out
of scope for now.</li>
    </ul>
  </li>
  <li>Figure out how to set up a socket in order to initialize USB/IP.</li>
  <li>Use <code class="language-plaintext highlighter-rouge">libusbip_open_device_with_vid_pid</code> to get a <code class="language-plaintext highlighter-rouge">libusbip_device</code> like in
the <a href="https://github.com/forensix/libusbip/blob/master/examples/idev_cmd.c#L114">example</a>.</li>
  <li>Confirm that opening and configuring the device actually means the same as
going <code class="language-plaintext highlighter-rouge">usbip bind</code> on the command line. I believe because <code class="language-plaintext highlighter-rouge">libusbip</code> has the
same interface for the client and the server, it uses the names <code class="language-plaintext highlighter-rouge">open</code> and
<code class="language-plaintext highlighter-rouge">close</code> instead of <code class="language-plaintext highlighter-rouge">bind</code>, <code class="language-plaintext highlighter-rouge">unbind</code> (the server terms), and <code class="language-plaintext highlighter-rouge">attach</code>,
<code class="language-plaintext highlighter-rouge">detach</code> (the client terms).</li>
</ul>

<h2 id="getting-a-product-id-and-a-vendor-id-from-a-udev_device">Getting a product ID and a vendor ID from a <code class="language-plaintext highlighter-rouge">udev_device</code></h2>

<p>The <code class="language-plaintext highlighter-rouge">udev_device_get_property_value</code> function seems like a good choice. USB/IP
and <code class="language-plaintext highlighter-rouge">udev</code> nomenclature differ a little: vendor IDs are called the same but
it’s product ID in USB/IP and model ID in <code class="language-plaintext highlighter-rouge">udev</code>.</p>

<p>To find a list of available keys, I ran <code class="language-plaintext highlighter-rouge">udevadm monitor --udev --env</code>, and I
get something like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ID_VENDOR=GenesysLogic
ID_VENDOR_ENC=GenesysLogic
ID_VENDOR_ID=05e3
ID_MODEL=USB2.1_Hub
ID_MODEL_ENC=USB2.1\x20Hub
ID_MODEL_ID=0610
ID_REVISION=9304
ID_SERIAL=GenesysLogic_USB2.1_Hub
</code></pre></div></div>

<p>With this in mind:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">printf</span><span class="p">(</span><span class="s">"%s %s vid:%s pid:%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">udev_device_get_action</span><span class="p">(</span><span class="n">device</span><span class="p">),</span>
       <span class="n">udev_device_get_devnode</span><span class="p">(</span><span class="n">device</span><span class="p">),</span>
       <span class="n">udev_device_get_property_value</span><span class="p">(</span><span class="n">device</span><span class="p">,</span> <span class="s">"ID_VENDOR_ID"</span><span class="p">),</span>
       <span class="n">udev_device_get_property_value</span><span class="p">(</span><span class="n">device</span><span class="p">,</span> <span class="s">"ID_MODEL_ID"</span><span class="p">));</span>
</code></pre></div></div>

<p>Looking good:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>add /dev/bus/usb/004/013 vid:090c pid:1000
remove /dev/bus/usb/004/013 vid:(null) pid:(null)
</code></pre></div></div>

<p>Except that when I remove the device, I no longer get a <code class="language-plaintext highlighter-rouge">vid</code> or a <code class="language-plaintext highlighter-rouge">pid</code>. I
think that might just be fine for now. I’m not even sure if I need to handle
removals, so let’s keep going.</p>

<p>Aside: your computer has a file with a database of known vendor and model IDs
alongside their names. You can find it in <code class="language-plaintext highlighter-rouge">/usr/share/hwdata/usb.ids</code>. I found
my flash drive <code class="language-plaintext highlighter-rouge">090c:1000</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ~ <span class="o">=&gt;</span> <span class="nb">grep</span> <span class="nt">-A6</span> <span class="s1">'^090c'</span> /usr/share/hwdata/usb.ids
090c  Silicon Motion, Inc. - Taiwan <span class="o">(</span>formerly Feiya Technology Corp.<span class="o">)</span>
        0371  Silicon Motion SM371 Camera
        0373  Silicon Motion Camera
        037a  Silicon Motion Camera
        037b  Silicon Motion Camera
        037c  300k Pixel Camera
        1000  Flash Drive
</code></pre></div></div>

<h2 id="initializing-usbip-and-learning-about-sockets">Initializing USB/IP and learning about sockets</h2>

<p>Since this is my first contact with sockets at this level, I’m going to record
my own introduction here.</p>

<p>After a first read of some <code class="language-plaintext highlighter-rouge">man</code> pages I’ve managed to gather some interesting
information:</p>

<ul>
  <li>I can create a socket using the <code class="language-plaintext highlighter-rouge">socket(2)</code> syscall. The kernel needs to know
what type of socket I want to create. The <a href="https://github.com/torvalds/linux/blob/master/tools/usb/usbip/README">USB/IP <code class="language-plaintext highlighter-rouge">README</code></a>
mentions that it works on TCP port 3240, so going by <code class="language-plaintext highlighter-rouge">man socket</code> I need to
pass:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">AF_INET</code> as the protocol family,</li>
      <li><code class="language-plaintext highlighter-rouge">SOCK_STREAM</code> (I suppose this is TCP as opposed to <code class="language-plaintext highlighter-rouge">SOCK_DGRAM</code> which
should be UDP),</li>
      <li><code class="language-plaintext highlighter-rouge">0</code> for the protocol, since for most combinations of protocol family and
socket type there is only one available protocol, the value <code class="language-plaintext highlighter-rouge">0</code>, which
stands for “do the right thing for me”. Let’s hope it delivers.</li>
    </ul>
  </li>
  <li>TCP sockets provide a two-way binding. The <code class="language-plaintext highlighter-rouge">accept(2)</code> syscall takes a
connection-based socket (i.e. not <code class="language-plaintext highlighter-rouge">SOCK_DGRAM</code>/UDP) and gives you a file
descriptor for a new socket, meant for clients to talk to.
    <ul>
      <li>Helpfully, it also warns that the original socket needs to have gone
through some other syscalls first: <code class="language-plaintext highlighter-rouge">bind(2)</code> and <code class="language-plaintext highlighter-rouge">listen(2)</code>.</li>
    </ul>
  </li>
</ul>

<p>Aside: to get <code class="language-plaintext highlighter-rouge">man socket</code> I had to install <code class="language-plaintext highlighter-rouge">man-pages</code> and run <code class="language-plaintext highlighter-rouge">mandb</code>,
otherwise I was getting Perl documentation, or <code class="language-plaintext highlighter-rouge">No manual entry for socket in section 2</code> if I passed a section.</p>

<p>After some time, I’ve got this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;arpa/inet.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;netinet/in.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;sys/socket.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="n">BACKLOG_LENGTH</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// Not sure if I need more.</span>

<span class="kt">int</span> <span class="nf">usairb_connect</span><span class="p">(</span><span class="kt">int</span> <span class="n">port</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">socket_fd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">socket_fd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"socket returned error code %i</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">socket_fd</span><span class="p">);</span>
    <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">socket_address_in</span> <span class="o">=</span> <span class="p">{</span>
      <span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">,</span>
      <span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">port</span><span class="p">),</span>
      <span class="p">.</span><span class="n">sin_addr</span> <span class="o">=</span> <span class="p">{.</span><span class="n">s_addr</span> <span class="o">=</span> <span class="n">INADDR_ANY</span><span class="p">},</span>
  <span class="p">};</span>
  <span class="kt">int</span> <span class="n">socket_len</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">socket_address_in</span><span class="p">);</span>
  <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">socket_address</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">socket_address_in</span><span class="p">;</span>

  <span class="kt">int</span> <span class="n">bind_result</span> <span class="o">=</span> <span class="n">bind</span><span class="p">(</span><span class="n">socket_fd</span><span class="p">,</span> <span class="n">socket_address</span><span class="p">,</span> <span class="n">socket_len</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">bind_result</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"bind returned error code %i</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">bind_result</span><span class="p">);</span>
    <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="kt">int</span> <span class="n">listen_result</span> <span class="o">=</span> <span class="n">listen</span><span class="p">(</span><span class="n">socket_fd</span><span class="p">,</span> <span class="n">BACKLOG_LENGTH</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">listen_result</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"listen returned error code %i</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">listen_result</span><span class="p">);</span>
    <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="n">socket_fd</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>What took me longest was figuring out what I need to pass to <code class="language-plaintext highlighter-rouge">bind</code>, and
understanding the cast from <code class="language-plaintext highlighter-rouge">sockaddr_in</code> to <code class="language-plaintext highlighter-rouge">sockaddr</code> (if you haven’t noticed
yet, I’m new to C):</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">socket_address</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">socket_address_in</span><span class="p">;</span>
</code></pre></div></div>

<p>Generally, I’m also starting to notice that my style of naming variables does
not go well with the style of the kernel API. Maybe one day I’ll budge and
start calling a <code class="language-plaintext highlighter-rouge">sockaddr</code> by its name.</p>

<p>Accepting connections on the socket seems easier:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">usairb_accept</span><span class="p">(</span><span class="kt">int</span> <span class="n">socket_fd</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">client_socket_fd</span> <span class="o">=</span> <span class="n">accept</span><span class="p">(</span><span class="n">socket_fd</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">client_socket_fd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"accept returned error code %i</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">client_socket_fd</span><span class="p">);</span>
    <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">client_socket_fd</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">man accept</code> mentions setting <code class="language-plaintext highlighter-rouge">errno</code> when the return value is <code class="language-plaintext highlighter-rouge">-1</code>. I haven’t
been doing that, and other syscalls I’ve been using likely report errors via
<code class="language-plaintext highlighter-rouge">errno</code> as well.</p>

<p>I sprinkled this after each call that may set <code class="language-plaintext highlighter-rouge">errno</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">listen_result</span> <span class="o">=</span> <span class="n">listen</span><span class="p">(</span><span class="n">socket_fd</span><span class="p">,</span> <span class="n">BACKLOG_LENGTH</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">errno</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"listen produced errno %i</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">errno</span><span class="p">);</span>
  <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Right now, my program runs but produces no output and seems to hang. Even if I
add a <code class="language-plaintext highlighter-rouge">printf</code> right at the beginning of <code class="language-plaintext highlighter-rouge">main</code>, it still won’t print. I’m not
sure why that happens, but the hang is certainly related to some of the network
syscalls.</p>

<p>Reading <code class="language-plaintext highlighter-rouge">man</code> pages for <code class="language-plaintext highlighter-rouge">socket</code>, <code class="language-plaintext highlighter-rouge">bind</code>, <code class="language-plaintext highlighter-rouge">listen</code> and <code class="language-plaintext highlighter-rouge">accept</code>, I found that
<code class="language-plaintext highlighter-rouge">accept</code> is a blocking call by default. At face value, this makes sense because
we want to wait for connections to listen to:</p>

<blockquote>
  <p>If the listen queue is empty of connection requests and O_NONBLOCK is not set
on the file descriptor for the socket, accept() shall block until a
connection is present. If the listen() queue is empty of connection requests
and O_NONBLOCK is set on the file descriptor for the socket, accept()
shall fail and set errno to [EAGAIN] or [EWOULDBLOCK].</p>
</blockquote>

<p>If I do this in <code class="language-plaintext highlighter-rouge">usairb_accept</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">socket_fd_flags</span> <span class="o">=</span> <span class="n">fcntl</span><span class="p">(</span><span class="n">socket_fd</span><span class="p">,</span> <span class="n">F_GETFL</span><span class="p">);</span>
<span class="n">fcntl</span><span class="p">(</span><span class="n">socket_fd</span><span class="p">,</span> <span class="n">F_SETFL</span><span class="p">,</span> <span class="n">socket_fd_flags</span> <span class="o">|</span> <span class="n">O_NONBLOCK</span><span class="p">);</span>
</code></pre></div></div>

<p>Then the program does not hang. However, as vaticinated by <code class="language-plaintext highlighter-rouge">man accept</code>, I get
this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o">~/</span><span class="n">Development</span><span class="o">/</span><span class="n">usairb</span> <span class="p">[</span><span class="mi">127</span><span class="p">]</span> <span class="o">=&gt;</span> <span class="p">.</span><span class="o">/</span><span class="n">target</span><span class="o">/</span><span class="n">usairb</span>
<span class="n">listen</span> <span class="n">produced</span> <span class="n">errno</span> <span class="mi">11</span>
</code></pre></div></div>

<p>Running <code class="language-plaintext highlighter-rouge">strace ./target/usairb</code> produces some clearer output:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(3240), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 1)                            = 0
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
accept(3, NULL, NULL)                   = -1 EAGAIN (Resource temporarily unavailable)
write(2, "accept produced errno 11\n", 25accept produced errno 11
) = 25
exit_group(1)                           = ?
+++ exited with 1 +++
</code></pre></div></div>

<p>So the <code class="language-plaintext highlighter-rouge">listen</code> queue is empty of connection requests and <code class="language-plaintext highlighter-rouge">O_NONBLOCK</code> is set
on the file descriptor for the socket, so I’m getting <code class="language-plaintext highlighter-rouge">[EAGAIN]</code>. I need to
find a way to call <code class="language-plaintext highlighter-rouge">accept</code> only if there’s something in the connection request
queue.</p>

<p>After some sleuthing, I found this <a href="https://stackoverflow.com/questions/12861956/is-it-possible-and-safe-to-make-an-accepting-socket-non-blocking#comment17408534_12862015">comment on StackOverflow</a>
suggesting a way: I can use <code class="language-plaintext highlighter-rouge">select</code> to check for listening connections and
then call <code class="language-plaintext highlighter-rouge">accept</code> only if there’s a request to serve. On further inspection,
this is exactly what <code class="language-plaintext highlighter-rouge">man accept</code> suggests as well:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>APPLICATION USAGE
       When  a  connection is available, select() indicates that the file
       descriptor for the socket is ready for reading.
</code></pre></div></div>

<p>I also found a great <a href="https://jvns.ca/blog/2017/06/03/async-io-on-linux--select--poll--and-epoll/">article by Julia Evans</a> introducing
this topic. It recommends <code class="language-plaintext highlighter-rouge">epoll</code>, but I’m going to go vanilla for learning
purposes and use <code class="language-plaintext highlighter-rouge">select</code>.</p>

<h2 id="getting-stuck">Getting stuck</h2>

<p>After getting something hacked together using <code class="language-plaintext highlighter-rouge">select</code> and getting the program
to compile and run without hanging, I still get no effect that’s visible from
the <code class="language-plaintext highlighter-rouge">usbip</code> tool (e.g. running <code class="language-plaintext highlighter-rouge">usbip list -r localhost</code> does not return
anything). I’m starting to lose hope in <code class="language-plaintext highlighter-rouge">libusbip</code>. After all, it hasn’t been
updated in ten years. I’m going to try a different path: simply calling the
<code class="language-plaintext highlighter-rouge">usbip</code> executable from my program. There’ll be something to learn by doing it
that way, too.</p>

<p>My consolation is that I found out about vendor and model IDs and how to get
them with <code class="language-plaintext highlighter-rouge">libudev</code>. I also had a first contact with sockets in C and got a
tiny bit more experience working with file descriptors.</p>

<p>On the next post I’ll be trying to execute the <code class="language-plaintext highlighter-rouge">usbip</code> CLI from my program and
act on its output. See you then!</p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><category term="devlog" /><category term="usairb" /><summary type="html"><![CDATA[Entry #2 of the usairb development log (USB/IP and embedded Linux)]]></summary></entry><entry><title type="html">Listening to devices with libudev – usairb devlog #1</title><link href="https://fnune.com/devlog/usairb/2022/02/05/listening-to-devices-with-libudev-usairb-devlog-1/" rel="alternate" type="text/html" title="Listening to devices with libudev – usairb devlog #1" /><published>2022-02-05T10:43:00+00:00</published><updated>2022-02-05T10:43:00+00:00</updated><id>https://fnune.com/devlog/usairb/2022/02/05/listening-to-devices-with-libudev-usairb-devlog-1</id><content type="html" xml:base="https://fnune.com/devlog/usairb/2022/02/05/listening-to-devices-with-libudev-usairb-devlog-1/"><![CDATA[<blockquote>
    <p>
      This is a development log of <a href="https://github.com/fnune/usairb"><code>usairb</code></a>, a
      project I'm building to learn embedded Linux. The goal is to transform any
      embedded Linux device with access to the Internet into a multiplexing
      transmitter for USB hubs.
    </p>

    <p>See other posts here:</p>
    <ul>
      
        
          <li>
            <a href="/devlog/usairb/2022/03/18/binding-devices-with-libusbip-usairb-devlog-2/">
              <span>Binding devices with libusbip – usairb devlog #2</span>
            </a>
            <span> · </span>
            <time datetime="2022-03-18T12:56:00+00:00">March 18, 2022</time>
          </li>
        
      
        
      
    </ul>

  </blockquote>

<p>First development day. Added an <a href="https://github.com/fnune/usairb/blob/main/CHANGELOG.md">empty <code class="language-plaintext highlighter-rouge">CHANGELOG</code></a> and a
<a href="https://github.com/fnune/usairb/blob/main/README.md"><code class="language-plaintext highlighter-rouge">README</code></a>, and started this development log. See <a href="https://github.com/fnune/usairb/blob/1721bd891d896dd77d38214a9bb63030b4145fad/src/main.c">the code at the
time of writing</a> if you’d like to follow along.</p>

<h2 id="introduction">Introduction</h2>

<p>I wrote this wishful piece for the <code class="language-plaintext highlighter-rouge">README</code>:</p>

<blockquote>
  <p>The goal of <a href="https://github.com/fnune/usairb"><code class="language-plaintext highlighter-rouge">usairb</code></a> (Universal Serial Air-Bus) is to transform
any embedded Linux device with access to the Internet into a multiplexing
transmitter for USB hubs: connect gadgets to it and use them remotely from your
desktop.</p>
</blockquote>

<p>A quick tech overview:</p>

<blockquote>
  <p>To achieve this, <code class="language-plaintext highlighter-rouge">usairb</code> uses <a href="http://usbip.sourceforge.net">USB/IP</a>. USB/IP follows a server-client
architecture where the server or host is the device broadcasting its USB
gadgets, and the client can connect to them. USB/IP is available as a native
Kernel module on Linux for the host, and has multi-platform client programs.</p>
</blockquote>

<p>And a justification:</p>

<blockquote>
  <p>While all planned features of <code class="language-plaintext highlighter-rouge">usairb</code> are achievable using just USB/IP,
<code class="language-plaintext highlighter-rouge">usairb</code> aims to provide a no-frills experience, potentially offering both a
client graphical user interface as well as very simple interface for the host
device.</p>
</blockquote>

<p>I guess you can call it a no-frills experience if there’s no product for you to
use!</p>

<h2 id="planning-features-of-the-host-device">Planning features of the host device</h2>

<p>To build a PoC that broadcasts devices automatically, and that can be used from
a client alongside the <code class="language-plaintext highlighter-rouge">usbip</code> command-line, interface, the host needs the
following features:</p>

<ul>
  <li>Bind only leaf devices. Avoid binding an entire USB hub.
    <ul>
      <li>Recognize connected USB hubs.
        <ul>
          <li>Eventually, reconsider the idea of not binding entire USB hubs. I’m
deciding this right now because I don’t know how USB hubs will behave.</li>
        </ul>
      </li>
      <li>Eventually, allow the user to bind and unbind specific USB hubs.
        <ul>
          <li>Remember this across boots. Maybe using <code class="language-plaintext highlighter-rouge">systemd</code> or a SQLite database?</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Listen to leaf USB devices when they connect and disconnect.
    <ul>
      <li>Use <code class="language-plaintext highlighter-rouge">libudev</code> for this.</li>
    </ul>
  </li>
  <li>Automatically bind and unbind USB devices.
    <ul>
      <li>Call <code class="language-plaintext highlighter-rouge">usbip bind</code> for this, using <code class="language-plaintext highlighter-rouge">libusbip</code>.</li>
    </ul>
  </li>
</ul>

<h2 id="telling-apart-leaf-usb-devices-from-usb-hubs">Telling apart leaf USB devices from USB hubs</h2>

<p>Running <code class="language-plaintext highlighter-rouge">lsusb</code> with the <code class="language-plaintext highlighter-rouge">--tree</code> option returns this:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gd">--- log-without-hub     2022-02-05 12:26:40.311210251 +0100
</span><span class="gi">+++ log-with-hub        2022-02-05 12:26:35.234559166 +0100
</span><span class="p">@@ -1,11 +1,15 @@</span>
 /:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 10000M
     ID 1d6b:0003 Linux Foundation 3.0 root hub
<span class="gi">+    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 5000M
+        ID 05e3:0620 Genesys Logic, Inc. GL3523 Hub
</span> /:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 480M
     ID 1d6b:0002 Linux Foundation 2.0 root hub
 /:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/10p, 10000M
     ID 1d6b:0003 Linux Foundation 3.0 root hub
 /:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/16p, 480M
     ID 1d6b:0002 Linux Foundation 2.0 root hub
<span class="gi">+    |__ Port 4: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
+        ID 05e3:0610 Genesys Logic, Inc. Hub
</span>     |__ Port 8: Dev 2, If 3, Class=Video, Driver=uvcvideo, 480M
         ID 04f2:b6be Chicony Electronics Co., Ltd
     |__ Port 8: Dev 2, If 1, Class=Video, Driver=uvcvideo, 480M
</code></pre></div></div>

<p>The Genesys USB hub shows up twice, under two different trees: first the 3.0
root hub, and then the 2.0 root hub. If I connect a USB 3.0 device to the hub, it doesn’t matter which port I connect it to, it always shows up under the 3.0 tree of the root hub in my laptop:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gd">--- log-with-hub        2022-02-05 12:26:35.234559166 +0100
</span><span class="gi">+++ log-with-device     2022-02-05 12:37:10.480333271 +0100
</span><span class="p">@@ -1,14 +1,16 @@</span>
 /:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 10000M
     ID 1d6b:0003 Linux Foundation 3.0 root hub
<span class="gd">-    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 5000M
</span><span class="gi">+    |__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/4p, 5000M
</span>         ID 05e3:0620 Genesys Logic, Inc. GL3523 Hub
<span class="gi">+        |__ Port 2: Dev 7, If 0, Class=Mass Storage, Driver=usb-storage, 5000M
+            ID 090c:1000 Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.) Flash Drive
</span> /:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 480M
     ID 1d6b:0002 Linux Foundation 2.0 root hub
 /:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/10p, 10000M
     ID 1d6b:0003 Linux Foundation 3.0 root hub
 /:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/16p, 480M
     ID 1d6b:0002 Linux Foundation 2.0 root hub
<span class="gd">-    |__ Port 4: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
</span><span class="gi">+    |__ Port 4: Dev 6, If 0, Class=Hub, Driver=hub/4p, 480M
</span>         ID 05e3:0610 Genesys Logic, Inc. Hub
     |__ Port 8: Dev 2, If 3, Class=Video, Driver=uvcvideo, 480M
         ID 04f2:b6be Chicony Electronics Co., Ltd
</code></pre></div></div>

<p>It looks like <code class="language-plaintext highlighter-rouge">lsusb</code> has a way to tell apart hubs from leaf devices. I can
probably simply look at the device <code class="language-plaintext highlighter-rouge">Class</code> and check to see if it’s <code class="language-plaintext highlighter-rouge">root_hub</code>
or <code class="language-plaintext highlighter-rouge">Hub</code>. This could enable letting the user pick whether to bind a USB hub or
their root hub (any ports on the host device itself).</p>

<p>I’m still not certain as to whether I can get this <code class="language-plaintext highlighter-rouge">Class</code> information directly
from <code class="language-plaintext highlighter-rouge">libudev</code> or I’ll need to include some other dependency.</p>

<h2 id="listening-to-usb-devices-as-they-connect-and-disconnect">Listening to USB devices as they connect and disconnect</h2>

<p>I found this helpful post: <a href="http://cholla.mmto.org/computers/usb/OLD/tutorial_usbloger.html"><code class="language-plaintext highlighter-rouge">libudev</code> and Sysfs
Tutorial</a>. I won’t be following it so much, but it
seems like a good example. Running <code class="language-plaintext highlighter-rouge">man libudev</code> also seems helpful.</p>

<p>As a first step, I’m going to implement a busy loop that listens to connection
and disconnection events and just logs any interesting information to the
console.</p>

<p>From <code class="language-plaintext highlighter-rouge">man libudev</code>:</p>

<blockquote>
  <p>To monitor the local system for hotplugged or unplugged devices, a monitor
can be created via <code class="language-plaintext highlighter-rouge">udev_monitor_new_from_netlink</code>(3).</p>
</blockquote>

<p>Looks like <code class="language-plaintext highlighter-rouge">udev_monitor_new_from_netlink</code> takes a pointer to <code class="language-plaintext highlighter-rouge">udev</code> and a
<code class="language-plaintext highlighter-rouge">name</code>. To get a <code class="language-plaintext highlighter-rouge">udev</code> context object, I can call <code class="language-plaintext highlighter-rouge">udev_new</code>.</p>

<p>Aside: to set up a bit of a quicker feedback loop, I’m running
<a href="https://crates.io/crates/watchexec-cli"><code class="language-plaintext highlighter-rouge">watchexec</code></a>: <code class="language-plaintext highlighter-rouge">watchexec -c -w src -e c 'make &amp;&amp; ./target/usairb'</code>.</p>

<p>After adding <code class="language-plaintext highlighter-rouge">-ludev</code> to my Makefile, I wrote this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;libudev.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">UDEV_MONITOR_NAME</span> <span class="o">=</span> <span class="s">"usairb-udev-monitor"</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">struct</span> <span class="n">udev</span> <span class="o">*</span><span class="n">udev</span> <span class="o">=</span> <span class="n">udev_new</span><span class="p">();</span>
  <span class="k">struct</span> <span class="n">udev_monitor</span> <span class="o">*</span><span class="n">udev_monitor</span> <span class="o">=</span>
      <span class="n">udev_monitor_new_from_netlink</span><span class="p">(</span><span class="n">udev</span><span class="p">,</span> <span class="n">UDEV_MONITOR_NAME</span><span class="p">);</span>

  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">udev_monitor</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"udev_monitor_new_from_netlink returned NULL</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>My error message came to fruition instantly. <code class="language-plaintext highlighter-rouge">man libudev</code> says “on failure, <code class="language-plaintext highlighter-rouge">NULL</code> is returned”, but doesn’t mentions what the reasons for failure are.</p>

<p>I’m wondering if it’s <code class="language-plaintext highlighter-rouge">udev_new</code> that’s failing:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">udev</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"udev_new returned NULL</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>No, it’s our other friend:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>udev_monitor_new_from_netlink returned NULL
[[Command exited with 1]]
</code></pre></div></div>

<p>I solved it out of sheer luck: I changed the value passed to <code class="language-plaintext highlighter-rouge">name</code> to
<code class="language-plaintext highlighter-rouge">"udev"</code>, and now it’s working just fine. The takeaway: the <code class="language-plaintext highlighter-rouge">name</code> param is the
name of a known <a href="https://man7.org/linux/man-pages/man7/netlink.7.html">Netlink</a>. A Netlink is similar to a domain socket and
is used for IPC. It looks like there’s one for <code class="language-plaintext highlighter-rouge">"udev"</code>, and you need to
specify that.</p>

<p>Now I’m looking into what I can do with <code class="language-plaintext highlighter-rouge">udev_monitor</code>. The manual only
includes entries for functions (such as <code class="language-plaintext highlighter-rouge">udev_new</code>) but not for structs. Maybe
the monitor is meant to be passed around to other functions. How can I find
those? My copy of <a href="https://man7.org/tlpi/">The Linux Programming Interface</a> by Michael Kerrisk
only introduces <code class="language-plaintext highlighter-rouge">udev</code> at a high level but doesn’t go into detail. I guess it’s
time to read examples on the Internet, unfortunately. This makes me miss the
Rust ecosystem. Documentation generated by <code class="language-plaintext highlighter-rouge">rustdoc</code> would make
cross-referencing searches very easy.</p>

<p>One practical solution I’ve found (besides reading existing work on the Internet) is to let my shell help me: if I type <code class="language-plaintext highlighter-rouge">udev_monitor_</code> and ask for an autocompletion with tab, I get this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ~/Development/usairb <span class="o">=&gt;</span> man udev_monitor_
udev_monitor_enable_receiving                    udev_monitor_filter_update                       udev_monitor_receive_device
udev_monitor_filter_add_match_subsystem_devtype  udev_monitor_get_fd                              udev_monitor_ref
udev_monitor_filter_add_match_tag                udev_monitor_get_udev                            udev_monitor_set_receive_buffer_size
udev_monitor_filter_remove                       udev_monitor_new_from_netlink                    udev_monitor_unref
</code></pre></div></div>

<p>That’s good enough. I can also use <a href="https://www.lunarvim.org/">LunarVim</a>’s LSP hints. Two functions
look interesting: <code class="language-plaintext highlighter-rouge">udev_monitor_receive_device</code> and
<code class="language-plaintext highlighter-rouge">udev_monitor_enable_receiving</code>. The latter sounds like a prerequisite, but I’m
going to go without it at first and see what happens.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">udev_device</span> <span class="o">*</span><span class="n">device</span> <span class="o">=</span> <span class="n">udev_monitor_receive_device</span><span class="p">(</span><span class="n">udev_monitor</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Prints if `udev_monitor_receive_device` is not blocking."</span><span class="p">);</span>
</code></pre></div></div>

<p>It printed. I added a call to <code class="language-plaintext highlighter-rouge">udev_monitor_enable_receiving</code>, but the behavior
didn’t change. Looks like my assumption that it’s blocking isn’t holding up!</p>

<p>After some sleuthing in <code class="language-plaintext highlighter-rouge">systemd</code> source code, I found <a href="https://github.com/systemd/systemd/blob/be1eae4fad5562da5cb784c121981206d1b77254/src/libudev/libudev-monitor.c#L222-L240">this comment</a> that confirms that the call is non-blocking, and suggests two possible paths forward:</p>

<ul>
  <li>use a variant of <code class="language-plaintext highlighter-rouge">poll()</code> on the file descriptor returned by <code class="language-plaintext highlighter-rouge">udev_monitor_get_fd</code>, or</li>
  <li>switch the file descriptor into blocking mode.</li>
</ul>

<p>I don’t know how to do either of these things, so it’s time for some more reading.</p>

<p><a href="https://man7.org/tlpi/">TLPI</a> to the rescue! I can use <code class="language-plaintext highlighter-rouge">fcntl</code> to modify flags on the file descriptor returned by <code class="language-plaintext highlighter-rouge">udev_monitor_get_fd</code>.</p>

<p>Got it to work thanks to some bitwise-fu from <a href="https://stackoverflow.com/questions/914463/how-to-make-a-file-descriptor-blocking">a StackOverflow answer</a>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// udev_monitor_receive_device is non-blocking. To make it blocking,</span>
<span class="c1">// get the monitor file descriptor and unset its O_NONBLOCK flag.</span>
<span class="kt">int</span> <span class="n">udev_monitor_fd</span> <span class="o">=</span> <span class="n">udev_monitor_get_fd</span><span class="p">(</span><span class="n">udev_monitor</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">udev_monitor_fd_flags</span> <span class="o">=</span> <span class="n">fcntl</span><span class="p">(</span><span class="n">udev_monitor_fd</span><span class="p">,</span> <span class="n">F_GETFL</span><span class="p">);</span>
<span class="n">fcntl</span><span class="p">(</span><span class="n">udev_monitor_fd</span><span class="p">,</span> <span class="n">F_SETFL</span><span class="p">,</span> <span class="n">udev_monitor_fd_flags</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">O_NONBLOCK</span><span class="p">);</span>
</code></pre></div></div>

<p>I wrote a busy loop:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Listening for new devices...</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

  <span class="k">struct</span> <span class="n">udev_device</span> <span class="o">*</span><span class="n">device</span> <span class="o">=</span> <span class="n">udev_monitor_receive_device</span><span class="p">(</span><span class="n">udev_monitor</span><span class="p">);</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">device</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Found a device!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Aside: I added <code class="language-plaintext highlighter-rouge">-r</code> to my <code class="language-plaintext highlighter-rouge">watchexec</code> command so that it restarts the process
every time, otherwise the busy loop never exits.</p>

<p>The behavior is not quite what I expected: my program logs <code class="language-plaintext highlighter-rouge">"Found a device!"</code>
but it seems really excited about it and does it many times over on every
connection. Additionally, it does it when I disconnect a device. It feels like
a race condition.</p>

<p>To find out, I added a <code class="language-plaintext highlighter-rouge">sleep(1);</code> right after <code class="language-plaintext highlighter-rouge">printf("Found a device!\n");</code>.
To my surprise, my program still “finds the device” a bunch of times. Without
<code class="language-plaintext highlighter-rouge">sleep(1);</code>, it prints roughly the same amount of times.</p>

<p>After reading the documentation a bit more, I found some new clarifications:</p>

<ul>
  <li>The existence of <code class="language-plaintext highlighter-rouge">udev_device_get_parent</code> pointed out the fact that what I’m
seeing is a tree of devices, and not a single device. To find the root, I
looked for a device with no parent, and this returned the expected: only one
device. The root device always belongs to the <code class="language-plaintext highlighter-rouge">bdi</code> subsystem.</li>
  <li>The return value of <code class="language-plaintext highlighter-rouge">udev_device_get_action</code> may contain values like <code class="language-plaintext highlighter-rouge">"add"</code>,
<code class="language-plaintext highlighter-rouge">"remove"</code>, <code class="language-plaintext highlighter-rouge">"bind"</code> or <code class="language-plaintext highlighter-rouge">"unbind"</code>, among others. I should probably start
calling my variables <code class="language-plaintext highlighter-rouge">event</code> instead of <code class="language-plaintext highlighter-rouge">device</code>.</li>
</ul>

<p>If I run <code class="language-plaintext highlighter-rouge">udevadm monitor --udev</code>, I get exactly the same output (well, in a different format):</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ~/Development/usairb <span class="o">=&gt;</span> udevadm monitor <span class="nt">-u</span>
monitor will print the received events <span class="k">for</span>:
UDEV - the event which udev sends out after rule processing

UDEV  <span class="o">[</span>8858.969668] add      /devices/virtual/workqueue/scsi_tmf_0 <span class="o">(</span>workqueue<span class="o">)</span>
UDEV  <span class="o">[</span>8858.971981] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6 <span class="o">(</span>usb<span class="o">)</span>
UDEV  <span class="o">[</span>8858.973386] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0 <span class="o">(</span>usb<span class="o">)</span>
UDEV  <span class="o">[</span>8858.974132] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0 <span class="o">(</span>scsi<span class="o">)</span>
UDEV  <span class="o">[</span>8858.974950] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/scsi_host/host0 <span class="o">(</span>scsi_host<span class="o">)</span>
UDEV  <span class="o">[</span>8858.975633] <span class="nb">bind</span>     /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0 <span class="o">(</span>usb<span class="o">)</span>
UDEV  <span class="o">[</span>8858.978815] <span class="nb">bind</span>     /devices/pci0000:00/0000:00:14.0/usb2/2-6 <span class="o">(</span>usb<span class="o">)</span>
UDEV  <span class="o">[</span>8860.074537] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0 <span class="o">(</span>scsi<span class="o">)</span>
UDEV  <span class="o">[</span>8860.075845] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0/0:0:0:0 <span class="o">(</span>scsi<span class="o">)</span>
UDEV  <span class="o">[</span>8860.075899] add      /devices/virtual/bdi/8:0 <span class="o">(</span>bdi<span class="o">)</span>
UDEV  <span class="o">[</span>8860.077712] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0/0:0:0:0/scsi_device/0:0:0:0 <span class="o">(</span>scsi_device<span class="o">)</span>
UDEV  <span class="o">[</span>8860.078456] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0/0:0:0:0/bsg/0:0:0:0 <span class="o">(</span>bsg<span class="o">)</span>
UDEV  <span class="o">[</span>8860.078522] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0/0:0:0:0/scsi_disk/0:0:0:0 <span class="o">(</span>scsi_disk<span class="o">)</span>
UDEV  <span class="o">[</span>8860.131761] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0/0:0:0:0/block/sda <span class="o">(</span>block<span class="o">)</span>
UDEV  <span class="o">[</span>8860.244986] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2 <span class="o">(</span>block<span class="o">)</span>
UDEV  <span class="o">[</span>8860.258575] add      /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1 <span class="o">(</span>block<span class="o">)</span>
UDEV  <span class="o">[</span>8860.259622] <span class="nb">bind</span>     /devices/pci0000:00/0000:00:14.0/usb2/2-6/2-6:1.0/host0/target0:0:0/0:0:0:0 <span class="o">(</span>scsi<span class="o">)</span>
</code></pre></div></div>

<p>Looks like new devices are added for different things: the partitions in my USB
flash drive, some accessors for protocols I don’t understand (SCSI), etc.</p>

<p>Since they all point to the same thing in <code class="language-plaintext highlighter-rouge">/sys/devices</code>, I think I can just
filter for events for which <code class="language-plaintext highlighter-rouge">udev_device_get_devtype</code> returns <code class="language-plaintext highlighter-rouge">"usb_device"</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">device_type</span> <span class="o">=</span> <span class="n">udev_device_get_devtype</span><span class="p">(</span><span class="n">device</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">device_type</span> <span class="o">||</span> <span class="n">strcmp</span><span class="p">(</span><span class="n">device_type</span><span class="p">,</span> <span class="s">"usb_device"</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">continue</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">printf</span><span class="p">(</span><span class="s">"Found a USB device:</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="c1">// ...</span>
</code></pre></div></div>

<p>Now, I get only two events for each physical action: <code class="language-plaintext highlighter-rouge">add</code> and <code class="language-plaintext highlighter-rouge">bind</code> (in that
order) when plugging in the device and <code class="language-plaintext highlighter-rouge">remove</code> and <code class="language-plaintext highlighter-rouge">unbind</code> when unplugging
it. For now, I’m only going to care about <code class="language-plaintext highlighter-rouge">add</code> and <code class="language-plaintext highlighter-rouge">remove</code>, and we’ll see
about this later!</p>

<p>Currently, the output looks like this when I plug a USB flash drive in and out:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Found a USB device:
   Node: /dev/bus/usb/002/026
   Subsystem: usb
   Devtype: usb_device
   Action: add
Found a USB device:
   Node: /dev/bus/usb/002/026
   Subsystem: usb
   Devtype: usb_device
   Action: remove
</code></pre></div></div>

<p>When I do the same with my USB hub, I get two distinct devices:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Found a USB device:
   Node: /dev/bus/usb/001/026
   Subsystem: usb
   Devtype: usb_device
   Action: add
Found a USB device:
   Node: /dev/bus/usb/004/015
   Subsystem: usb
   Devtype: usb_device
   Action: add
Found a USB device:
   Node: /dev/bus/usb/001/026
   Subsystem: usb
   Devtype: usb_device
   Action: remove
Found a USB device:
   Node: /dev/bus/usb/004/015
   Subsystem: usb
   Devtype: usb_device
   Action: remove
</code></pre></div></div>

<p>This is because, like we saw earlier, my hub registers once as a USB 2.0 device
and once again as a USB 3.0 device.</p>

<p>I’m calling this one a success! Next time I get a chance to work on this, I’ll
be working on binding these devices automatically using <code class="language-plaintext highlighter-rouge">libusbip</code>. Thanks for
reading!</p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><category term="devlog" /><category term="usairb" /><summary type="html"><![CDATA[Entry #1 of the usairb development log (USB/IP and embedded Linux)]]></summary></entry><entry><title type="html">First thoughts on Remix</title><link href="https://fnune.com/2021/12/24/first-thoughts-on-remix/" rel="alternate" type="text/html" title="First thoughts on Remix" /><published>2021-12-24T16:29:51+00:00</published><updated>2021-12-24T16:29:51+00:00</updated><id>https://fnune.com/2021/12/24/first-thoughts-on-remix</id><content type="html" xml:base="https://fnune.com/2021/12/24/first-thoughts-on-remix/"><![CDATA[<p>I gave <a href="https://remix.run">Remix</a> a quick spin following their “Jokes App” <a href="https://remix.run/docs/en/v1/tutorials/jokes">tutorial</a>
and gathered some notes. These are just my initial thoughts during my first contact with the
framework. For a proper introduction, read <a href="https://remix.run/docs/en/v1">the documentation</a>.</p>

<figure>
  <blockquote cite="https://remix.run">
    Remix is a seamless server and browser runtime that provides snappy page loads and instant
    transitions by leveraging distributed systems and native browser features instead of clunky static
    builds. Built on the Web Fetch API (instead of Node) it can run anywhere. It already runs natively
    on Cloudflare Workers, and of course supports serverless and traditional Node.js environments, so
    you can come as you are.
  </blockquote>
  <figcaption>From the Remix homepage.</figcaption>
</figure>

<p>The website is the result of a great amount of marketing effort. It’s amazing what JS frameworks do
these days to get noticed. Regardless of whether the framework lives up to the hype or not, I get a
strange feeling from the website: the language attempts to be humorous and light, and this doesn’t
help me build trust.</p>

<p>From my notes, the most interesting parts are probably on <a href="#the-scrollrestoration--component">the <code class="language-plaintext highlighter-rouge">&lt;ScrollRestoration /&gt;</code>
component</a> and on <a href="#on-typescript-use">the <code class="language-plaintext highlighter-rouge">loader</code> pattern</a>.</p>

<h2 id="on-setting-up-remix">On setting up Remix</h2>

<ul>
  <li>Remix nuked my <code class="language-plaintext highlighter-rouge">README.md</code> file (on which I already had some notes) and I had to recreate it.
Should have expected that!</li>
  <li>Since Remix picks up on certain exports from files (like <code class="language-plaintext highlighter-rouge">export const meta</code>) but my IDE doesn’t
know about that, I’m getting a bunch of “unused export” linter errors on those lines. I’m not sure
where the errors are coming from, since from my recollection <code class="language-plaintext highlighter-rouge">eslint</code> doesn’t complain about
unused exports. It has no knowledge of the other files. It’s probably IntelliJ, then.</li>
  <li>The default <code class="language-plaintext highlighter-rouge">root.tsx</code> contains several interesting elements:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">&lt;Outlet /&gt;</code> which is like a Svelte <code class="language-plaintext highlighter-rouge">&lt;slot /&gt;</code>: it renders children components.</li>
      <li><code class="language-plaintext highlighter-rouge">&lt;ScrollRestoration /&gt;</code>, probably aptly-named. Its presence surprises me because this used to be
a feature of <code class="language-plaintext highlighter-rouge">react-router</code> that got <a href="https://v5.reactrouter.com/web/guides/scroll-restoration">dropped</a> after the developers noticed
scroll restoration working increasingly better out of the box on major browsers.
        <ul class="task-list">
          <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" checked="checked" /><code class="language-plaintext highlighter-rouge">TODO</code>: find
    out <a href="#the-scrollrestoration--component">how <code class="language-plaintext highlighter-rouge">&lt;ScrollRestoration /&gt;</code> is implemented</a>.</li>
          <li class="task-list-item">Remix <a href="https://remix.run/docs/en/v1/api/remix#scrollrestoration">documentation on scroll restoration</a> mentions that this component works
by restoring the scroll level before rehydration. This should eliminate the jarring effect of
having the scroll point being restored after the page loads completely.
            <ul>
              <li>The “before rehydration” part is true only by virtue of the <code class="language-plaintext highlighter-rouge">&lt;ScrollRestoration /&gt;</code>
component being used one line before the <code class="language-plaintext highlighter-rouge">&lt;Scripts /&gt;</code> component.</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>The <code class="language-plaintext highlighter-rouge">yarn build</code> command finished in 0.44 seconds. Nice!</li>
  <li>I like that the default app doesn’t contain images or marketing text selling Remix. It just has
some documentation links.</li>
</ul>

<h3 id="the-scrollrestoration--component">The <code class="language-plaintext highlighter-rouge">&lt;ScrollRestoration /&gt;</code> component</h3>

<p>It’s implemented <a href="https://github.com/remix-run/remix/blob/1fd70960e4d88740df5bf407a6ba2cd2b9549459/packages/remix-react/scroll-restoration.tsx">here</a> and works roughly so:</p>

<ul>
  <li>It disables the browser implementation with <code class="language-plaintext highlighter-rouge">window.history.scrollRestoration = "manual"</code>, but
only in a <code class="language-plaintext highlighter-rouge">useEffect</code> call that runs after <code class="language-plaintext highlighter-rouge">useLayoutEffect</code> (used for other effects in the
component).</li>
  <li>Provides a <code class="language-plaintext highlighter-rouge">&lt;script&gt;</code> tag that runs a simpler effect (it’s simpler because it doesn’t need to know
about browser history, since it runs only on the initial script load before hydration).</li>
  <li>Only after the component has hydrated does the component run some more complex logic (e.g. to
respect <code class="language-plaintext highlighter-rouge">location.hash</code>) that ultimately may run <code class="language-plaintext highlighter-rouge">scrollTo(0, position)</code>.</li>
  <li>Scroll positions are stored in an in-memory <code class="language-plaintext highlighter-rouge">positions</code> dictionary where the keys
are <code class="language-plaintext highlighter-rouge">location.key</code>s.</li>
  <li>To survive for longer, <code class="language-plaintext highlighter-rouge">positions</code> gets added to <code class="language-plaintext highlighter-rouge">localStorage</code> and is used to restore <code class="language-plaintext highlighter-rouge">positions</code>
into memory when the script runs again.</li>
</ul>

<h2 id="on-first-contact-dx">On first-contact DX</h2>

<ul>
  <li>Live reload works great and spinning up the development server takes no time.</li>
  <li>While adding some code and missing an import, the app showed me a build error (expectedly). But
then after fixing the error, the app didn’t go back to a normal state, and the error remained,
even though the build didn’t show the error any longer.</li>
  <li>Adding the new routes, I’m thinking that the structure recommended by the tutorial
where <code class="language-plaintext highlighter-rouge">jokes/new</code> shares a namespace with <code class="language-plaintext highlighter-rouge">jokes/$jokeId</code> is not great. What if I wanted slugs
instead of IDs, and someone created a joke titled <code class="language-plaintext highlighter-rouge">new</code>? Other solutions aren’t as pretty,
though: <code class="language-plaintext highlighter-rouge">jokes/show/$jokeId + jokes/new</code>, or <code class="language-plaintext highlighter-rouge">new-joke + jokes/$jokeId</code>.</li>
  <li>By exporting a <code class="language-plaintext highlighter-rouge">links</code> array, you can add <code class="language-plaintext highlighter-rouge">&lt;link&gt;</code> elements to <code class="language-plaintext highlighter-rouge">&lt;head&gt;</code> sort of like
with <a href="https://github.com/nfl/react-helmet"><code class="language-plaintext highlighter-rouge">react-helmet</code></a>. They then get picked up by a top-level <code class="language-plaintext highlighter-rouge">&lt;Links /&gt;</code> component.</li>
  <li>The tutorial recommends a file structure for styles that’s not great: a <code class="language-plaintext highlighter-rouge">styles</code> directory
separate from other parts of the app, such as <code class="language-plaintext highlighter-rouge">routes</code>. If the CSS I write is encapsulated
together with a route, then why shouldn’t their files live together? Having a separate <code class="language-plaintext highlighter-rouge">styles</code>
directory adds quite a bit of indirection and could make a project hard to navigate.</li>
</ul>

<h2 id="on-typescript-use">On TypeScript use</h2>

<ul>
  <li>The default <code class="language-plaintext highlighter-rouge">entry.server.tsx</code> file contains a <code class="language-plaintext highlighter-rouge">handleRequest</code> function that takes a <code class="language-plaintext highlighter-rouge">request</code>.
That’s fine, but it also takes a <code class="language-plaintext highlighter-rouge">responseStatusCode</code> and <code class="language-plaintext highlighter-rouge">responseHeaders</code>. Am I still able to
decide what status code to respond with? This signature is a bit weird to me.
    <ul>
      <li>Looks like there’s a default <code class="language-plaintext highlighter-rouge">200</code> response and I still have a chance to change it, as expected.
Still, the signature feels awkward.</li>
    </ul>
  </li>
  <li>I wonder why the tutorial recommends using <code class="language-plaintext highlighter-rouge">export let</code>. It looks to me as if the things I’m
exporting shouldn’t ever be reassigned. I’m changing these to <code class="language-plaintext highlighter-rouge">export const</code>, hoping that nothing
explodes.
    <ul>
      <li>It looks like in other areas of their documentation they use <code class="language-plaintext highlighter-rouge">export const</code>, which makes more
sense.</li>
    </ul>
  </li>
  <li>The <code class="language-plaintext highlighter-rouge">loader</code> pattern (see <a href="https://remix.run/docs/en/v1/api/conventions#loader">related docs</a>) with an <code class="language-plaintext highlighter-rouge">export const loader</code> coupled with a
<code class="language-plaintext highlighter-rouge">useLoaderData</code> call imported from <code class="language-plaintext highlighter-rouge">remix</code> feels a bit weird to me. I suppose there must be quite
a bit going on at hydration time for this to be worth the indirection. My first impression is that
it shouldn’t be necessary? Why can’t I go <code class="language-plaintext highlighter-rouge">export const loader = someRemixUtility(async () =&gt; {})</code> instead, removing the <code class="language-plaintext highlighter-rouge">useLoaderData</code> call inside the component? The client and server
bundles can still provide different implementations of <code class="language-plaintext highlighter-rouge">someRemixUtility</code>.
    <ul class="task-list">
      <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" checked="checked" /><code class="language-plaintext highlighter-rouge">TODO</code>: find out why <code class="language-plaintext highlighter-rouge">export const loader</code> can’t be used directly and needs to be accessed
    via <code class="language-plaintext highlighter-rouge">useLoaderData</code>. My guess: the purpose is to call the loader during server rendering and
    then to reuse the same data during rehydration, to initialize a frontend cache with. Remix
    developers simply decided to go for a standard way to access Remix functionality, and this just
    looks consistent.
        <ul>
          <li>It looks like I was correct: Remix <a href="https://github.com/remix-run/remix/blob/1fd70960e4d88740df5bf407a6ba2cd2b9549459/packages/remix-server-runtime/server.ts#L448-L453">hands off</a> serialized data to the client
as a string and then has the client route reuse this data. It works similarly to
what <a href="https://www.apollographql.com/docs/react/performance/server-side-rendering/#executing-queries-with-getdatafromtree">Apollo GraphQL recommends</a>.</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>There’s another insidious result of the indirection introduced by the <code class="language-plaintext highlighter-rouge">useLoaderData</code>
and <code class="language-plaintext highlighter-rouge">export const loader</code> pattern, aggravated by the fact that the suggested type <code class="language-plaintext highlighter-rouge">LoaderFunction</code>
isn’t generic: discrepancies between what <code class="language-plaintext highlighter-rouge">loader</code> actually returns and what <code class="language-plaintext highlighter-rouge">useLoaderData</code>
returns aren’t going to be caught unless a type is shared between them. But <code class="language-plaintext highlighter-rouge">LoaderFunction</code> isn’t
generic, so there’s no enforcement from Remix to make sure that this is the case. I can have
a <code class="language-plaintext highlighter-rouge">loader</code> that returns <code class="language-plaintext highlighter-rouge">number</code> but then access <code class="language-plaintext highlighter-rouge">string[]</code> in <code class="language-plaintext highlighter-rouge">useLoaderData</code> and unless I
actively share the types, TypeScript won’t have a chance to complain. In my
opinion, <code class="language-plaintext highlighter-rouge">LoaderFunction</code> should take a required type argument for the return type, and another for query parameters, which can probably be optional.
    <ul>
      <li>One could argue that this is the responsibility of the developer, and it is, but by not
requiring any type arguments, Remix isn’t helping.</li>
      <li>It’s also inconsistent because <code class="language-plaintext highlighter-rouge">LoaderFunction</code> takes no type arguments but <code class="language-plaintext highlighter-rouge">useLoaderData</code>
takes a type argument for the returned data.</li>
    </ul>
  </li>
  <li>When submitting data, the type mismatch is more accentuated, because <code class="language-plaintext highlighter-rouge">POST</code> requests
contain <code class="language-plaintext highlighter-rouge">FormData</code>, which bears (as far as I know) no information on the shape of the data from
the form. In this case, however, it matters less, because the tutorial calls the user to perform
backend validation/parsing of this form data, by going <code class="language-plaintext highlighter-rouge">form.get("field-name")</code> and then
validating the result.
    <ul>
      <li>I wonder whether building a way to type-check JSX forms and providing e.g. a TS <code class="language-plaintext highlighter-rouge">eslint</code> plug-in
that uses the full power of the AST to build type-safe forms would be worth it. I suppose
exporting a simple component for use, <code class="language-plaintext highlighter-rouge">TypedForm&lt;T&gt;</code> would be enough, or perhaps even more
magic, somehow simply type-check <code class="language-plaintext highlighter-rouge">&lt;form&gt;</code> elements based on their current children. This is
probably not possible because one would need to go into other modules. Maybe the <code class="language-plaintext highlighter-rouge">TypedForm&lt;T&gt;</code>
approach is good as long as one shares <code class="language-plaintext highlighter-rouge">T</code> with child controls.</li>
    </ul>
  </li>
</ul>

<p>That’s it for now! I’ll probably give Remix a proper try once I have a need for it. I feel like the
typing issues I mentioned can be avoided through discipline, and the DX looks promising.</p>

<p>Relevant documentation:</p>

<ul>
  <li><a href="https://remix.run/docs/en/v1">Remix documentation</a></li>
  <li><a href="https://remix.run/docs/en/v1/api/conventions#loader">The <code class="language-plaintext highlighter-rouge">loader</code> pattern in Remix</a></li>
  <li><a href="https://v5.reactrouter.com/web/guides/scroll-restoration">React Router documentation on scroll restoration</a></li>
  <li><a href="https://reactjs.org/docs/hooks-reference.html#uselayouteffect"><code class="language-plaintext highlighter-rouge">useLayoutEffect</code> documentation</a></li>
</ul>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><summary type="html"><![CDATA[I gave Remix a quick spin following their main tutorial and gathered some notes, focusing on the TypeScript]]></summary></entry><entry><title type="html">Nuking most of my .vimrc and just using LunarVim</title><link href="https://fnune.com/2021/11/20/nuking-most-of-my-vimrc-and-just-using-lunarvim/" rel="alternate" type="text/html" title="Nuking most of my .vimrc and just using LunarVim" /><published>2021-11-20T19:35:51+00:00</published><updated>2021-11-20T19:35:51+00:00</updated><id>https://fnune.com/2021/11/20/nuking-most-of-my-vimrc-and-just-using-lunarvim</id><content type="html" xml:base="https://fnune.com/2021/11/20/nuking-most-of-my-vimrc-and-just-using-lunarvim/"><![CDATA[<p>The recent developments that landed with Neovim 0.5 provide it with built-in support for the <a href="https://neovim.io/doc/lsp/">Language Server Protocol</a>. Before <a href="https://github.com/fnune/dotfiles/commit/64c128c8cebbf8296eb1326a034bc766ece27ae2">adopting this new feature</a> I had been using the wonderful <a href="https://github.com/neoclide/coc.nvim">coc.nvim</a> for my language server needs. With all the new tricks Neovim was learning, the amount of work I needed to do to get everything working the way I wanted increased steadily.</p>

<p>My configuration became a Frankenstein of Lua and Vimscript, and this came with unexpected drawbacks such as having a syntax error in the middle of a Lua block be reported as if it had happened at the beginning of the block.</p>

<p>Setting up Neovim to work like an IDE was starting to become a maintenance burden for me, and I didn’t have the patience to clean it all up again. Enter <a href="https://www.lunarvim.org">LunarVim</a>:</p>

<blockquote>
  <p>LunarVim is an opinionated, extensible, and fast IDE layer for Neovim &gt;= 0.5.0. LunarVim takes advantage of the latest Neovim features such as Treesitter and Language Server Protocol support.</p>
</blockquote>

<p>That is exactly what I needed! In this post, I’m going to cover my efforts in translating my existing, years-old Neovim configuration into a LunarVim configuration that behaves roughly the same. Some spoilers:</p>

<ul>
  <li>My Neovim configuration wasn’t as personal as I thought it was. As it turns out, vanilla LunarVim ticks almost all the boxes for me, and it appears so does it for over <a href="https://github.com/LunarVim/LunarVim/stargazers">six thousand users</a> on GitHub. <a href="https://github.com/fnune/dotfiles/blob/master/lvim/.config/lvim/config.lua">My LunarVim configuration</a> has 69 lines of Lua at the time of writing, whereas <a href="https://github.com/fnune/dotfiles/tree/master/neovim/.config/nvim">my Neovim config</a> has 5 files and a whopping 439 lines of code.</li>
  <li>Adapting LunarVim to my needs has mostly been a breeze, but I did have to investigate a little bit more into a couple of issues.</li>
  <li>The UX inside of LunarVim is welcoming, discoverable and forgiving, so I would recommend it to Vim users who are just about done getting familiar with basic editing skills.</li>
</ul>

<h2 id="keybindings">Keybindings</h2>

<p>Most of <a href="https://github.com/fnune/dotfiles/blob/master/neovim/.config/nvim/mappings.vim">my mappings</a> ended up being redundant.</p>

<p>LunarVim makes excellent use of <a href="https://github.com/folke/which-key.nvim"><code class="language-plaintext highlighter-rouge">which-key</code></a>, a pop-up window that suggests options to help you complete a keybinding.</p>

<figure>
  <img src="/img/lvim/which-key-leader.png" alt="The which-key plugin in LunarVim after pressing the leader key" />
  <figcaption>The which-key plugin in LunarVim after pressing the leader key</figcaption>
</figure>

<p>There’s the reassuring certainty that I’ll be able to find the keybinding again if I’ve found it once, by exploring the nested menus that update as you select an option.</p>

<p>Once I’ve learned a combination, however, it quickly becomes second nature: the keys are simply well-chosen. I remembered my first experience with <a href="https://magit.vc/">Magit</a> as I found that the combination to <em>search</em> for <em>text</em> is <code class="language-plaintext highlighter-rouge">st</code>, and as I realized that this bit of knowledge would allow me to discover other things that are searchable, by just pressing <code class="language-plaintext highlighter-rouge">s</code> and waiting <code class="language-plaintext highlighter-rouge">timeoutlen</code> milliseconds for the <code class="language-plaintext highlighter-rouge">which-key</code> pop-up to appear.</p>

<p>I did end up adding exactly four keybindings that I missed:</p>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">vim</span><span class="p">.</span><span class="n">cmd</span><span class="p">(</span><span class="s2">"map 0 ^"</span><span class="p">)</span>
</code></pre></div></div>

<figure>
  <img src="/img/lvim/zero.png" alt="map 0 ^" />
  <figcaption>I rarely want my cursor to go to position (2). By default, <code class="language-plaintext highlighter-rouge">0</code> takes you to the first column, but I want it to take me to the first character in the line.</figcaption>
</figure>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">vim</span><span class="p">.</span><span class="n">cmd</span><span class="p">(</span><span class="s2">"nnoremap Q &lt;nop&gt;"</span><span class="p">)</span>
</code></pre></div></div>

<figure>
  <img src="/img/lvim/ex.png" alt="nnoremap Q nop" />
  <figcaption>I <a href="https://vi.stackexchange.com/questions/457/does-ex-mode-have-any-practical-use">never became friends with Ex mode</a>, and seeing this always frustrated me, so I disabled its keybinding.</figcaption>
</figure>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">vim</span><span class="p">.</span><span class="n">cmd</span><span class="p">(</span><span class="s2">"nnoremap j gj"</span><span class="p">)</span>
<span class="n">vim</span><span class="p">.</span><span class="n">cmd</span><span class="p">(</span><span class="s2">"nnoremap k gk"</span><span class="p">)</span>
</code></pre></div></div>

<figure>
  <img src="/img/lvim/gj.png" alt="nnoremap j gj" />
  <figcaption>If you write prose and you’ve enabled line-wrapping, then remapping <code class="language-plaintext highlighter-rouge">j</code> to <code class="language-plaintext highlighter-rouge">gj</code> and <code class="language-plaintext highlighter-rouge">k</code> to <code class="language-plaintext highlighter-rouge">gk</code> is a great idea. Pressing <code class="language-plaintext highlighter-rouge">j</code> here will take me to position (1) and not (2).</figcaption>
</figure>

<h2 id="fuzzy-finder">Fuzzy finder</h2>

<p>I’ve used the magnificent <a href="https://github.com/junegunn/fzf.vim"><code class="language-plaintext highlighter-rouge">fzf.vim</code></a> for some years now. LunarVim comes with <a href="https://github.com/nvim-telescope/telescope.nvim">Telescope</a>, though, and there are some things I’m enjoying about it.</p>

<p>One of them is that it simply looks great: it goes really well together with a patched font (in this case <code class="language-plaintext highlighter-rouge">Cascadia Code SemiLight</code>) thanks to the iconography, and the preview on the right is syntax-highlighted, and it’ll hide responsively depending on the available size of the terminal.</p>

<figure>
  <img src="/img/lvim/telescope.png" alt="Telescope in LunarVim" />
  <figcaption>It just looks beautiful</figcaption>
</figure>

<p>Each fragment in a file path can be truncated to fit a longer path in the screen. I thought this would be confusing at first, but I’ve had no trouble with it.</p>

<p>I have no complaints about the file fuzzy finder, but the “live grep” functionality has one big drawback. With <code class="language-plaintext highlighter-rouge">fzf.vim</code>, I used to be able to do this:</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">:</span>Rg search_string
</code></pre></div></div>

<p>This would pop up a view similar to Telescope, and I could fuzzy-filter <em>the search results</em>. This was incredibly useful, for example, if I want to find <code class="language-plaintext highlighter-rouge">search_string</code> but realize after the fact that most results are in Python files, while I’m interested in the TypeScript results. I would then simply type <code class="language-plaintext highlighter-rouge">.ts</code> and get all files containing <code class="language-plaintext highlighter-rouge">search_string</code> in TypeScript files only. Very flexible!</p>

<p>Unfortunately, this is not possible in vanilla Telescope, and I’ve yet to find a solution for this. It is a big part of my daily workflow, so I might revert to <code class="language-plaintext highlighter-rouge">fzf.vim</code> for my text-search needs.</p>

<div id="grep-input-string" />

<p><em>Thanks to <a href="https://old.reddit.com/r/neovim/comments/qysjgf/nuking_most_of_my_vimrc_and_just_using_lunarvim/hljkbz5/">two helpful Redditors</a>, I’ve managed to find a solution for this. With the following snippet, pressing <code class="language-plaintext highlighter-rouge">&lt;leader&gt;sT</code> will do something very similar to <code class="language-plaintext highlighter-rouge">:Rg</code>, and will also take the word under the cursor as an initial value:</em></p>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="nf">GrepInputString</span><span class="p">()</span>
  <span class="kd">local</span> <span class="n">default</span> <span class="o">=</span> <span class="n">vim</span><span class="p">.</span><span class="n">api</span><span class="p">.</span><span class="n">nvim_eval</span><span class="p">(</span><span class="s">[[expand("&lt;cword&gt;")]]</span><span class="p">)</span>
  <span class="kd">local</span> <span class="n">input</span> <span class="o">=</span> <span class="n">vim</span><span class="p">.</span><span class="n">fn</span><span class="p">.</span><span class="n">input</span><span class="p">({</span>
    <span class="n">prompt</span> <span class="o">=</span> <span class="s2">"Search for: "</span><span class="p">,</span>
    <span class="n">default</span> <span class="o">=</span> <span class="n">default</span><span class="p">,</span>
  <span class="p">})</span>
  <span class="nb">require</span><span class="p">(</span><span class="s2">"telescope.builtin"</span><span class="p">).</span><span class="n">grep_string</span><span class="p">({</span> <span class="n">search</span> <span class="o">=</span> <span class="n">input</span> <span class="p">})</span>
<span class="k">end</span>
<span class="n">lvim</span><span class="p">.</span><span class="n">builtin</span><span class="p">.</span><span class="n">which_key</span><span class="p">.</span><span class="n">mappings</span><span class="p">[</span><span class="s2">"sT"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">"&lt;cmd&gt;lua GrepInputString()&lt;CR&gt;"</span><span class="p">,</span> <span class="s2">"Text under cursor"</span> <span class="p">}</span>
</code></pre></div></div>

<h2 id="file-explorer">File explorer</h2>

<p>I was a happy user of <a href="https://github.com/jarun/nnn"><code class="language-plaintext highlighter-rouge">nnn</code></a>, a terminal file explorer with <a href="https://github.com/mcchrish/nnn.vim">a Vim plugin</a>. It’s great, but some features are compile-in, which may be a nuisance to some.</p>

<p>LunarVim comes with <a href="https://github.com/kyazdani42/nvim-tree.lua"><code class="language-plaintext highlighter-rouge">nvim-tree</code></a>. Honestly, I can’t complain. I wasn’t an advanced user of <code class="language-plaintext highlighter-rouge">nnn</code>. In <code class="language-plaintext highlighter-rouge">nvim-tree</code>, all features are quickly discoverable by entering <code class="language-plaintext highlighter-rouge">g?</code> (“go to help”, in and of itself an easily discoverable combination).</p>

<figure>
  <img src="/img/lvim/nvim-tree.png" alt="nvim-tree in LunarVim" />
  <figcaption>The file explorer opens with the file from the current buffer selected. It also (in my opinion) benefits greatly from the patched font.</figcaption>
</figure>

<h2 id="git-interface">Git interface</h2>

<p>During <a href="/2017/12/27/making-emacs-work-like-my-vim-setup">my time using Emacs</a> I became a fan of <a href="https://magit.vc/">Magit</a>. It’s a great piece of software that changed my expectations of what a Git interface can do.</p>

<p>Since then, I’ve been through different solutions, including using an always-running <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html">Emacs instance in server mode</a> running only Magit, which I accessed inside of Neovim and other programs. Later on, I used <a href="https://github.com/tpope/vim-fugitive">tpope’s <code class="language-plaintext highlighter-rouge">vim-fugitive</code></a> and tried to adapt <a href="https://github.com/fnune/dotfiles/blob/master/neovim/.config/nvim/mappings.vim#L74-L84">some Magit-inspired combinations</a> such as <code class="language-plaintext highlighter-rouge">p-fp</code> for “push”, “force”, “push”.</p>

<p>LunarVim’s porcelain of choice is <a href="https://github.com/jesseduffield/lazygit"><code class="language-plaintext highlighter-rouge">lazygit</code></a>. I’d been meaning to try <code class="language-plaintext highlighter-rouge">lazygit</code> for a while now, and this was the perfect opportunity. The “unboxing” experience was great: <code class="language-plaintext highlighter-rouge">lazygit</code> shows a link to <a href="https://www.youtube.com/watch?v=CPLdltN7wgE">a YouTube video</a> by the author Jesse Duffield. I can’t make the software justice in this introduction, so I would recommend that you simply try it out.</p>

<figure>
  <img src="/img/lvim/lazygit.png" alt="lazygit in LunarVim" />
  <figcaption>Obligatory screenshot. Please <a href="https://www.youtube.com/watch?v=CPLdltN7wgE">watch the YouTube video</a> for a proper introduction.</figcaption>
</figure>

<p>One minor drawback of using <code class="language-plaintext highlighter-rouge">lazygit</code> inside of Neovim is that its <code class="language-plaintext highlighter-rouge">open</code> and <code class="language-plaintext highlighter-rouge">edit</code> commands when pointing at files will open a nested <code class="language-plaintext highlighter-rouge">$EDITOR</code> inside of the <code class="language-plaintext highlighter-rouge">lazygit</code> terminal. With <code class="language-plaintext highlighter-rouge">vim-fugitive</code>, opening a file in its UI would simply reuse the current Neovim instance. I had this expectation of <code class="language-plaintext highlighter-rouge">lazygit</code> running inside LunarVim as well. I’ve read about using <a href="https://github.com/mhinz/neovim-remote">Neovim in remote mode</a> to solve this, but I haven’t gotten around to it. I do feel like if LunarVim picks <code class="language-plaintext highlighter-rouge">lazygit</code> as its integrated Git interface, it could also come with a working solution for this.</p>

<h2 id="verdict">Verdict</h2>

<p>I think I’ll keep using LunarVim. With my old configuration, It’s a rare week if I don’t need to fix one or two things on one of my LSP setups, or any of the IDE-like features that Neovim plugins offer. This all just works mostly out of the box on LunarVim, and not having to maintain this is a great relief. I’m looking forward to not being in complete control of this.</p>

<p>If you can relate, I’d like to invite you to give <a href="https://www.lunarvim.org">LunarVim</a> a try and see if you like it. Thanks for reading my blog!</p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><summary type="html"><![CDATA[Setting up Neovim to work like an IDE has become a maintenance burden. LunarVim looks like a promising solution that abstracts this away from me, so let's give it a try!]]></summary></entry><entry><title type="html">Embedded learning log – Running a FreeRTOS recurring task</title><link href="https://fnune.com/embedded-learning-log/2021/02/21/embedded-learning-log-3-running-a-recurring-freertos-task/" rel="alternate" type="text/html" title="Embedded learning log – Running a FreeRTOS recurring task" /><published>2021-02-21T19:00:51+00:00</published><updated>2021-02-21T19:00:51+00:00</updated><id>https://fnune.com/embedded-learning-log/2021/02/21/embedded-learning-log-3-running-a-recurring-freertos-task</id><content type="html" xml:base="https://fnune.com/embedded-learning-log/2021/02/21/embedded-learning-log-3-running-a-recurring-freertos-task/"><![CDATA[<blockquote>
  <p>This post is part of a series where I log my experience getting into embedded software development. The overarching goal is to use the <a href="https://docs.espressif.com/projects/esp8266-rtos-sdk">ESP8266 RTOS SDK</a> to learn how to operate my ESP8266 board using an RTOS and to learn how to integrate the <a href="https://docs.memfault.com/">Memfault real-time SDK</a>. Disclaimer: I work for Memfault as a full-stack engineer, mostly on web stuff. Here are the other posts in the series:</p>
  <ul>
    
      
        <li>
          <a href="/embedded-learning-log/2021/02/21/embedded-learning-log-4-integrating-the-memfault-firmware-sdk/">
            <span>Embedded learning log – Integrating the Memfault Firmware SDK</span>
          </a>
        </li>
      
    
      
    
      
        <li>
          <a href="/embedded-learning-log/2021/02/20/embedded-learning-log-2-dmesg-tty-and-minicom/">
            <span>Embedded learning log – A foray into Linux specifics: dmesg, tty and playing with minicom</span>
          </a>
        </li>
      
    
      
        <li>
          <a href="/embedded-learning-log/2021/02/14/embedded-learning-log-1-connecting-a-board-and-flashing-an-rtos/">
            <span>Embedded learning log – Connecting a board and flashing an RTOS</span>
          </a>
        </li>
      
    
  </ul>
</blockquote>

<blockquote>
  <p>Browse the accompanying repository <a href="https://github.com/fnune/toastboard/tree/061238f3ccffd2f7f13eb0a4d0844fc31d5ad9c8">at the commit in which I was done with this part</a>.</p>
</blockquote>

<p>Documentation on the ESP8266_RTOS_SDK does not feature any information about task creation. I guess this is because the underlying RTOS is FreeRTOS, so I’m going to try to find documentation for that.</p>

<p><a href="https://www.freertos.org/a00125.html">Here’s the documentation</a>.</p>

<p>Apparently I can create tasks with <code class="language-plaintext highlighter-rouge">xTaskCreate</code> or <code class="language-plaintext highlighter-rouge">xTaskCreateStatic</code>. If I want to use <code class="language-plaintext highlighter-rouge">xTaskCreateStatic</code>, I need to provide my own memory, so I need to pass more parameters, but I can allocate this memory at compile time. I’m going to go with the simpler <code class="language-plaintext highlighter-rouge">xTaskCreate</code>, which allocates from <a href="https://www.freertos.org/a00111.html">the FreeRTOS heap</a>.</p>

<p>The most important argument to <code class="language-plaintext highlighter-rouge">xTaskCreate</code> is the task function I want to run:</p>

<blockquote>
  <p>Tasks are normally implemented as an infinite loop, and must never attempt to return or exit from their implementing function. Tasks can however delete themselves.</p>
</blockquote>

<p>To create a task that executes periodically, I just need to make it an infinite loop that calls <code class="language-plaintext highlighter-rouge">vTaskDelay</code> in it or <code class="language-plaintext highlighter-rouge">vTaskDelayUntil</code>. I’m going for the simpler <code class="language-plaintext highlighter-rouge">vTaskDelay</code>.</p>

<p>Another interesting argument is <code class="language-plaintext highlighter-rouge">usStackDepth</code>. It’s in words, and the docs say a word is 32 bits in an ESP8266EX. One choice would be to find out the minimum stack size required for a task in FreeRTOS. I found this interesting article: <a href="https://mcuoneclipse.com/2015/08/21/gnu-static-stack-usage-analysis/">GNU Static Stack Usage Analysis</a> by <a href="https://mcuoneclipse.com/author/mcuoneclipse/">Erich Styger</a>. I can pass <code class="language-plaintext highlighter-rouge">-fstack-usage</code> to <code class="language-plaintext highlighter-rouge">gcc</code> and get a nice <code class="language-plaintext highlighter-rouge">.su</code> file that gives me the stack usage of each function in bytes. I can append to <code class="language-plaintext highlighter-rouge">CFLAGS</code> for specific components, so I did so in <code class="language-plaintext highlighter-rouge">esp8266_sdk/memfault/component.mk</code>, and then found this file <code class="language-plaintext highlighter-rouge">memfault/memfault_platform_http_client.su</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>memfault_platform_http_client.c:178:5:memfault_platform_http_client_post_data	192	static
</code></pre></div></div>

<p>That’s it! 192 bytes divided by my word size of 4 is exactly 48. I’ll use 48 as a stack size for my task and eventually test to see if I can get by with less (I doubt it).</p>

<p>After creating the task, I get an crash loop due to a stack overflow on my new <code class="language-plaintext highlighter-rouge">task_upload_memfault_data</code>. Is my stack size not big enough?</p>

<h2 id="finding-out-the-stack-size-needed-by-a-function">Finding out the stack size needed by a function</h2>

<p>I found this interesting article: <a href="https://mcuoneclipse.com/2015/08/21/gnu-static-stack-usage-analysis/">GNU Static Stack Usage Analysis</a> by <a href="https://mcuoneclipse.com/author/mcuoneclipse/">Erich Styger</a>. I can pass <code class="language-plaintext highlighter-rouge">-fstack-usage</code> to <code class="language-plaintext highlighter-rouge">gcc</code> and get a nice <code class="language-plaintext highlighter-rouge">.su</code> file that gives me the stack usage of each function in bytes.</p>

<p>I found out I can pass append to <code class="language-plaintext highlighter-rouge">CFLAGS</code> for specific components, so I did so in <code class="language-plaintext highlighter-rouge">esp8266_sdk/memfault/component.mk</code>, and then found this file <code class="language-plaintext highlighter-rouge">memfault/memfault_platform_http_client.su</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>memfault_platform_http_client.c:178:5:memfault_platform_http_client_post_data	192	static
</code></pre></div></div>

<p>That’s it! 192 bytes divided by my word size of 4 is exactly 48. I’ll use 48 as a stack size for my task and eventually test to see if I can get by with less (I doubt it).</p>

<h3 id="the-stack-size-i-calculated-wasnt-enough">The stack size I calculated wasn’t enough</h3>

<p>I started by trying to allocate a stack of 48 words for my <code class="language-plaintext highlighter-rouge">task_upload_memfault_data</code> function, but that crashed my device due to bad allocations. I bluntly tried to increase it gradually until it worked, and it did! At 4096 words. I was off by a lot.</p>

<p>Could this be due to the fact that I measured stack usage for <code class="language-plaintext highlighter-rouge">memfault_platform_http_client_post_data</code> and not for my task’s function <code class="language-plaintext highlighter-rouge">task_upload_memfault_data</code>? Let’s build with <code class="language-plaintext highlighter-rouge">-fstack-usage</code> again, this time scouting for my task function instead. The number reported for <code class="language-plaintext highlighter-rouge">memfault_platform_http_client_post_data</code> was 192 bytes.</p>

<p>The output contains this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>main.c:148:6:task_upload_memfault_data	16	static
</code></pre></div></div>

<p>Eew! 16 is a lot less than 192. It seems like this isn’t going all the way down the call stack to calculate stack usage. Maybe I’m missing some other flag?</p>

<h2 id="runtime-analysis-of-the-target-stack-size">Runtime analysis of the target stack size</h2>

<p>I’m going to try to let the code run and analyze how much memory the task takes after the fact. I probably need to make the task run through all of its different branches and take the maximum.</p>

<p>I remember that allocation of tasks created via <code class="language-plaintext highlighter-rouge">xTaskCreate</code> is handled by FreeRTOS, and there’s another way to create tasks that lets me control allocation: <code class="language-plaintext highlighter-rouge">xTaskCreateStatic</code>.</p>

<p>My plan is to:</p>

<ol>
  <li>Refactor my task to use <code class="language-plaintext highlighter-rouge">xTaskCreateStatic</code>.</li>
  <li>Flash and run the code.</li>
  <li>Figure out how to analyze the memory layout after the fact.</li>
  <li>Read how much of the stack I allocated was actually used by the task.</li>
</ol>

<p>To be able to access <code class="language-plaintext highlighter-rouge">xTaskCreateStatic</code> I had to change <code class="language-plaintext highlighter-rouge">configSUPPORT_STATIC_ALLOCATION</code> to <code class="language-plaintext highlighter-rouge">1</code> in <code class="language-plaintext highlighter-rouge">components/freertos/include/freertos/FreeRTOS.h</code>. Surprisingly, this setting wasn’t available under <code class="language-plaintext highlighter-rouge">make menuconfig</code> -&gt; Component configuration -&gt; FreeRTOS.</p>

<p>I’m giving up on this approach and returning to static analysis because compiling with <code class="language-plaintext highlighter-rouge">configSUPPORT_STATIC_ALLOCATION</code> requires me to implement my own allocators/deallocators for FreeRTOS’s idle task, and I’m… not up for the task.</p>

<h2 id="static-analysis-of-the-target-stack-size">Static analysis of the target stack size</h2>

<p>The reason why my 192 number was wrong is because <code class="language-plaintext highlighter-rouge">gcc</code> outputs <code class="language-plaintext highlighter-rouge">.su</code> files for each <code class="language-plaintext highlighter-rouge">.o</code> file it produces; it doesn’t look into other output objects to determine stack usage in a recursive fashion.</p>

<p>I found this Perl script by Daniel Beer <a href="https://dlbeer.co.nz/oss/avstack.html"><code class="language-plaintext highlighter-rouge">avstack.pl</code></a> which reportedly builds this tree or call graph for you and then sums the results:</p>

<blockquote>
  <p>The script reads all .su files, and disassembles all .o files, including relocation data. The disassemblies are parsed and used to construct a call graph. Multiple functions in different translation units with the same name don’t cause problems, provided there are no global namespace collisions. Information will appear on any unresolvable or ambiguous references.</p>
</blockquote>

<p>I’ve added the script and results to the repository in <a href="src/avstack.txt"><code class="language-plaintext highlighter-rouge">src/avstack.txt</code></a>. Functions prefixed with <code class="language-plaintext highlighter-rouge">&gt;</code> are supposed to have a summary of function calls in lines below them, but my run seems to have produced a flat stack where no function calls other functions in its body. It’s weird, and I got a 196 for <code class="language-plaintext highlighter-rouge">memfault_platform_http_client_post_data</code>, which looks like it’s my previous 192 plus 4. This 4 is passed as an argument to <code class="language-plaintext highlighter-rouge">avstack.pl</code> called <code class="language-plaintext highlighter-rouge">call_cost</code>.</p>

<p>So! I’m giving up on this method as well. My last attempt: using FreeRTOS’s <code class="language-plaintext highlighter-rouge">uxTaskGetStackHighWaterMark</code>.</p>

<h2 id="measuring-the-target-stack-size-at-runtime-using-uxtaskgetstackhighwatermark">Measuring the target stack size at runtime using <code class="language-plaintext highlighter-rouge">uxTaskGetStackHighWaterMark</code></h2>

<p>I’ve instrumented my task like this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">task_upload_memfault_data</span><span class="p">(</span> <span class="kt">void</span> <span class="o">*</span> <span class="n">pvParameters</span> <span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// [...]</span>
    <span class="n">uxHighWaterMark</span> <span class="o">=</span> <span class="n">uxTaskGetStackHighWaterMark</span><span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
    <span class="n">ESP_LOGD</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Water mark at task entry: %lu"</span><span class="p">,</span> <span class="n">uxHighWaterMark</span><span class="p">);</span>

    <span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// [...]</span>
        <span class="n">uxHighWaterMark</span> <span class="o">=</span> <span class="n">uxTaskGetStackHighWaterMark</span><span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
        <span class="n">ESP_LOGD</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Water mark at task exit: %lu"</span><span class="p">,</span> <span class="n">uxHighWaterMark</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The output looks like this, with irrelevant sections edited out:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>D (807) TOASTBOARD: Water mark at task entry: 3976

D (10832) TOASTBOARD: Water mark at task exit: 3140

D (29036) TOASTBOARD: Water mark at task exit: 580
D (39037) TOASTBOARD: Water mark at task exit: 580
D (49039) TOASTBOARD: Water mark at task exit: 580
D (59041) TOASTBOARD: Water mark at task exit: 580
D (69042) TOASTBOARD: Water mark at task exit: 580
D (79045) TOASTBOARD: Water mark at task exit: 580
</code></pre></div></div>

<p>So it’s 3976 on entry, on its first exit it’s 3140, and then it’s in the infinite loop (it has a 10 second delay after each run) and stabilizes at 580.</p>

<p>The initial drop from 3976 to 3140 is explained by the documentation:</p>

<blockquote>
  <p>Calling the function will have used some stack space, we would therefore now expect uxTaskGetStackHighWaterMark() to return a value lower than when it was called on entering the task.</p>
</blockquote>

<p>In my case, “the function(s)” are <code class="language-plaintext highlighter-rouge">vTaskDelay</code> and <code class="language-plaintext highlighter-rouge">memfault_esp_port_http_client_post_data</code>.</p>

<p>The second drop from 3140 to the stable 580 is explained by the fact that <code class="language-plaintext highlighter-rouge">memfault_esp_port_http_client_post_data</code> returned early because there was no more data to post. Cool!</p>

<p>Two questions remain:</p>

<ul>
  <li>Is the high water mark going to be higher than 3976 if there’s more than one chunk to send to Memfault? I’ve seen it post several at a time. I guess the stack size is going to be the same if the code runs inside a loop.</li>
  <li>I need to try and allocate a more optimized stack size to see if that affects execution. My new size in words is 3976.</li>
</ul>

<p>With 3976 it works just fine, but on a new run the high water mark is 3864. Why couldn’t it be more than my allocated 3976? Do people pad these values? I’m sticking with my original 4096 for good measure.</p>

<h3 id="finding-out-the-size-of-a-word-manually-in-c">Finding out the size of a word manually in C</h3>

<p>I remember in Rust this would be the size of <code class="language-plaintext highlighter-rouge">usize</code>. I guess in C I can go <code class="language-plaintext highlighter-rouge">sizeof(some_type)</code> to get this.</p>

<p>After some Googling, I found <code class="language-plaintext highlighter-rouge">size_t</code>, which varies depending on the address size of the processor, and is the type returned by <code class="language-plaintext highlighter-rouge">sizeof</code>. So let’s try <code class="language-plaintext highlighter-rouge">sizeof(size_t)</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ESP_LOGI(TAG, "Size of a word is %u bytes!", sizeof(size_t));
</code></pre></div></div>

<p>And then in <code class="language-plaintext highlighter-rouge">make monitor</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I (532) TOASTBOARD: Size of a word is 4 bytes!
</code></pre></div></div>

<p>Four bytes are 32 bits. Thanks Toastboard!</p>

<p>Next I’ll be <a href="/embedded-learning-log/2021/02/21/embedded-learning-log-4-integrating-the-memfault-firmware-sdk/">integrating the Memfault Firmware SDK</a>.</p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><category term="embedded-learning-log" /><summary type="html"><![CDATA[Running a recurring task with ESP8266_RTOS_SDK/FreeRTOS and calculating the stack size needed by a C function]]></summary></entry><entry><title type="html">Embedded learning log – Integrating the Memfault Firmware SDK</title><link href="https://fnune.com/embedded-learning-log/2021/02/21/embedded-learning-log-4-integrating-the-memfault-firmware-sdk/" rel="alternate" type="text/html" title="Embedded learning log – Integrating the Memfault Firmware SDK" /><published>2021-02-21T19:00:51+00:00</published><updated>2021-02-21T19:00:51+00:00</updated><id>https://fnune.com/embedded-learning-log/2021/02/21/embedded-learning-log-4-integrating-the-memfault-firmware-sdk</id><content type="html" xml:base="https://fnune.com/embedded-learning-log/2021/02/21/embedded-learning-log-4-integrating-the-memfault-firmware-sdk/"><![CDATA[<blockquote>
  <p>This post is part of a series where I log my experience getting into embedded software development. The overarching goal is to use the <a href="https://docs.espressif.com/projects/esp8266-rtos-sdk">ESP8266 RTOS SDK</a> to learn how to operate my ESP8266 board using an RTOS and to learn how to integrate the <a href="https://docs.memfault.com/">Memfault real-time SDK</a>. Disclaimer: I work for Memfault as a full-stack engineer, mostly on web stuff. Here are the other posts in the series:</p>
  <ul>
    
      
    
      
        <li>
          <a href="/embedded-learning-log/2021/02/21/embedded-learning-log-3-running-a-recurring-freertos-task/">
            <span>Embedded learning log – Running a FreeRTOS recurring task</span>
          </a>
        </li>
      
    
      
        <li>
          <a href="/embedded-learning-log/2021/02/20/embedded-learning-log-2-dmesg-tty-and-minicom/">
            <span>Embedded learning log – A foray into Linux specifics: dmesg, tty and playing with minicom</span>
          </a>
        </li>
      
    
      
        <li>
          <a href="/embedded-learning-log/2021/02/14/embedded-learning-log-1-connecting-a-board-and-flashing-an-rtos/">
            <span>Embedded learning log – Connecting a board and flashing an RTOS</span>
          </a>
        </li>
      
    
  </ul>
</blockquote>

<blockquote>
  <p><strong>Note</strong>: I make many mistakes during this integration. It’s not an example of how one should go about it, but just a log of my first attempt as a newcomer to embedded development. If you’re looking for a guide, <a href="https://docs.memfault.com/docs/embedded/esp8266-rtos-sdk-guide/">the documentation</a> is a perfect place to start.</p>
</blockquote>

<p>I’m starting by getting some application code in place. It’s just going to be <a href="https://github.com/fnune/toastboard/commit/6671fbf094254d0afd4aef5a65e8cd3eb9b12798">an HTTP server with simple routes</a> adapted from the ESP8266_RTOS_SDK examples. Once I’m done, I’ll try to integrate the Memfault SDK on top.</p>

<p>After <a href="https://docs.memfault.com/docs/embedded/esp8266-rtos-sdk-guide/#integration-steps">following the basic steps in the documentation</a> (here’s the <a href="https://github.com/fnune/toastboard/commit/edbfc2c9b19160f6e74d2c1db1245671cc0f643c">related commit</a>), I ran into this while compiling:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>In file included from /home/fausto/Development/toastboard/src/components/memfault_port/memfault-firmware-sdk/components/include/memfault/components.h:20,
                 from /home/fausto/Development/toastboard/src/main/main.c:17:
/home/fausto/Development/toastboard/src/components/memfault_port/memfault-firmware-sdk/components/include/memfault/config.h:30:39: fatal error: memfault_platform_config.h: No such file or directory
 #define MEMFAULT_PLATFORM_CONFIG_FILE "memfault_platform_config.h"
                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
</code></pre></div></div>

<p>I later found this from the <code class="language-plaintext highlighter-rouge">CHANGES.md</code> file in the Memfault SDK:</p>

<div class="language-md highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">-</span> You must create the file <span class="sb">`memfault_platform_config.h`</span> and add it to your
  include path. This file can be used in place of compiler defines to tune the
  SDK configurations settings.
</code></pre></div></div>

<p>After solving that by creating <code class="language-plaintext highlighter-rouge">src/main/include/memfault_platform_config.h</code>, there was another missing header file:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/home/fausto/Development/toastboard/src/components/memfault_port/memfault-firmware-sdk/ports/esp8266_sdk/memfault/esp_reboot_tracking.c:14:10: fatal error: internal/esp_system_internal.h: No such file or directory
 #include "internal/esp_system_internal.h"
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</code></pre></div></div>

<p>I got a bunch of compiler errors because I was on the <code class="language-plaintext highlighter-rouge">master</code> branch of ESP8266_RTOS_SDK and the Memfault integration supports only v3.3. The changes from <code class="language-plaintext highlighter-rouge">master</code> to v3.3 are significant in the HTTP server example, so I’m <a href="https://github.com/fnune/toastboard/commit/6ae1b36f236fec02dce7c4918ca0d14bab31e9fd">updating my application code</a>.
The next compiler error was a missing header file <code class="language-plaintext highlighter-rouge">esp_console.h</code> expected in <code class="language-plaintext highlighter-rouge">memfault_cli.c</code>. I could solve it by adding this to <code class="language-plaintext highlighter-rouge">src/sdkconfig</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONFIG_USING_ESP_CONSOLE=y
</code></pre></div></div>

<p>Et voila! It has built! Time to get it flashed onto the board.</p>

<h2 id="reboot-loop-after-integrating-the-sdk">Reboot loop after integrating the SDK</h2>

<p>There are some useful logs:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I (492) system_api: Base MAC address is not set, read default base MAC address from EFUSE
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
</code></pre></div></div>

<p>And:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>E (463) mflt: Coredumps enabled but no storage partition found!
</code></pre></div></div>

<p>I’m not sure which one is causing the reboots, so I’m going to fix the MAC address problem first. It should be a matter of using a different method that doesn’t get the “base” MAC address but the one from EFUSE. For context, I’m trying to use the MAC address as a device identifier to send to the Memfault cloud.</p>

<p>I gave up trying to fix the MAC address problem because no matter what I picked, it would crash. I’ll name this device <code class="language-plaintext highlighter-rouge">"the-one-and-only"</code> instead so that I can skip the problem of fetching the MAC address.</p>

<p>We’re left with:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>E (463) mflt: Coredumps enabled but no storage partition found!
</code></pre></div></div>

<p>It’s a bit weird because I’m still not at the step where I can <a href="https://docs.memfault.com/docs/embedded/coredumps/">add coredumps integration</a>.</p>

<p>Either way: I can print the partition table of the device with <code class="language-plaintext highlighter-rouge">make partition_table</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Espressif ESP32 Partition Table
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  24K,
phy_init, data, phy,     0xf000,  4K,
factory,  app,  factory, 0x10000, 960K,
</code></pre></div></div>

<p><a href="https://www.amazon.de/-/en/gp/product/B08BTXCZC1/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;psc=1">My chip</a> supposedly has 4MB of storage, and that’s roughly 1MB in the partition table, so I guess I could flash something else onto it. For now, I’m going to go with this.</p>

<p>Now I need to:</p>

<ol>
  <li>Identify which of those is the storage partition.</li>
  <li>Figure out how to tell Memfault to use that.</li>
</ol>

<p>The <a href="https://docs.espressif.com/projects/esp8266-rtos-sdk/en/release-v3.3/api-guides/partition-tables.html?highlight=storage">ESP8266_RTOS_SDK documentation on partition tables</a> says NVS stands for non-volatile storage. I guess that’s what we want. That means I want the partition starting at <code class="language-plaintext highlighter-rouge">0x9000</code> that’s 24K in size.</p>

<p>I’m going to look for a way to do (2) in <code class="language-plaintext highlighter-rouge">make menuconfig</code>.</p>

<p>The Memfault-specific configuration has an option “Enable saving a coredump to flash storage (OTA slot)”. The other choice is “User defined coredump storage region”. I guess I could pick the second, but there’s a default partition table that includes an OTA slot from the SDK, so I’m going to use that instead of the NVS partition.</p>

<p>The configuration changed like so:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gd">- CONFIG_PARTITION_TABLE_SINGLE_APP=y
</span><span class="gi">+ # CONFIG_PARTITION_TABLE_SINGLE_APP is not set
</span><span class="gd">- # CONFIG_PARTITION_TABLE_TWO_OTA is not set
</span><span class="gi">+ CONFIG_PARTITION_TABLE_TWO_OTA=y
</span></code></pre></div></div>

<p>I’m going to add that to the defaults file because it seems critical to the project. I also changed how I’m getting my WiFi SSID and password. Time to flash it again!</p>

<h2 id="the-reboot-loop-continues">The reboot loop continues</h2>

<p>But now it’s different! There are no more errors from Memfault, and I get a reassuring message, but the device still reboots in a loop:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I (499) mflt: Coredumps will be saved at 0x110000 (983040B)
</code></pre></div></div>

<p>This means my new partition table is being used correctly.</p>

<p>To begin debugging, I removed the <code class="language-plaintext highlighter-rouge">memfault_platform_boot()</code> call. Now, the device works correctly and does what it’s supposed to do (not much). I can look into my Memfault-related files to find the culprit.</p>

<p>After some time trying to figure this out, I’m going to give up and hardcode the hardware version instead of trying to get it from <code class="language-plaintext highlighter-rouge">chip_info</code>, since I’m suspicious of my C.</p>

<p>Now, the device is stable! I just don’t know C.</p>

<h2 id="sending-data">Sending data</h2>

<p>I need to add <code class="language-plaintext highlighter-rouge">memfault_esp_port_http_client_post_data()</code> somewhere.</p>

<p>My device exposes an HTTP server, so I decided to create a <code class="language-plaintext highlighter-rouge">GET /upload</code> route that will upload anything saved up to Memfault.</p>

<p>I open <code class="language-plaintext highlighter-rouge">192.168.0.24:80/upload</code> on a browser and…</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>D (30030) mflt: Posting Memfault Data
D (30339) mflt: Posting Memfault Data Complete!
I (30342) mflt: Result: 0
</code></pre></div></div>

<p>My device now exists on Memfault!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>the-one-and-only	1.0.0+4bb166	ESP8266EX_CH340C	a minute ago
</code></pre></div></div>

<h2 id="the-esp-idf-console">The ESP-IDF console</h2>

<p>The Memfault docs mention a <code class="language-plaintext highlighter-rouge">crash</code> CLI command. I’m not sure what this is. I tried to find some information about this, thinking it’s related to the <code class="language-plaintext highlighter-rouge">CONFIG_USING_ESP_CONSOLE=y</code> flag I passed in for compilation. The ESP8266 documentation doesn’t mention the <code class="language-plaintext highlighter-rouge">console</code> component or the <code class="language-plaintext highlighter-rouge">crash</code> CLI command.</p>

<p>ESP-IDF documentation mentions this:</p>

<blockquote>
  <p>ESP-IDF provides console component, which includes building blocks needed to develop an interactive console over serial port.</p>
</blockquote>

<p>I guess I’m supposed to build the interactivity into a new target? Maybe I’m supposed to test with the <code class="language-plaintext highlighter-rouge">console</code> example provided with the RTOS.</p>

<p>I’m blocked at this step because the next steps depend on this: the crash data I could get from the <code class="language-plaintext highlighter-rouge">crash</code> CLI would be uploaded with the <code class="language-plaintext highlighter-rouge">memfault</code> CLI, and then the web application would warn me there’s a missing symbols file for the data, and I could then upload the symbols file and get issues from it.</p>

<p>I guess I need to find a way around the problem if I can’t find out what this <code class="language-plaintext highlighter-rouge">crash</code> CLI command is.</p>

<h2 id="trying-to-force-a-crash-by-flashing-buggy-code">Trying to force a crash by flashing buggy code</h2>

<p>Let’s try adding an infinite loop in a <code class="language-plaintext highlighter-rouge">GET</code> request handler under <code class="language-plaintext highlighter-rouge">/crash</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>esp_err_t crash_get_handler(httpd_req_t *req)
{
    while (true) {
      // ...
    };

    const char* resp_str = (const char*) req-&gt;user_ctx;
    httpd_resp_send(req, resp_str, strlen(resp_str));

    return ESP_OK;
}

httpd_uri_t crash = {
    .uri       = "/crash",
    .method    = HTTP_GET,
    .handler   = crash_get_handler,
    .user_ctx  = "The application should crash before this shows up"
};
</code></pre></div></div>

<p>Calling <code class="language-plaintext highlighter-rouge">/crash</code> left my browser loading for about 30 (!) seconds before the device crashed. Here’s the full output of the crash, from <code class="language-plaintext highlighter-rouge">make monitor</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Saving Memfault Coredump!
Erasing Coredump Storage: 0x0 983040
coredump erase complete
Task watchdog got triggered.

Guru Meditation Error: Core  0 panic'ed (IllegalInstruction). Exception was unhandled.
Core 0 register dump:
PC      : 0x4026f3d4  PS      : 0x00000030  A0      : 0x40247d9c  A1      : 0x3fff57c0
0x4026f3d4: crash_get_handler at /home/fausto/Development/toastboard/src/main/main.c:54

0x40247d9c: httpd_uri at /home/fausto/.esp/ESP8266_RTOS_SDK/components/esp_http_server/src/httpd_uri.c:218

A2      : 0x40107cec  A3      : 0x4026f3d4  A4      : 0x00000002  A5      : 0x00000004
0x4026f3d4: crash_get_handler at /home/fausto/Development/toastboard/src/main/main.c:54

A6      : 0x00000073  A7      : 0x00000001  A8      : 0x00000001  A9      : 0x00000068
A10     : 0x00000068  A11     : 0x80808080  A12     : 0x40107c9c  A13     : 0x40107cec
A14     : 0x40107c9c  A15     : 0x40107cec  SAR     : 0x00000018  EXCCAUSE: 0x00000000

Backtrace: 0x4026f3d4:0x3fff57c0 0x40247d9c:0x3fff57c0 0x4024853b:0x3fff57e0 0x402485ed:0x3fff5860 0x402475df:0x3fff5880 0x40246f58:0x3fff5890 0x40246fc4:0x3fff58b0
0x4026f3d4: crash_get_handler at /home/fausto/Development/toastboard/src/main/main.c:54

0x40247d9c: httpd_uri at /home/fausto/.esp/ESP8266_RTOS_SDK/components/esp_http_server/src/httpd_uri.c:218

0x4024853b: httpd_parse_req at /home/fausto/.esp/ESP8266_RTOS_SDK/components/esp_http_server/src/httpd_parse.c:527

0x402485ed: httpd_req_new at /home/fausto/.esp/ESP8266_RTOS_SDK/components/esp_http_server/src/httpd_parse.c:594

0x402475df: httpd_sess_process at /home/fausto/.esp/ESP8266_RTOS_SDK/components/esp_http_server/src/httpd_sess.c:327

0x40246f58: httpd_server at /home/fausto/.esp/ESP8266_RTOS_SDK/components/esp_http_server/src/httpd_main.c:113

0x40246fc4: httpd_thread at /home/fausto/.esp/ESP8266_RTOS_SDK/components/esp_http_server/src/httpd_main.c:113

@R%dPMT%w@Y)Q
OT5V'I
T       )dE     5Y
NZA     I^NTR
@\Y!NZA I^{YP1g@\@Y
[)!E   pL@LYYX)IIPKVqRA I       YЛ     pL@PWK   V       ZQHYYV[)!E     pL@Y^ZYY
                         1eʉE  xO@Y     J5)aEEAJA%Y     J)Q
AEaE   xL@Y     J-I
%ʉE    xO@YZAFPYM)!E   `M@YI9V5ԻT)dVEEAJAH%Y=eZ)R
                                                 E
                                                  E    h%Y-JP-G

                                                               E       h%Y1iGQP)PNP-E  h%Y--HPPG
-AKRMYV@Q                                                                                       YAJAH^-G-HPP-YAJAH^w\PRZANPYEEAJAHq
         E     h)YVYP1DT
                        PTg
                           TWp)ʉE      hM)YVY1DT
                                                P%=DT
                                                     T5қ
                                                        @)ʉE   h)YVYRP#PR
5P@H)IJ)!E     hN)YVRP%=DT
                          Tg
)IJ)!E h                    P!)IJ)!E   h)YVYPRPT5eHP@
        %YYP-^1qQHT-TRYI (411) system_api: Base MAC address is not set, read default base MAC address from EFUSE
</code></pre></div></div>

<p>It looks like the system gave me the backtrace and the exact location of my crash: the body of the <code class="language-plaintext highlighter-rouge">crash_get_handler</code>. What a surprise.</p>

<p>On the Memfault application nothing’s showing up yet. I guess it’s because my device doesn’t upload data unless I tell it to, using the <code class="language-plaintext highlighter-rouge">GET /upload</code> route.</p>

<p>After I upload the data in the device, I get this in the issues view:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Unprocessed traces exist due to missing symbol file(s):

Upload 1.0.0+5a05af (toastboard-firmware)
</code></pre></div></div>

<p>Cool! Uploading that now. I’m such a noob that I don’t even know what I’m supposed to upload. I think it’s <code class="language-plaintext highlighter-rouge">build/toastboard.elf</code>, though.</p>

<p>Let’s try crashing the same away again to test issue deduplication. While my device takes some time to decide to crash through the infinite loop, I’m thinking of two questions:</p>

<ol>
  <li>Why does it take so long for it to crash? I’d have guessed the timeout is shorter. Although it’s an infinite loop, shouldn’t it still be cancelable by some interrupt or whatever mechanism the RTOS has?</li>
  <li>Why is it showing up as a <code class="language-plaintext highlighter-rouge">Hard Fault</code> instead of a <code class="language-plaintext highlighter-rouge">Watchdog</code> issue? Wasn’t the device restarted by the watchdog?</li>
</ol>

<p>Looking around in <code class="language-plaintext highlighter-rouge">make menuconfig</code>, I found the answer to (1): <code class="language-plaintext highlighter-rouge">Task Watchdog timeout period (seconds) (26.2144s)</code> under <code class="language-plaintext highlighter-rouge">ESP8266-specific</code>. I was pretty close with my 30 seconds guess!</p>

<p>I think I can answer (2): the issue is a <code class="language-plaintext highlighter-rouge">Hard Fault</code>. The reboot event should be have the watchdog as a cause. However, it shows up as <code class="language-plaintext highlighter-rouge">Unspecified</code>. I guess I have something else to integrate.</p>

<p>Issue deduplication seems to be working fine. Here’s what the Queue Status widget shows:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>a few seconds ago	Attached to Issue #38075
26 minutes ago	Attached to Issue #38075
</code></pre></div></div>

<p>Both were attached to issue <code class="language-plaintext highlighter-rouge">38075</code>.</p>

<h2 id="integrating-reboot-reasons">Integrating reboot reasons</h2>

<p><a href="https://docs.memfault.com/docs/embedded/reboot-reason-tracking">Here’s the documentation I’m following</a>.</p>

<p>I guess my reboot is showing up as having an <code class="language-plaintext highlighter-rouge">Unspecified</code> reason because I haven’t completed integration. Let’s continue with that.</p>

<p>The guide mentions I should <code class="language-plaintext highlighter-rouge">#include "memfault/core/reboot_tracking.h"</code>, but I confirmed that’s already included with <code class="language-plaintext highlighter-rouge">"memfault/components.h"</code>.</p>

<p>There are two things I need to figure out from my chip and use in the initialization code:</p>

<ol>
  <li>A pointer to the reboot reason register.</li>
  <li>Additional information about the reboot reason, mapped to a <code class="language-plaintext highlighter-rouge">MfltResetReason</code>.</li>
</ol>

<p>As for (2), the ESP8266_RTOS_SDK documentation points to a function <a href="https://docs.espressif.com/projects/esp8266-rtos-sdk/en/release-v3.3/api-reference/system/system.html?highlight=reset#_CPPv416esp_reset_reasonv"><code class="language-plaintext highlighter-rouge">esp_reset_reason</code></a> that returns a value of type <a href="https://docs.espressif.com/projects/esp8266-rtos-sdk/en/release-v3.3/api-reference/system/system.html?highlight=reset#_CPPv418esp_reset_reason_t"><code class="language-plaintext highlighter-rouge">esp_reset_reason_t</code></a>. I need to figure out how to map from <code class="language-plaintext highlighter-rouge">esp_reset_reason_t</code> to <code class="language-plaintext highlighter-rouge">MfltResetReason</code>.</p>

<p>As for (1), I can’t find information in the documentation indicating how to access that register. There’s only the functions described above. Looking at  the RTOS source code, I found this: <code class="language-plaintext highlighter-rouge">RTC_RESET_HW_CAUSE_REG</code>. I’m wondering if that’s defined. To find that out, I’m going to try to compile with that and <code class="language-plaintext highlighter-rouge">kMfltRebootReason_Unknown</code> for now.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>error: 'RTC_RESET_HW_CAUSE_REG' undeclared
</code></pre></div></div>

<p>Nope! However, I found that <code class="language-plaintext highlighter-rouge">RTC_RESET_HW_CAUSE_REG</code> points to a register <code class="language-plaintext highlighter-rouge">RTC_STATE1</code>, which I can access if I <code class="language-plaintext highlighter-rouge">#include "esp8266/rtc_register.h"</code>. This feels really hacky, but the code now compiles!</p>

<p>Reboot reasons still show up as <code class="language-plaintext highlighter-rouge">Unspecified</code> and <code class="language-plaintext highlighter-rouge">Unexpected Reset</code>. Time to continue with the integration: mapping <code class="language-plaintext highlighter-rouge">esp_reset_reason_t</code> to <code class="language-plaintext highlighter-rouge">MfltResetReason</code> and passing it to the Memfault SDK.</p>

<p>I built the mapper and passed it to <code class="language-plaintext highlighter-rouge">memfault_reboot_tracking_boot</code>, and everything compiles just fine, but the reboots in the app are still <code class="language-plaintext highlighter-rouge">Unspecified</code>. There’s more integration steps to take, so I probably need to continue.</p>

<p>I needed to dedicate some storage space for events and pass it to Memfault. Once that was done, I tortured the little thing once more with the <code class="language-plaintext highlighter-rouge">GET /crash</code> endpoint, and voila! There’s a reason for my reboot on the Memfault application: <code class="language-plaintext highlighter-rouge">Software Watchdog</code>.</p>

<p>This is a bit weird because the logs from <code class="language-plaintext highlighter-rouge">make monitor</code> show this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I (503) mflt: ESP Reset Cause 0x7
I (509) mflt: Reset Causes:
I (514) mflt:  Hardware Watchdog
</code></pre></div></div>

<p>Maybe I got the mappings wrong!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/* Reset (software or hardware) due to interrupt watchdog. */
case ESP_RST_INT_WDT: return kMfltRebootReason_HardwareWatchdog;
/* Reset due to task watchdog. */
case ESP_RST_TASK_WDT: return kMfltRebootReason_SoftwareWatchdog;
/* Reset due to other watchdogs. */
case ESP_RST_WDT: return kMfltRebootReason_SoftwareWatchdog;
</code></pre></div></div>

<p>Reset cause <code class="language-plaintext highlighter-rouge">0x7</code> corresponds to “other watchdogs”, so I’m going to map that to <code class="language-plaintext highlighter-rouge">HardwareWatchdog</code> instead, since that’s what the logs say. The <code class="language-plaintext highlighter-rouge">Hardware Watchdog</code> log from the Memfault SDK was there long before I added my mapping, so that suggests to me that they knew the reset reason all along. Why did I have to implement the mapping, then?</p>

<p>As it turns out, it’s because I didn’t read the port included in the SDK well enough (duh). It includes <a href="https://github.com/memfault/memfault-firmware-sdk/blob/master/ports/esp8266_sdk/memfault/esp_reboot_tracking.c">an implementation of <code class="language-plaintext highlighter-rouge">memfault_reboot_reason_get</code></a> which I should have used from the start.</p>

<h2 id="sending-data-periodically">Sending data periodically</h2>

<p>I simply used the code from <a href="/embedded-learning-log/2021/02/21/embedded-learning-log-3-running-a-recurring-freertos-task/">my previous investigation</a> on how to create a recurring task on FreeRTOS and called <code class="language-plaintext highlighter-rouge">memfault_esp_port_http_client_post_data</code> from there. <a href="https://github.com/fnune/toastboard/blob/061238f3ccffd2f7f13eb0a4d0844fc31d5ad9c8/src/main/main.c#L148">Here’s how it ended up looking</a>.</p>

<p>So! My device is sending data to the cloud. I’d call this a success for now.</p>]]></content><author><name>Fausto Núñez Alberro</name><email>fausto.nunez@mailbox.org</email></author><category term="embedded-learning-log" /><summary type="html"><![CDATA[I take a stab at integrating my the product my company produces with my development board project.]]></summary></entry></feed>