<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Lee's Notes]]></title><description><![CDATA[Lee's Notes]]></description><link>https://routevegetable.com/</link><image><url>https://routevegetable.com/favicon.png</url><title>Lee&apos;s Notes</title><link>https://routevegetable.com/</link></image><generator>Ghost 4.33</generator><lastBuildDate>Wed, 22 Jan 2025 18:23:59 GMT</lastBuildDate><atom:link href="https://routevegetable.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Trans Day of Visibility]]></title><description><![CDATA[<p>Hey, so it&apos;s apparently this day; I figured I should do my part, and also give interested folx a chance to learn a bit more about me.</p><p>I do indeed identify as a Transgender individual for several reasons, which may be surprising to some who know me. I&</p>]]></description><link>https://routevegetable.com/trans-day-of-visibility/</link><guid isPermaLink="false">6245e578cafd2475c62669ee</guid><category><![CDATA[Personal]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Thu, 31 Mar 2022 22:32:16 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2022/03/1024px-Transgender_Pride_flag.svg.png" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2022/03/1024px-Transgender_Pride_flag.svg.png" alt="Trans Day of Visibility"><p>Hey, so it&apos;s apparently this day; I figured I should do my part, and also give interested folx a chance to learn a bit more about me.</p><p>I do indeed identify as a Transgender individual for several reasons, which may be surprising to some who know me. I&apos;d like to go into a bit of depth over what that means for me, but also for the wider community. So here are a bunch of meaningful words!</p><p>If you already know a decent amount about LGBT+ language, feel free to skip straight to <a href="#about-me">About Me</a> .</p><h2 id="language">Language</h2><p>As we continue to nudge society toward a fairer, more inclusive and less awful place, we develop the need for new language. Getting to grips with LGBT+ realities is no exception, and we need language sufficiently powerful to articulate what is going on. Here are some definitions that are particularly important to the LGBT+ and Transgender experience:</p><ul><li><strong>AMAB</strong> - Assigned Male At Birth: This one is quite self explanatory.<br>Most people called &apos;Boys&apos; or &apos;Men&apos; in my English-speaking culture, are AMAB individuals. This assignment is typically based on the presence of external genitalia.</li><li><strong>AFAB</strong> - Assigned Female At Birth: Same as above, but the assignment is typically based on the absence of external genitalia.</li><li><strong>Man/Male</strong> - An individual who identifies as such.<br>Traditionally associated with certain behaviors, societal roles, clothing, colors and more. All, some or none of these things may apply to any particular man. For our purposes, mutually exclusive with &apos;Woman&apos;.</li><li><strong>Woman/Female</strong> - An individual who identifies as such.<br>Traditionally associated with certain behaviors, societal roles, clothing, colors and more. All, some or none of these things may apply to any particular woman. For our purposes, mutually exclusive with &apos;Man&apos;.</li><li><strong>Non-binary</strong> - Typically someone who identifies as neither strictly a &apos;Man&apos; nor &apos;Woman&apos;.</li><li><strong>Cisgender</strong> - From Latin &apos;cis-&apos;, meaning &apos;on this side of&apos;.<br>Someone whose Assigned Gender at Birth, &apos;matches&apos; their gender identity.<br>Eg: An AMAB individual who identifies as a &apos;man&apos; can typically be referred to as a &apos;Cisgender man&apos;, or commonly &apos;Cis man&apos;.<br>Cisgender individuals make up the majority of the population, and as a group are well represented in various contexts.</li><li><strong>Transgender</strong> - From Latin &apos;trans-&apos;, meaning &apos;across, beyond&apos;.<br>Someone whose Assigned Gender at Birth does not &apos;match&apos; their gender identity.<br>Some individuals here may feel most comfortable and authentic presenting differently to ways that &apos;match&apos; their Assigned Gender at Birth.<br>Some may identify with some specific gender, while others do not. <br>Some may benefit from any of a wide variety of medical procedures to better align their body with what makes sense for them, while others do not.<br>Some may feel that they were &quot;born in the wrong body&quot;, while others do not consider this to be true.<br>Eg: An AMAB individual who identifies as a &apos;woman&apos; can typically be referred to as a &apos;Transgender woman&apos;, or commonly &apos;Trans woman&apos;.</li><li><strong>Hormone Replacement Therapy (HRT)</strong> - Also known as &apos;Gender Affirming Hormone Therapy&apos;, represents a family of medical treatments intended to modify the levels of an individual&apos;s sex hormones (primarily testosterone and estrogen, but also others). This can have a broad range of desirable physical and psychological effects, and there are a multiple possible goals for such an endeavour. It is highly individualized, and usually involves experiencing a &apos;second puberty&apos;.</li><li><strong>Transsexual</strong> - Arcane term for what we now typically refer to as a Transgender individual. Best for most people to avoid using this to refer to human beings, though within the LGBT+ community there is some nuance here.</li></ul><p>This is the language I use - none of this is &apos;final&apos;; words are ultimately &apos;made up&apos; noises and squiggles for referring to things, tangible and otherwise, that we need to communicate about. Definitions may differ between points of view, and do just change over time.</p><h2 id="about-me">About Me</h2><p>After all that, it should make sense that some labels I use for myself are <strong>AMAB</strong>, <strong>Transgender</strong>, <strong>Non-binary</strong> and <strong>Gender-fluid</strong>. Breaking it down:</p><ul><li>I was assigned &apos;male&apos; at birth (thanks to my external genitalia), but I do not identify as male.</li><li>&apos;Woman&apos; is also inaccurate, making me &apos;non-binary&apos;.</li><li>Gender-fluid describes how some of my behaviors, presentation and internal workings, when viewed through a gendered lens, tend to shift around from day to day.</li></ul><p>Something I haven&apos;t spoken to many people about previously is that I do indeed employ feminizing HRT - moving my body from the testosterone-dominant regime I have had for most of my life, to an estrogen-dominant one. This has brought a slew of benefits which are, at this time, still difficult to convert into language - you&apos;re just going to have to trust me on this ;) .<br>It has been challenging to talk about for a number of reasons, including:</p><ul><li>By sharing such a fact, people may think I am looking for their approval, which is a burdensome misunderstanding for all involved. At this point however, things have been going on for long enough that it should be clear I&apos;m not asking for permission.</li><li>Many people are simply weirded out by this stuff. It&apos;s unusual and makes people uncomfortable to think about. I don&apos;t like making people uncomfortable and speaking frankly, I expect this will lose me the support of some friends who find it hard to tolerate.</li><li>I don&apos;t want this to change how people treat me; alas, things are becoming more difficult to...conceal - I might as well take the opportunity and do my part to help normalize all this.</li><li>I don&apos;t want to be labelled a &apos;woman&apos;. For many people, this kind of disclosure will put me into the &apos;woman&apos; box, or indeed the less-nice &apos;trying to be a woman&apos; box. Neither of these are good for me. What I am going through can reasonably be called &apos;feminization&apos;, but &apos;transition&apos; is misleading. Something that becomes painfully, wonderfully obvious, is that everyone seems to be doing this stuff for different and personalized reasons. The transgender community isn&apos;t one big monolith - it&apos;s a diverse bunch of people with some stuff in common. Kinda. Since getting acquainted with this reality, I actually feel less connected to a solid community, but I feel much <em>more</em> connected to <strong>myself</strong>; perhaps that makes sense to someone!</li></ul><p>How can you support me?</p><ul><li>Basically don&apos;t do anything different.</li><li>Don&apos;t make disrespectful/invasive questions/comments about my body. I do enjoy talking about myself in general, but there is also a big issue with folks feeling entitled to inspect/judge transgender bodies - perhaps asking quite clinical/medicalized questions which would normally demand a good deal of familiarity, or at least a little &quot;asking to ask&quot;. It&apos;s annoying and weird, and particularly if it&apos;s &apos;out of concern&apos;, please just don&apos;t.</li><li>Continue to address me as the non-binary individual I am. Avoid gendered language. Use they/them pronouns (I <em>definitely</em> don&apos;t want to hear nonsense about singular they/them being grammatically illegitimate - <a href="https://www.merriam-webster.com/words-at-play/singular-nonbinary-they">it&apos;s not; get over it</a>).</li></ul><h2 id="diversity-within-the-community">Diversity within the community</h2><p>As i&apos;ve labored previously in this post, there is a great deal of diversity within the group of people called &apos;Transgender&apos;. To not appreciate this will undoubtedly lead to confusion, so here are some dimensions which can vary between Transgender individuals:</p><ul><li><strong>Identity</strong> - eg: Man, Woman, Non-binary, Genderfluid, etc... (many of these)</li><li><strong>Presentation</strong> - eg: clothing, behavior, third-person pronouns.</li><li><strong>Presence/degree of Gender Dysphoria</strong> - this is a medical diagnosis centered around discomfort with one&apos;s body, along gendered lines; a Transgender individual may or may not experience it.</li><li><strong>Self concept</strong> - eg: &quot;Born in the wrong body&quot; vs personal evolution, vs something else?</li><li><strong>Medical procedures undertaken</strong> - eg: none, hair removal, facial surgery, breast augmentation/reduction, genital surgeries, many more.</li><li><strong>Presence/degree of HRT undertaken</strong> - eg: none, microdosing, feminizing, masculinizing, transitional.</li><li><strong>History</strong> - eg: Some single moment they &quot;found out they were transgender&quot; vs some incremental change, vs something else? Presence of Childhood &apos;signs&apos; vs not?</li><li><strong>Desire to &apos;pass&apos;</strong> - particularly for Trans men and Trans women, it may or may not be desirable to appear visibly transgender.</li></ul><p>This is not exhaustive or even extensive; hopefully it illustrates some of the great diversity within this group.</p><h2 id="challenges">Challenges</h2><p>Some social challenges particularly related to the Transgender population include:</p><ul><li>Underrepresentation and lack of visibility in media, workplace and other contexts.</li><li>Social/moral taboo - Many individuals simply take moral issue with some or all aspects of Transgender individuals; this may be for religious reasons, and/or cultural beliefs around narrow, very specific definitions of man/woman-hood.</li><li>Trivialization - Often a massively oversimplified view of this group is the only one considered. Eg: a popular trope is the AMAB individual who spends their childhood secretly dressing in female clothes, eventually &apos;fully transitioning&apos; to become a Transgender woman, taking full advantage of all medical procedures available to present as closely to an idealized Cisgender woman as possible, with a goal of becoming indistinguishable from one. Though completely valid, it should be clear that this is <em>very far</em> from a universal story.</li><li>Fetishization - <em>Sigh</em></li><li>Misinformation and even organized hate - Unfortunately, there exist influential and well-resourced groups of individuals, many of whom are so-called Trans Exclusionary Radical Feminists (TERFs), casting Transgender individuals as some combination of mentally disturbed, untrustworthy, hostile to feminism, hostile to womens&apos; rights, or even predatory. This is a large problem in the UK for example, where such views could be called practically mainstream. It represents a sizeable risk to Transgender equality/safety.</li></ul><h2 id="closing-note">Closing note</h2><p>There is so, so much more to say on all of this, and I have not tried to cover everything. This is a snapshot into my world, and here I try to show how I place myself within it.</p>]]></content:encoded></item><item><title><![CDATA[BLE Covid Test #3: Bringing it all together!]]></title><description><![CDATA[<p>So here&apos;s what is likely the final installment in my COVID test explorations. I&apos;ve learned a bunch and got some seemingly useful practical experience.</p><p>Broadly, I knew where I wanted to go with this - I wanted to be able to use the Arduino IDE to</p>]]></description><link>https://routevegetable.com/covid-test-3/</link><guid isPermaLink="false">61d657fdf3057b0b4e98bbf5</guid><category><![CDATA[BLE]]></category><category><![CDATA[Arduino]]></category><category><![CDATA[nRF52810]]></category><category><![CDATA[IOT]]></category><category><![CDATA[Electronics]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Tue, 11 Jan 2022 02:32:58 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2022/01/arduino.png" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2022/01/arduino.png" alt="BLE Covid Test #3: Bringing it all together!"><p>So here&apos;s what is likely the final installment in my COVID test explorations. I&apos;ve learned a bunch and got some seemingly useful practical experience.</p><p>Broadly, I knew where I wanted to go with this - I wanted to be able to use the Arduino IDE to reprogram the device, and I wanted to be able to make use of the BLE radio to do something interesting. In my <a href="https://routevegetable.com/covid-test-2/">last post</a>, I talked about getting the Jeff Probe working with the nRF52810 chip, well enough that I could erase/program it.</p><p>I&apos;ve not done much with the Arduino platform, so I knew I had to learn a bunch of little pieces on the way. The first thing I needed was an Arduino &apos;core&apos; for this chip. This is Arduino parlance for a board support package, which implements what you might call the Arduino basics - initialization, serial ports, GPIO, ADC and the like. Some googling around led me pretty quickly to an nRF5x core: </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/sandeepmistry/arduino-nRF5"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - sandeepmistry/arduino-nRF5: Arduino Core for Nordic Semiconductor nRF5 based boards</div><div class="kg-bookmark-description">Arduino Core for Nordic Semiconductor nRF5 based boards - GitHub - sandeepmistry/arduino-nRF5: Arduino Core for Nordic Semiconductor nRF5 based boards</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="BLE Covid Test #3: Bringing it all together!"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">sandeepmistry</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/43104b65a9bb2af894d66447ae239437f4665f11ec9c953a4e5beaaa9897a232/sandeepmistry/arduino-nRF5" alt="BLE Covid Test #3: Bringing it all together!"></div></a></figure><p>While it has no specific support for the nRF52810 chip, it has support for others which vary in relatively minor ways such as memory size, pinout and how many of whatever peripheral type there are. This also has Blackmagicprobe support which ended up working out-of-the-box with the Jeff Probe. So I set about creating a new board in <code>boards.txt</code> for the Ellume COVID test, along with an appropriately configured variant placed in the <code>variants</code> directory. A smattering of other little changes here and there were needed to get things going, including adding linker scripts and <code>#ifdef</code> directives. Without too much difficulty, I was able to write a program, compile it and download it onto the chip. I could even use gdb to verify that it was running!</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2022/01/signal-2022-01-05-162333-1.jpeg" class="kg-image" alt="BLE Covid Test #3: Bringing it all together!" loading="lazy" width="2000" height="1500" srcset="https://routevegetable.com/content/images/size/w600/2022/01/signal-2022-01-05-162333-1.jpeg 600w, https://routevegetable.com/content/images/size/w1000/2022/01/signal-2022-01-05-162333-1.jpeg 1000w, https://routevegetable.com/content/images/size/w1600/2022/01/signal-2022-01-05-162333-1.jpeg 1600w, https://routevegetable.com/content/images/2022/01/signal-2022-01-05-162333-1.jpeg 2048w" sizes="(min-width: 720px) 720px"></figure><p>Something I needed to do at this point was figure out what GPIOs are hooked to what things on the board. From poking around with a multimeter and experimenting with some basic code, I gleaned the following:</p><ul><li>P0.18 - Green LED</li><li>P0.15 - Red test strip-reading LEDs</li><li>P0.12 - ??? - Driving it low while P0.15 is high makes one of the red LEDs turn off</li><li>P0.25 - Something button-related</li></ul><p>On P0.25/Button, I spent a lot of time poking around trying to figure out how exactly it worked. It wasn&apos;t trivial, and I was prodding it with an oscilloscope probe for quite a long time indeed, as it jumped around on pushing the button - a capacitor seemed to be involved. I prodded a little too hard however, so much so that I actually deformed the solder and shorted out that pin of the MCU &#x1F631;.</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2022/01/2022-01-07-091125.jpg" width="640" height="480" loading="lazy" alt="BLE Covid Test #3: Bringing it all together!" srcset="https://routevegetable.com/content/images/size/w600/2022/01/2022-01-07-091125.jpg 600w, https://routevegetable.com/content/images/2022/01/2022-01-07-091125.jpg 640w"></div><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2022/01/2022-01-07-092243.jpg" width="640" height="480" loading="lazy" alt="BLE Covid Test #3: Bringing it all together!" srcset="https://routevegetable.com/content/images/size/w600/2022/01/2022-01-07-092243.jpg 600w, https://routevegetable.com/content/images/2022/01/2022-01-07-092243.jpg 640w"></div><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2022/01/2022-01-07-092430.jpg" width="640" height="480" loading="lazy" alt="BLE Covid Test #3: Bringing it all together!" srcset="https://routevegetable.com/content/images/size/w600/2022/01/2022-01-07-092430.jpg 600w, https://routevegetable.com/content/images/2022/01/2022-01-07-092430.jpg 640w"></div></div></div><figcaption>Courtesy of my old USB microscope xmas present, being legitimately useful beyond just grossing out me and my friends (the micro-world is full of awful).</figcaption></figure><p>The bridge between those two bits of solder on the bottom-left of the chip is reasonably visible in the first pic. The second pic shows me trying to separate them indirectly, via a rigid pin - you can see the pesky capacitor preventing direct access with the soldering iron. The third picture shows what appears to be the once-again separated conductors.</p><p>Unfortunately after all of this poking and prodding, it still didn&apos;t work! Perhaps I left a dry joint under the QFN; more likely I feel is that my shorting out with VDD, combined with driving the pin low from software while I was experimenting, lead to that GPIO driver being permanently destroyed. Or maybe something else was wrong - who knows? In any case, I gave up on using the switch for anything and just moved on.</p><p>I also ended up figuring out those two unknown pads on the programming header!</p><ul><li>P0.16 - Pad 3 on the programming header</li><li>P0.20 - Pad 2 on the programming header, and also a red LED</li></ul><p>I decided these should be a UART, and pretty arbitrarily declared Pad 3 to be TX and Pad 2 to be RX; this has the nice benefit of making the red LED blink while data is being received.</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2022/01/signal-2022-01-10-131719_001.jpeg" class="kg-image" alt="BLE Covid Test #3: Bringing it all together!" loading="lazy" width="2000" height="1500" srcset="https://routevegetable.com/content/images/size/w600/2022/01/signal-2022-01-10-131719_001.jpeg 600w, https://routevegetable.com/content/images/size/w1000/2022/01/signal-2022-01-10-131719_001.jpeg 1000w, https://routevegetable.com/content/images/size/w1600/2022/01/signal-2022-01-10-131719_001.jpeg 1600w, https://routevegetable.com/content/images/2022/01/signal-2022-01-10-131719_001.jpeg 2048w" sizes="(min-width: 720px) 720px"></figure><p>I wired these up to the TDI and TDO pins of the Jeff Probe; these aren&apos;t used when speaking SW-DP protocol, but the Blackmagic probe has a handy feature where you can set the lines to be logically attached to the second tty device presented by the probe, giving you a serial console. This behavior can be switched on in GDB via the command: <code>monitor convert_tdio enable</code> .</p><p>This was all working pretty well thus far, but of course still no BLE. I had a feeling this would be tough to get working and I was right, but not for any reason that I predicted.</p><h2 id="bluefruitlib">BluefruitLib</h2><p>To make things easier for myself I tried to find some Arduino-friendly way to do this. I figured I already have a working Arduino core, so this should just drop right in, right? Well kinda, but also no. Adafruit has a BluefruitLib library that seems to be super easy to use and even had some examples:</p><figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Adafruit_nRF52_Arduino/libraries/Bluefruit52Lib at master &#xB7; adafruit/Adafruit_nRF52_Arduino</div><div class="kg-bookmark-description">Adafruit code for the Nordic nRF52 BLE SoC on Arduino - Adafruit_nRF52_Arduino/libraries/Bluefruit52Lib at master &#xB7; adafruit/Adafruit_nRF52_Arduino</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="BLE Covid Test #3: Bringing it all together!"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">adafruit</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/e0649810b3a29d0164c107398b5e05cec71c8e42fa1b0f7a671dea9499623312/adafruit/Adafruit_nRF52_Arduino" alt="BLE Covid Test #3: Bringing it all together!"></div></a><figcaption>This should be easy enough...</figcaption></figure><p>But some digging around revealed that I couldn&apos;t just copy/paste that library into the Arduino core I was working with. This is because the library depends on the Adafruit core specifically, which is quite different from the one I have been working with and ported to the nRF52810. While being Arduinoish, it&apos;s actually based on FreeRTOS; BluefruitLib and its dependencies depend on the specifics of this core, and some FreeRTOS parts, in order to work.</p><h2 id="take-1">Take 1</h2><p>So I investigated trying to pull BluefruitLib and its dependencies out one-by-one, along with FreeRTOS. This was not as painful as one might fear, but it was quite painful. One problem was that this port of FreeRTOS seems to require hard floating point support - something the nRF52810 doesn&apos;t have. So I tried to mess with the context switching function, to avoid switching out FP registers, and hopefully make it compatible. In the end there was just a bunch of this kind of nonsense to get something basic building, and the result didn&apos;t even work! &#x1F622; &#x1F5D1;&#xFE0F;</p><h2 id="take-2"> Take 2</h2><p>I mostly threw that monstrosity away and tried a different <s>monstrosity</s> approach, this time starting with the new Adafruit core for which BluefruitLib and its dependencies was designed. I had a pretty good understanding of how an Arduino core hung together at this point, and figured it wouldn&apos;t be terribly hard to port the Adafruit core (for the most part) to the nRF52810, remove the bits of FreeRTOS that didn&apos;t work for me and just try to kludge it into working in some minimal way. I did this work and actually got something building, downloaded and running! The UART was funky, but I figured I could sort that out. The biggest problem was when I tried to do anything with Bluetooth, BluefruitLib and all its friends would get pulled in as dependencies. The poor nRF52810 has a lot less memory than what these components are normally running on, so it didn&apos;t fit! &#x1F62D;<br>I tried hacking bits off, to no avail. And yeah, the UART didn&apos;t work. &#x1F5D1;&#xFE0F;</p><h2 id="take-3">Take 3</h2><p>So my next attempt and the one that ultimately worked, was to go back to my original core, dispensing with BluefruitLib, FreeRTOS et al, and basically do the bluetooth interaction from scratch, ripping the necessary parts out of BluefruitLib. I only wanted a BLE beacon; I didn&apos;t even want connections/pairing, so that&apos;s a pretty small amount of functionality, I thought.</p><h2 id="wtf-is-a-softdevice">WTF is a Softdevice?</h2><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2022/01/image.png" class="kg-image" alt="BLE Covid Test #3: Bringing it all together!" loading="lazy" width="640" height="480" srcset="https://routevegetable.com/content/images/size/w600/2022/01/image.png 600w, https://routevegetable.com/content/images/2022/01/image.png 640w"></figure><p>Thus far, I had been mainly running only the code in the Arduino core. I&apos;ve not been using any bootloader etc; just writing my program directly into the MCU&apos;s flash at an appropriate address, so it&apos;s the first thing to run at powerup. This is fine and reasonable until you want to use BLE. It seems to be a universal constant that the presence of wireless hardware necessitates a binary blob. For Nordic&apos;s nRF52 devices, this blob is called a &quot;Softdevice&quot;.</p><p>You use it by writing it into the flash where you would normally write your application, so it has control of the MCU on power up. It then acts a bit like a hypervisor - after doing some initialization itself, it jumps to the code located immediately after itself in flash (your application goes here) in exactly the way the CPU would do at power up; specifically, it expects to find an ARM interrupt vector table at that location, and jumps to the reset vector therein.</p><p>So you have this softdevice written into the lower chunk of flash, and your application, with its vector table, needs to be loaded immediately above it. This APP_CODE_BASE address is always immediately after the end of the softdevice blob (modulo some alignment), so the version of softdevice blob installed actually needs to match the sizes/offsets in the application&apos;s linker script; such a linker script will contain a memory layout like this:</p><figure class="kg-card kg-code-card"><pre><code>MEMORY
{
  FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0x30000 - 0x26000
  RAM (rwx)  : ORIGIN = 0x20003600, LENGTH = 0x20006000 - 0x20003600
}</code></pre><figcaption>0x26000 bytes are &apos;reserved&apos; at the start of the flash memory (which actually begins at 0x0), for the softdevice, which assumes the &apos;real application&apos; starts at 0x26000.</figcaption></figure><p>A corollary of this setup is that the softdevice gets first dibs on any interrupts; it can handle an interrupt itself or (normally) it can forward it to the application&apos;s vector table. Your application can access the hardware directly as usual, but it needs to ask the softdevice blob to do BLE work. Your application also needs to avoid touching RTC0, which the softdevice expects to have exclusive access to. There is an API to call various functions of the softdevice, which seems to be implemented using software interrupts.</p><p><strong>SO! </strong>As part of my &quot;Take 3&quot; I also needed to upgrade the softdevice version (and API headers) to match the version (v6.1.1) used in the Adafruit code I was callously ripping out of BluefruitLib, to ensure it would work properly with minimal adjustment.</p><h2 id="success">Success!</h2><p>After a whole lot of mashing sourcecode around into the right shape, I got everything into a function that&apos;s needed to initialize a beacon that broadcasts for 3 seconds.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/routevegetable/arduino-nRF5/blob/6058680eed78d70bd81cc442ad234bbf1a7dc8b5/cores/nRF5/nrf_ble_utils.cpp#L123"><div class="kg-bookmark-content"><div class="kg-bookmark-title">arduino-nRF5/nrf_ble_utils.cpp at 6058680eed78d70bd81cc442ad234bbf1a7dc8b5 &#xB7; routevegetable/arduino-nRF5</div><div class="kg-bookmark-description">Arduino core + example for turning an Ellume Covid test into a BLE beacon - arduino-nRF5/nrf_ble_utils.cpp at 6058680eed78d70bd81cc442ad234bbf1a7dc8b5 &#xB7; routevegetable/arduino-nRF5</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="BLE Covid Test #3: Bringing it all together!"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">routevegetable</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/c1ca1e76ec723c9f0949863543d5ffe4518b2ec9cb0e7dd365b522f86eb72b52/routevegetable/arduino-nRF5" alt="BLE Covid Test #3: Bringing it all together!"></div></a></figure><p>Moreover, what I ended up doing for this project was read the internal temperature sensor of the MCU and include that reading in the minor number of the beacon. Not particularly big or clever, but undeniably satisfying and it actually seems pretty accurate as far as I can tell.</p><h2 id="irqssoftdevice-events">IRQs/SoftDevice Events</h2><p>The softdevice pretty much completely handles the transmission, signalling the user application that it has run for the desired time, via an &quot;SD Event&quot;:</p><p>SD Events are delivered to the application via a interrupt; or rather, your application receives an interrupt when there are events to read from the softdevice. Such a handler in your application might look like this:</p><pre><code class="language-C">extern &quot;C&quot; void SD_EVT_IRQHandler(void)
{
  got_sd_events = true;
}</code></pre><p>The application&apos;s main loop can then periodically check this flag and, if it is set, retrieve any pending events via a softdevice call. The code could look like this:</p><pre><code class="language-C">if(got_sd_events)
{
    got_sd_events = false;

    // For each pending event:
    bool done = false;
    while(!done)
    {
        // Get BLE event from softdevice
        uint32_t err = sd_ble_evt_get(ev_buf, &amp;ev_len);

        switch (err) {
        case NRF_SUCCESS:
            /* ... Handle event ... */
            break;
        case NRF_ERROR_NOT_FOUND:
            /* ... Done processing all events */
            done = true;
            break;
        default:
            /* Some kind of error! */
            done = true;
            break;
        }
    }
}</code></pre><p></p><h2 id="sleeping">Sleeping</h2><p>This is an area where my inexperience with the nRF52 shows. I was expecting to find something akin to the ESP32&apos;s model of deep sleep, light sleep, etc... I found this isn&apos;t exactly the case - the nRF52 is just a way less power-hungry chip. To get decent power usage, you can just...stop doing things. Sitting in a loop or on a <code>wfi</code> instruction, with the automatic low power mode enabled (simply <code>NRF_POWER-&gt;LOWPWR = 1;</code>) gets the chip down into the range of 10s of microamps. The datasheet suggests much more power saving is possible, down to sub-microamp amounts by disabling peripherals, clocks and RAM retention, but my lack of patience got the better of me and I just wanted to see it do some stuff. So I made a very much belt-and-braces implementation &#xA0;of &apos;do a thing, sleep for 30 seconds, do it again, and so on...&apos;. From power-on, I do 3 seconds of beacon-transmitting, then I embark upon the following litany of crazed off-switch-throwing:</p><figure class="kg-card kg-code-card"><pre><code class="language-C">Serial.end();
// Disable softdevice
sd_softdevice_disable();

// Kill RTC interrupt for better quality sleep
NVIC_DisableIRQ(RTC1_IRQn);

// Kill timers?
NRF_TIMER0-&gt;TASKS_STOP = 1;
NRF_TIMER1-&gt;TASKS_STOP = 1;
NRF_TIMER2-&gt;TASKS_STOP = 1;

// Kill RTCs?
NRF_RTC0-&gt;TASKS_STOP = 1;
NRF_RTC1-&gt;TASKS_STOP = 1;

// Wake after some time
#define WAKE_SECS 30
NRF_RTC0-&gt;PRESCALER = 4095; // 8Hz
NRF_RTC0-&gt;CC[0] = WAKE_SECS * 8;

NRF_RTC0-&gt;INTENSET = RTC_INTENSET_COMPARE0_Msk;
NRF_RTC0-&gt;EVTENSET = 0;

NVIC_EnableIRQ(RTC0_IRQn);
NRF_RTC0-&gt;TASKS_START = 1;

__WFI();
NVIC_SystemReset();</code></pre><figcaption>These things seemed to reduce power consumption and it was getting late enough I didn&apos;t care much about pruning the non-useful ones. I then go into a WFI instruction, where the CPU should sit until the RTC counter hits the configured value, and an interrupt fires. If for some reason we proceed beyond the WFI, we immediately reset. I don&apos;t know enough about ARM or the current state of this chip to know if this is possible, but figured it wouldn&apos;t hurt.</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-C">extern &quot;C&quot; void RTC0_IRQHandler(void) {
      NVIC_SystemReset();
}</code></pre><figcaption>This interrupt handler fires after 30 seconds, resetting everything and starting over again.</figcaption></figure><p></p><p>I&apos;m quite sleep deprived at this point, but after a solid 4 days of frustration and learning, it all seems to work. A day or so later, it&apos;s still reporting in. Given the high frequency of broadcasting and lack of attention to detail around power consumption, I doubt this will last a week on the coin cell the device came installed with, but it&apos;ll be interesting to see!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2022/01/signal-2022-01-09-192605_001.jpeg" class="kg-image" alt="BLE Covid Test #3: Bringing it all together!" loading="lazy" width="1068" height="656" srcset="https://routevegetable.com/content/images/size/w600/2022/01/signal-2022-01-09-192605_001.jpeg 600w, https://routevegetable.com/content/images/size/w1000/2022/01/signal-2022-01-09-192605_001.jpeg 1000w, https://routevegetable.com/content/images/2022/01/signal-2022-01-09-192605_001.jpeg 1068w" sizes="(min-width: 720px) 720px"><figcaption>As I said, sleep deprived</figcaption></figure><h3 id="conclusion-future-things">Conclusion &amp; Future things</h3><p>The Arduino core I am using, with parts added on to do BLE beacon business with an Ellume COVID test, can be found here:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/routevegetable/arduino-nRF5"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - routevegetable/arduino-nRF5: Arduino core + example for turning an Ellume Covid test into a BLE beacon</div><div class="kg-bookmark-description">Arduino core + example for turning an Ellume Covid test into a BLE beacon - GitHub - routevegetable/arduino-nRF5: Arduino core + example for turning an Ellume Covid test into a BLE beacon</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="BLE Covid Test #3: Bringing it all together!"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">routevegetable</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/c1ca1e76ec723c9f0949863543d5ffe4518b2ec9cb0e7dd365b522f86eb72b52/routevegetable/arduino-nRF5" alt="BLE Covid Test #3: Bringing it all together!"></div></a></figure><p>I want to get a better handle on the way sleep works on these devices - there&apos;s clearly a lot more I could be doing to save power, and a lot of potential for the kinds of low-powered applications that interest me.</p><p>It would be good to be able to do OTA firmware updates without physically plugging in a SW-DP probe. I suspect there&apos;s a good amount of memory left, which could be used to hold a replacement image, and the softdevice seems to have software update-relevant parts to do these kinds of things robustly.</p><p>Even if I don&apos;t bother figuring out how to do OTA, it&apos;d be nice to be able to program this thing without soldering 3 wires to it every time, so I&apos;ll have a think about how to more neatly do that.</p><p>Finally, that damn button I broke is really bugging me. For a beacon which just periodically broadcasts autonomously it&apos;s not really relevant, but i&apos;m sure there are useful things I could come up with if I could figure out the button.</p>]]></content:encoded></item><item><title><![CDATA[BLE COVID Test #2: Jeff Probe + nRF52810]]></title><description><![CDATA[<p>Next in my list of things to do with this <a href="https://routevegetable.com/ble-covid-test/">COVID test</a> is figure out how to program it/erase it using the programming port I mentioned previously. I acquired a <a href="https://flirc.tv/more/flirc-jeff-probe-bmp-jtag-black-magic-probe">Jeff Probe</a> - a Blackmagic-based/compatible multipurpose JTAG device, which I was going to try to use for this.</p>]]></description><link>https://routevegetable.com/covid-test-2/</link><guid isPermaLink="false">61d52c73f3057b0b4e98b942</guid><category><![CDATA[BLE]]></category><category><![CDATA[nRF52810]]></category><category><![CDATA[Arduino]]></category><category><![CDATA[JTAG]]></category><category><![CDATA[GDB]]></category><category><![CDATA[Electronics]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Thu, 06 Jan 2022 01:02:45 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2022/01/PXL_20220104_212128027-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2022/01/PXL_20220104_212128027-2.jpg" alt="BLE COVID Test #2: Jeff Probe + nRF52810"><p>Next in my list of things to do with this <a href="https://routevegetable.com/ble-covid-test/">COVID test</a> is figure out how to program it/erase it using the programming port I mentioned previously. I acquired a <a href="https://flirc.tv/more/flirc-jeff-probe-bmp-jtag-black-magic-probe">Jeff Probe</a> - a Blackmagic-based/compatible multipurpose JTAG device, which I was going to try to use for this.</p><p>Things didn&apos;t just work out of the box; of course they didn&apos;t!</p><p>First off, I didn&apos;t realize the IDC connector on the Jeff Probe was 1mm pitch, rather than the 2.54mm I had in my brain. So much for my plan for soldering some wires onto the board and simply jamming them into the IDC cable holes - they&apos;re too small. I tried using some very thin wire...</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2022/01/signal-2022-01-05-165630_001.jpeg" class="kg-image" alt="BLE COVID Test #2: Jeff Probe + nRF52810" loading="lazy" width="2000" height="1500" srcset="https://routevegetable.com/content/images/size/w600/2022/01/signal-2022-01-05-165630_001.jpeg 600w, https://routevegetable.com/content/images/size/w1000/2022/01/signal-2022-01-05-165630_001.jpeg 1000w, https://routevegetable.com/content/images/size/w1600/2022/01/signal-2022-01-05-165630_001.jpeg 1600w, https://routevegetable.com/content/images/2022/01/signal-2022-01-05-165630_001.jpeg 2048w" sizes="(min-width: 720px) 720px"></figure><p>But even after I mostly stopped the wires popping out of the IDC connector, things weren&apos;t happening - the probe wasn&apos;t finding the MCU:</p><pre><code>(gdb) target extended-remote /dev/ttyACM1
Remote debugging using /dev/ttyACM1
(gdb) monitor swdp_scan
Target voltage: 3.3V
SW-DP scan failed!</code></pre><p>I figured I needed pullups on the clock and data lines and/or a better connection, so I slowed down, put things on a breadboard with some Dupont wires, and legitimately tried make an okay job of it. It felt slow and tedious, but worth it - I didn&apos;t have to worry about wires popping out or snapping as 30AWG tends to do.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2022/01/signal-2022-01-05-162333.jpeg" class="kg-image" alt="BLE COVID Test #2: Jeff Probe + nRF52810" loading="lazy" width="2000" height="1500" srcset="https://routevegetable.com/content/images/size/w600/2022/01/signal-2022-01-05-162333.jpeg 600w, https://routevegetable.com/content/images/size/w1000/2022/01/signal-2022-01-05-162333.jpeg 1000w, https://routevegetable.com/content/images/size/w1600/2022/01/signal-2022-01-05-162333.jpeg 1600w, https://routevegetable.com/content/images/2022/01/signal-2022-01-05-162333.jpeg 2048w" sizes="(min-width: 720px) 720px"><figcaption>Slightly more effort</figcaption></figure><p>But even with all that...</p><pre><code>(gdb) monitor swdp_scan
Target voltage: 3.3V
SW-DP scan failed!</code></pre><p>Arg!<br>I figured I needed the source code for this thing to better understand what could be going wrong; this was easy enough to get hold of - I just cloned the <a href="https://github.com/blacksphere/blackmagic">Blackmagic git repo</a>. I also figured I should update the firmware to the latest, because why not!? Maybe it will fix my problem. So I make&apos;d the Makefile after taking care of some dependencies, and used the dfu-util tool to download the generated file to it. And...it stopped working completely! Unplug...replug...nothing; nothing even in dmesg!</p><p>I panicked a bit, concerned I had bricked my brand new probe. Fortunately after messing with the button on it, I found that plugging it in *while* the button is depressed puts it in some bootloader mode, where at the very least you can install new things on it; so it wasn&apos;t bricked! Still didn&apos;t work though...</p><p>I realized my error: I needed firmware built for the Jeff Probe, duh! Not the blackmagic probe. They might be compatible from a user perspective, look similar and run largely the same software, but they have different MCUs, different peripherals etc; I&apos;m not sure how I expected it to work.</p><p>So I acquired the <a href="https://github.com/flirc/blackmagic">Jeff Probe fork of the firmware</a>, built it, downloaded it and... same problem; I was befuddled! How is anyone supposed to use this? I spent ages trying to figure it out, incl. manually messing around with the existing supported platforms to match the Jeff Probe (a dangerous game that risks overwriting the bootloader) - my hopes were low and I was almost ready to throw in the towel and just buy a Blackmagic probe so I could get on with my project. Then, somehow, I noticed something: the Jeff Probe repo has a <a href="https://github.com/flirc/blackmagic/tree/sam">branch called &quot;sam&quot;</a>. I checked it out in my repo and lo and behold there it was - the <code>platforms/sam/jeff</code> directory! I had a good feeling about this. I built and downloaded it hungrily....it worked normally! As above, it still didn&apos;t find the nRF52810, but I was now able to build firmware from source code - that&apos;s some kind of progress!</p><p>So while the latest Jeff Probe firmware does seem to support some nRF52 chips (see <code>src/target/nrf51.c</code>), it doesn&apos;t support the Control Access Port or &quot;CTRL-AP&quot;. This is needed to re-enable access to the main debug port, if it has been protected. So I tried to backport the code to support this, from the original blackmagic repo. After a lot of messing around (things had not changed too much since the Jeff Probe fork, but they had changed somewhat) I got it building.</p><p>I downloaded and connected everything, and it showed the access port in the scan! This is the first hard evidence I&apos;ve had that the wiring is good, and the debug port isn&apos;t disabled some other way, so I am super pleased about this.</p><p>Attaching seems to be a problem - the probe stops responding... more staring at code... I find that my backported code needs to initialize a struct to default values, which in the modern codebase has been refactored to be done elsewhere. I added the following nonsense to the appropriate place:</p><pre><code class="language-C">t-&gt;attach = (void*)nop_function;
t-&gt;detach = (void*)nop_function;
t-&gt;check_error = (void*)nop_function;
t-&gt;mem_read = (void*)nop_function;
t-&gt;mem_write = (void*)nop_function;
t-&gt;regs_read = (void*)nop_function;
t-&gt;regs_write = (void*)nop_function;
t-&gt;reset = (void*)nop_function;
t-&gt;halt_request = (void*)nop_function;
t-&gt;halt_poll = mdm_halt_poll;
t-&gt;halt_resume = (void*)nop_function;</code></pre><p>and it works! I can now both scan and attach to the Access Port without the probe crashing!</p><pre><code>(gdb) monitor swdp_scan
Target voltage: 3.3V
Available Targets:
No. Att Driver 1
      Nordic nRF52 Access Port (protected)
(gdb) attach 1
Attaching to Remote target
warning: while parsing target description: no element found
warning: Could not load XML target description; ignoring
PC register is not available</code></pre><p>Here we see the access port is indeed &quot;protected&quot;, so we need to unprotect it via the <code>monitor erase_mass</code> command:</p><pre><code>(gdb) monitor erase_mass
(gdb) detach
Detaching from program: , Remote target
(gdb) monitor hard_srst
(gdb) monitor swdp_scan
Target voltage: 3.3V
Available Targets:
No. Att Driver
1      ARM Cortex-M
2      Nordic nRF52 Access Port</code></pre><p>After resetting the chip, &quot;ARM Cortex-M&quot; is clearly visible as another target, meaning I have successfully erased the firmware, unprotecting the debug port; w00t!</p><p>I next try attaching to the &quot;ARM Cortex-M&quot; target; it complains about a missing memory map, but registers are accessible. On the missing memory map, more poking (peeking, rather) reveals my chip&apos;s device ID is not present in the hard coded list and the probe isn&apos;t identifying it as specifically an nRF52; it&apos;s falling back to a generic &quot;Cortex-M&quot; CPU target. It looks like the latest blackmagic firmware (from the original blackmagic repo) dispenses with the list and handles things differently, with ignorance of the device ID - probably a more robust approach, as this ID seems to change with chip revision.</p><p>Rather than backport these changes too, I simply added my chip&apos;s device ID to the list of known nRF52 devices. Rebuild, download, it works:</p><pre><code>(gdb) mon swdp_scan
Target voltage: 3.3V
Available Targets:
No. Att Driver
 1      Nordic nRF52
 2      Nordic nRF52 Access Port
(gdb) attach 1
A program is being debugged already.  Kill it? (y or n) y
Attaching to Remote target
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the &quot;file&quot; command.
0xfffffffe in ?? ()
0xfffffffe in ?? ()
(gdb) info mem 
Using memory regions provided by the target.
Num Enb Low Addr   High Addr  Attrs 
0   y  	0x00000000 0x00030000 flash blocksize 0x1000 nocache 
1   y  	0x10001000 0x10001100 flash blocksize 0x100 nocache 
2   y  	0x20000000 0x20006000 rw nocache 
(gdb) 
</code></pre><p>AAAAAAA that was so much messing around!</p><p>This should be everything I need in order to get code into the chip, and maybe even debug it.</p><p>Here&apos;s the repo:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/routevegetable/blackmagic/tree/sam"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - routevegetable/blackmagic at sam</div><div class="kg-bookmark-description">In application debugger for ARM Cortex microcontrollers. - GitHub - routevegetable/blackmagic at sam</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="BLE COVID Test #2: Jeff Probe + nRF52810"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">routevegetable</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/9744788368969acdd7cc59e253c75b5db3e4c21d501b0730ae16b4e05661ff93/routevegetable/blackmagic" alt="BLE COVID Test #2: Jeff Probe + nRF52810"></div></a></figure><p>Building &amp; Downloading the firmware is simply a matter of:</p><pre><code class="language-shell">make PROBE_HOST=jeff
...
...
...

sudo dfu-util -d 0000:0000 -s 0x2000:leave -D src/blackmagic.bin</code></pre><p>Next up, i&apos;ll be trying to run some actual code on this thing!</p>]]></content:encoded></item><item><title><![CDATA[What's inside a BLE COVID test?]]></title><description><![CDATA[<p>This week for some extra peace of mind, my friend let me use one of their spare rapid tests prior to visiting with them later in the day. With the Omicron variant rampaging around, it seemed like a wise precaution on top of us both being vaccinated/boosted.</p><p><a href="https://www.ellumecovidtest.com/home-test">This particular</a></p>]]></description><link>https://routevegetable.com/ble-covid-test/</link><guid isPermaLink="false">61d08bb9f3057b0b4e98b78c</guid><category><![CDATA[BLE]]></category><category><![CDATA[nRF52810]]></category><category><![CDATA[Arduino]]></category><category><![CDATA[Electronics]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Sat, 01 Jan 2022 20:51:30 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2022/01/img_feature_eua_01-825x340-9.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2022/01/img_feature_eua_01-825x340-9.jpg" alt="What&apos;s inside a BLE COVID test?"><p>This week for some extra peace of mind, my friend let me use one of their spare rapid tests prior to visiting with them later in the day. With the Omicron variant rampaging around, it seemed like a wise precaution on top of us both being vaccinated/boosted.</p><p><a href="https://www.ellumecovidtest.com/home-test">This particular test</a> works in conjunction with a smartphone app. After connecting the &quot;analyzer&quot; to the app, you drop your sample in a small hole. 15 minutes later, the app displays the test result.</p><p>After the test had given me my negative result, I decided to disassemble the analyzer</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2022/01/signal-2021-12-31-111337.jpeg" class="kg-image" alt="What&apos;s inside a BLE COVID test?" loading="lazy" width="1080" height="1794" srcset="https://routevegetable.com/content/images/size/w600/2022/01/signal-2021-12-31-111337.jpeg 600w, https://routevegetable.com/content/images/size/w1000/2022/01/signal-2021-12-31-111337.jpeg 1000w, https://routevegetable.com/content/images/2022/01/signal-2021-12-31-111337.jpeg 1080w" sizes="(min-width: 720px) 720px"></figure><p>The white strip, normally mounted above the PCB, is the COVID-relevant part. This is a seemingly typical lateral flow test strip, positioned such that the end is under the sample-accepting hole. On the other side not pictured are a pair of pregnancy test-style lines. Presumably one shows blue to indicate the test is valid, while the other indicates a positive result when visible. There are some lights and sensors on the PCB aligned with these areas on the strip.</p><p>I am tempted to label this another instance of IoT-gone-mad, but maybe this one is potentially justifiable, given high stakes and low cost of powerful electronics, if you absolutely want to remove human error from the equation?</p><p>The white round pill-like object appears to be some kind of moisture absorber, which makes sense; the analyzer (and its contained strip) is kept in a sealed bag prior to use.</p><p>The QFN32 chip on the left of the PCB is where the magic happens - a Nordic Semiconductor <a href="https://infocenter.nordicsemi.com/pdf/nRF52810_PS_v1.0.pdf">nRF52810</a>. This is a BLE-capable microcontroller with GPIO and some internal peripherals including a temperature sensor. I figured it&apos;d be a fun exercise to try to reprogram the device, perhaps to make a bluetooth temperature sensor or beacon, or something similar. Encouragingly, there are <a href="https://www.adafruit.com/?q=nrf52&amp;sort=BestMatch">a bunch of nRF52-based boards</a> on Adafruit with complete Arduino-compatible firmware, including parts to drive the BLE radio; hopefully that will not be difficult to leverage here.</p><p>I did some poking around with a multimeter, hoping the set of 7 pads near the right end of the PCB was a programming port of some kind. This turned out to be the case, and the 3-wire ARM &quot;SWD&quot; (Serial Wire Debug) port, or &quot;SW-DP&quot; can be found here.</p><p>The meanings of each pad, specifically:<br>1. GND<br>2. ?<br>3. ?<br>4. VDD<br>5. SWDIO<br>6. SWCLK<br>7. Reset</p><p>I couldn&apos;t find the meaning of #2 and #3 without more poking than I felt like doing for now, though it might come up later.</p><p>The MCU has integrated power conditioning/regulation, and there&apos;s no obvious external regulator. There&apos;s what is probably a P-channel MOSFET between the battery + and VDD. When the analyzer is powered down the gate is pulled high, seemingly to avoid draining the battery via leakage current while not in use.</p><p>Though it&apos;s physically awkward to verify, the sole button on the device probably holds this gate low when pressed, powering up the MCU. The firmware then likely engages some GPIO to keep the gate low after the button has been released. The MCU can then release that when it decides to power itself off.</p><p>While the device is powered up, the button is held down to initiate some &apos;pairing&apos; with the smartphone app, so I expect there&apos;s some extra circuitry that permits the state of the button to be read via a separate GPIO.</p><p>I ordered an <a href="https://www.amazon.com/gp/product/B07ZK4LFTQ">open source JTAG interface</a> which seems to be nRF52 compatible, glancing at <a href="https://github.com/blacksphere/blackmagic/wiki ">the github repo</a>. I&apos;ve used such products rarely and could be missing some obvious reason this won&apos;t work, but so far it&apos;s looking positive. The code in the repo also shows that there&apos;s support for the MCU&apos;s ERASEALL command via the CTRL-AP or Control Access Port. <a href="https://github.com/blacksphere/blackmagic/blob/master/src/target/nrf51.c#L442">Confusingly, this is internally referred to as &quot;erase_mass&quot;</a>; this will be needed for writing new code, if it turns out the MCU&apos;s program memory is protected.</p><p>I&apos;ll keep thinking about possible applications for this, and when the JTAG interface arrives in the mail I can actually try some stuff.</p>]]></content:encoded></item><item><title><![CDATA[exec considered harmful?]]></title><description><![CDATA[<p>Is &apos;exec&apos; an abstraction leak wrt &apos;client code&apos;? When a program wants to use some other bit of code to do something, there are a number of ways it does it, including:</p><ul><li>open a socket and send a request/start a communication</li><li>spawn a program to</li></ul>]]></description><link>https://routevegetable.com/exec-considered-harmful/</link><guid isPermaLink="false">604d3ef924bf4e295f4cc3a1</guid><category><![CDATA[Linux]]></category><category><![CDATA[UNIX]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Sat, 13 Mar 2021 22:44:52 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2021/03/execve.png" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2021/03/execve.png" alt="exec considered harmful?"><p>Is &apos;exec&apos; an abstraction leak wrt &apos;client code&apos;? When a program wants to use some other bit of code to do something, there are a number of ways it does it, including:</p><ul><li>open a socket and send a request/start a communication</li><li>spawn a program to do the thing</li></ul><p>Out of these two, the commonality is &quot;I want to invoke someone else&apos;s code to perform a service for me&quot;. One is saying: &quot;I want to talk to a process which is already running&quot;, the other one is &quot;I want to make a new process&quot;.</p><p>So in order to decide which one to use, your code needs to have an understanding of what a process is, and also how the service you want relates to that concept.</p><p>This seems like an irrelevant-to-client-code implementation detail of the service being requested; why should the client know or care if a new memory space and thread must be created to best handle what it&apos;s asking for?</p><p>This degree of freedom also ends up papered over as necessary:</p><ul><li>A library may be used to abstract the difference, providing a function which internally communicates with a running server or spawns a new program as appropriate.</li><li>Some programs even when exec&apos;d, just tell a running server to start a new instance in its own process (examples: chrome, gnome-terminal)</li></ul><p>So my thought is perhaps &apos;exec&apos; really shouldn&apos;t be used by client code. Perhaps it wants to be something more akin to an administration command, like &apos;mount&apos;.<br>Perhaps in the days of yore, to exec or not exec was a useful degree of freedom, but these days I&apos;m not sure.</p><p>If we were going to make a brand new unix, perhaps systemd would be in charge of execing things; the OS would maintain a registry of installed services, and new programs could invoke those things in some standardized way; it&apos;d be up to the service whether it wanted to spawn a new process, new thread or whatever, to handle a given request.</p>]]></content:encoded></item><item><title><![CDATA[ESP32 Solar Camera Project]]></title><description><![CDATA[<p>In general I&apos;ve been moving away from only building complex/technically-flashy things in my spare time and just trying to build things which are neat, even if they are simple. This is to help me avoid burnout, and quell impulses of perfectionism which tend to monopolize my time.</p>]]></description><link>https://routevegetable.com/solar-camera/</link><guid isPermaLink="false">60425f7e24bf4e295f4cc0a9</guid><category><![CDATA[IOT]]></category><category><![CDATA[ESP32]]></category><category><![CDATA[Electronics]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Fri, 05 Mar 2021 21:05:55 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2021/03/157594397_508501333876625_309086994300240741_n--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2021/03/157594397_508501333876625_309086994300240741_n--1-.jpg" alt="ESP32 Solar Camera Project"><p>In general I&apos;ve been moving away from only building complex/technically-flashy things in my spare time and just trying to build things which are neat, even if they are simple. This is to help me avoid burnout, and quell impulses of perfectionism which tend to monopolize my time.</p><p>I&apos;d been doing a bit of reading about solar panels and wanted to build something solar-powered. Particularly with my recent low-power ESP32 escapades, I was ready to do something in that vein. I got to work planning and prototyping with a goal of building a thingy which would collect solar energy, periodically taking a photo and uploading it somewhere.</p><p>This all ended up taking far longer than I expected it to.</p><h2 id="first-attempt">First Attempt</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2021/03/ouch.png" class="kg-image" alt="ESP32 Solar Camera Project" loading="lazy" width="692" height="438" srcset="https://routevegetable.com/content/images/size/w600/2021/03/ouch.png 600w, https://routevegetable.com/content/images/2021/03/ouch.png 692w"><figcaption>At one point, this is what things looked like</figcaption></figure><p>I started by drawing things in CircuitLab and playing with breadboards. I desired to use a 2.5ish V solar panel I harvested from a yard lantern. I figured that with a boost converter, I could take whatever this panel was putting out up to 5V and use that to charge a supercapacitor. Then I could take another boost converter and use that to power my ESP32-CAM module and boom! Job done! Or...not.</p><h3 id="supercapacitor-charging">Supercapacitor Charging</h3><p>First off, you can&apos;t just hook a boost converter to a supercapacitor; the supercapacitor has very low impedance and, when it&apos;s empty, will effectively &apos;short out&apos; the boost converter. So you need some kind of current limiting. No problem there - I can just make such thing with an opamp and a reasonably chunky MOSFET. So I did that and, after some messing around, I managed to charge a supercapacitor at a current-limited rate, up to 5V, using a low voltage solar panel. Hurrah!</p><h3 id="uvlo">UVLO</h3><p>I also needed an undervoltage lockout circuit or UVLO - this circuit avoids powering the ESP32 until some voltage threshold is reached by the supercapacitor. A UVLO then only switches off when a (lower) off-threshold is crossed.</p><p>It&apos;s needed because the ESP32 sucks quite a lot of power on startup, and if it were allowed to turn on as soon as the boost converter sensed enough supercap charge to start, it would immediately:</p><ul><li>Suck a lot of current out of the supercap</li><li>The supercap voltage would drop too low for the boost converter to operate</li><li>The boost converter would stop working and stop drawing current</li><li>The supercap voltage would go high enough to start the boost converter</li><li>Start all over again</li></ul><p>This would repeat over and over and make no progress. No problem! The hysteresis portion of the UVLO can be implemented with an op-amp and positive feedback network, and I already have a dual op-amp chip in the design from the current limiter, so I can use the other op-amp in there with another MOSFET, to implement a UVLO. This also seemed to work, after a little tweaking.</p><h3 id="i-got-a-bit-carried-away">I got a bit carried away</h3><p>This is where things took a turn for the complicated. I didn&apos;t like having 2 boost converters in a design when theoretically, the services of only one should be enough. So I got to designing a circuit that would share the input to the boost converter between the solar input, and the supercap&apos;s charge, and would use that boosted output to power the ESP32, and also charge the supercap further when appropriate. It was a neat design and...I basically just couldn&apos;t get it working enough.</p><p>I even designed/ordered a PCB with all of the above, partially because I just wanted to make a PCB for the first time in a while, but also because I really thought it would work.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2021/03/155930398_2774339132878604_1260889137880726790_n.jpg" class="kg-image" alt="ESP32 Solar Camera Project" loading="lazy" width="2000" height="1500" srcset="https://routevegetable.com/content/images/size/w600/2021/03/155930398_2774339132878604_1260889137880726790_n.jpg 600w, https://routevegetable.com/content/images/size/w1000/2021/03/155930398_2774339132878604_1260889137880726790_n.jpg 1000w, https://routevegetable.com/content/images/size/w1600/2021/03/155930398_2774339132878604_1260889137880726790_n.jpg 1600w, https://routevegetable.com/content/images/2021/03/155930398_2774339132878604_1260889137880726790_n.jpg 2048w" sizes="(min-width: 720px) 720px"><figcaption>First PCB, heavily messed-with</figcaption></figure><p>There were multiple issues. One of the main ones being that the boost converter kept oscillating when the supercap charge got too low. I took measurements, experimented, asked on IRC and learned a bit more boost converters (A good article <a href="https://www.eetimes.com/power-tip-3-damping-the-input-filter-part-1/#">https://www.eetimes.com/power-tip-3-damping-the-input-filter-part-1/#</a>), and it turns out that having a small supply impedance is crucial to not accidentally making an oscillator here. I also learned that the supercaps I was using were quite low quality and had high equivalent series resistance (ESR), meaning that the input to the boost converter was wobbling all over the place. Notice in the picture above how I have a bunch of them paralleled.</p><h2 id="second-attempt">Second attempt</h2><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2021/03/157594397_508501333876625_309086994300240741_n--1--1.jpg" class="kg-image" alt="ESP32 Solar Camera Project" loading="lazy" width="2000" height="1500" srcset="https://routevegetable.com/content/images/size/w600/2021/03/157594397_508501333876625_309086994300240741_n--1--1.jpg 600w, https://routevegetable.com/content/images/size/w1000/2021/03/157594397_508501333876625_309086994300240741_n--1--1.jpg 1000w, https://routevegetable.com/content/images/size/w1600/2021/03/157594397_508501333876625_309086994300240741_n--1--1.jpg 1600w, https://routevegetable.com/content/images/2021/03/157594397_508501333876625_309086994300240741_n--1--1.jpg 2048w" sizes="(min-width: 720px) 720px"></figure><p>So after lots of lessons learned I canned that particular design and set about simplifying it all, while also filling in some gaps I left in the previous one. This time, I didn&apos;t bother trying to do the boost-converter sharing thing. Instead, I used a higher voltage solar panel (5v), which I could connect to the supercap directly. I still need a UVLO to power on/off the ESP32, but nothing more fancy than that.</p><p>Rather than working with the supercaps I had, I did some searching around and acquired some much nicer ones, with much lower ESR (<a href="https://www.newark.com/illinois-capacitor/dgh505q5r5/supercap-5f-5-5v-radial/dp/16AC9334">https://www.newark.com/illinois-capacitor/dgh505q5r5/supercap-5f-5-5v-radial/dp/16AC9334</a>). I only needed 1 in the end!</p><h3 id="some-new-features">Some New Features</h3><ul><li>Programming header/jumper</li><li>Area to mount the actual ESP32 &amp; boost converter</li><li>Space for WS2812 LEDs</li><li>Space for DHT-11 temperature/humidity sensor</li><li>Voltage divider for charge level sensing</li></ul><p>This all worked pretty well!</p><h2 id="software">Software</h2><p>My plan is to not rely on the UVLO during normal operation - while the sun is somewhat out, the ESP32 should try to stay running, checking the supercap charge level and collecting temperature/humidity data, even if there&apos;s not enough power to connect to Wifi and upload an image (by far the most power-expensive thing this circuit does).</p><p>The ESP32 features a &apos;deep sleep&apos; mode which shuts down most of the microcontroller, leaving the realtime clock and a small amount of RAM running, so it can wake back up based on a timer or other triggers. See here for more info: <a href="https://lastminuteengineers.com/esp32-deep-sleep-wakeup-sources/">https://lastminuteengineers.com/esp32-deep-sleep-wakeup-sources/</a>.</p><h3 id="sleep-algorithm">Sleep Algorithm</h3><p>I played with a bunch of strategies for saving power, but ended up going for the following:<br>There&apos;s a fixed &quot;wifi threshold&quot; - 4.4V. If the ESP32 reads this or higher voltage at startup, it&apos;ll try to take a picture and upload it over wifi. If not, it will log data, go to sleep for a bit then try again.</p><p>As for how long to sleep, we try 2-minute &quot;short sleeps&quot; for as long as the voltage always appears to be increasing (or staying above wifi threshold) between wakeups.</p><p>If the voltage is observed to drop during a short sleep, that means the power cost of waking the ESP32 is outstripping what power the solar panel can provide during a short sleep.</p><p>In this case, we switch to 30-minute &quot;long sleeps&quot;, staying in this &quot;long sleep&quot; mode until the wifi threshold is reached again. Once the wifi threshold is reached, we go back to trying short sleeps as above.</p><h2 id="data-logging">Data Logging</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2021/03/graph.png" class="kg-image" alt="ESP32 Solar Camera Project" loading="lazy" width="933" height="577" srcset="https://routevegetable.com/content/images/size/w600/2021/03/graph.png 600w, https://routevegetable.com/content/images/2021/03/graph.png 933w" sizes="(min-width: 720px) 720px"><figcaption>Some data collected this morning</figcaption></figure><p>Making use of the RTC and the RAM which persists through deep sleeps I decided to log the supercap voltage, as well as temperature and humidity from the DHT-11 sensor on every startup, regardless of whether there is enough power for wifi.</p><p>Then at the next wifi connection, we upload all of the previously logged data.</p><h2 id="cameras-are-hard">Cameras are hard</h2><p>So it&apos;s all working apart from one small detail; the camera is doing ALL KINDS of wacky stuff. I went through various strange failure/glitch modes.</p><h3 id="greenness">Greenness</h3><p>At one point, the camera would produce green-tinted images. I went down various rabbit holes suspecting electrical issues, a faulty SPI RAM chip, etc... It turned out to be very straightforward - the camera needs some number of frames to &apos;warm up&apos; and get its automatic gain control into a good place, and I wasn&apos;t giving it that because I was uploading the first frame that came out of it. Makes sense when you think about it!</p><h3 id="timeouts">Timeouts</h3><p>These OV2640 camera modules seem to be a bit unreliable - both of the ones I have don&apos;t always initialize the first time, and sometimes don&apos;t produce a frame. Some googling indicates this isn&apos;t completely unknown, and my solution is to basically retry a bunch of times, before giving up and going to sleep again.</p><h3 id="frame-corruption">Frame Corruption</h3><p>So here&apos;s a weird one. I noticed that if the sun moves into frame (or just seemingly randomly at other points), i&apos;d end up getting half a picture; eg:</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2021/03/oof.png" class="kg-image" alt="ESP32 Solar Camera Project" loading="lazy" width="544" height="453"></figure><p>After much googling, headscratching, playing with registers in the camera and reading the <a href="https://cdn.datasheetspdf.com/pdf-down/O/V/2/OV2640_OmniVisionTechnologie.pdf">OV2640 Reference Manual</a>, I have a theory about what causes this. The clock architecture is thus:</p><ul><li>The camera&apos;s &apos;main clock&apos; (XVCLK) is generated by the ESP32 (default 20MHz).</li><li>XVCLK is divided by the CLKRC register to generate the pixel/frame clocks internally.</li><li>This resulting clock is further converted via PLL/divider (R_DVP_SP) to PCLK, which is then used to clock data out of the camera and into the ESP32.</li></ul><p>So, reducing CLKRC makes the framerate increase, and reducing R_DVP_SP makes the data rate increase. However! One cannot simply reduce R_DVP_SP to its lowest possible value, as it will be shifting data out faster than the I2S peripheral in the ESP32 can consume it. Now, the amount of (JPEG) data to shift out depends on how much the image can be compressed. So I suspect the above happens when there&apos;s not enough time to shift out all of the data before the next frame starts. But I haven&apos;t confirmed this.</p><p>My solution has been to reduce the framerate (via CLKRC), then increase the PCLK (via R_DVP_SP) up to the maximum the ESP32 will tolerate. Leaving more time to get all the data out before the next frame starts.</p><h2 id="tools">Tools</h2><h3 id="circuitlab">CircuitLab</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.circuitlab.com/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Online circuit simulator &amp; schematic editor - CircuitLab</div><div class="kg-bookmark-description">Powerful online circuit simulator and schematic editor. Easy to learn.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.circuitlab.com/assets/images/apple-touch-icon-114x114.png" alt="ESP32 Solar Camera Project"><span class="kg-bookmark-author">CircuitLab</span><span class="kg-bookmark-publisher">&#x2014; yigitdemirag</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.circuitlab.com/assets/images/og_logo.png" alt="ESP32 Solar Camera Project"></div></a></figure><h3 id="eagle-pcb">Eagle PCB</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.autodesk.com/products/eagle/overview"><div class="kg-bookmark-content"><div class="kg-bookmark-title">EAGLE | PCB Design And Electrical Schematic Software | Autodesk</div><div class="kg-bookmark-description">Autodesk EAGLE is a powerful PCB design &amp; schematic software for professional electronics designers, with easy-to-use schematic editor, and powerful PCB layout.</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">BUY FUSION 360</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://damassets.autodesk.net/content/dam/autodesk/www/products/responsive-imagery/responsive-lockups-banners/2018/eagle-2017-lockup-1200x132.png" alt="ESP32 Solar Camera Project"></div></a></figure><h3 id="esp32-cam">ESP32-CAM</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.amazon.com/dp/B07S5PVZKV"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Amazon.com: 2 Pack ESP32-CAM WiFi Bluetooth Camera Module Development Board ESP32 with Camera Module OV2640: Computers &amp; Accessories</div><div class="kg-bookmark-description">Amazon.com: 2 Pack ESP32-CAM WiFi Bluetooth Camera Module Development Board ESP32 with Camera Module OV2640: Computers &amp; Accessories</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-publisher">Top 10 Zone</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:131-4407136-1633917:HXK2XER6SJVEBHPGHHHG$uedata=s:%2Frd%2Fuedata%3Fstaticb%26id%3DHXK2XER6SJVEBHPGHHHG%26pty%3DError%26spty%3DPageNotFound%26pti%3DB00T49A0OY:1000" alt="ESP32 Solar Camera Project"></div></a></figure><h3 id="esp-idf">ESP-IDF</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/espressif/esp-idf"><div class="kg-bookmark-content"><div class="kg-bookmark-title">espressif/esp-idf</div><div class="kg-bookmark-description">Espressif IoT Development Framework. Official development framework for ESP32. - espressif/esp-idf</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="ESP32 Solar Camera Project"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">espressif</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://avatars.githubusercontent.com/u/9460735?s=400&amp;v=4" alt="ESP32 Solar Camera Project"></div></a></figure><h3 id="esp32-camera">esp32-camera</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/espressif/esp32-camera"><div class="kg-bookmark-content"><div class="kg-bookmark-title">espressif/esp32-camera</div><div class="kg-bookmark-description">Contribute to espressif/esp32-camera development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="ESP32 Solar Camera Project"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">espressif</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://avatars.githubusercontent.com/u/9460735?s=400&amp;v=4" alt="ESP32 Solar Camera Project"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Window Management in the age of Covid-19]]></title><description><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2021/02/tiling.png" class="kg-image" alt loading="lazy"><figcaption>Emacs with EXWM (Screenshot courtesy of project)</figcaption></figure><p>About a year into the pandemic, I&apos;ve been working at home for quite some time now.<br>Aside from the obvious negatives, there are some positives to this whole thing:</p><ul><li>No more commuting! Still relatively new to the San Francisco Bay Area,</li></ul>]]></description><link>https://routevegetable.com/exwm/</link><guid isPermaLink="false">60287c60f8641b0300d3351e</guid><category><![CDATA[Linux]]></category><category><![CDATA[Emacs]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Sun, 14 Feb 2021 03:01:20 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2021/02/tiling-1.png" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2021/02/tiling.png" class="kg-image" alt="Window Management in the age of Covid-19" loading="lazy"><figcaption>Emacs with EXWM (Screenshot courtesy of project)</figcaption></figure><img src="https://routevegetable.com/content/images/2021/02/tiling-1.png" alt="Window Management in the age of Covid-19"><p>About a year into the pandemic, I&apos;ve been working at home for quite some time now.<br>Aside from the obvious negatives, there are some positives to this whole thing:</p><ul><li>No more commuting! Still relatively new to the San Francisco Bay Area, commuting holds some novelty. I like how it breaks up the day; a kind of life &quot;minigame&quot; if you will. However if I am being honest, I know it harms my productivity, at least in the immediate sense. Compared to days when I am working from home, it takes me a lot longer to &quot;settle down&quot; and start doing stuff in the morning.</li><li>More time! Now there&apos;s no commuting, I have more free time. That and lunchtime can be used for things I would just not be able to do before. I can take a walk, work out in the back yard, do yoga or <strong>work on projects!</strong></li><li>Less disruption - kinda obvious and a double-edged sword, as I benefit from some degree of diversion. Nonetheless, I can more predictably get stuff done now that I have more control over my physical workspace.</li><li>Ergonomics...okay, here&apos;s the deal:</li></ul><p>I <strong>suck</strong> at this! For most of the pandemic, I have been typing away on my tiny 13 inch laptop. I&apos;ve done some great work that i&apos;m proud of, but DAMN! Particularly without my regular gym visits, my posture has not responded well to this.<br>Finally I decided enough was enough and DID something about it - I bought a<br><a href="https://www.amazon.com/gp/product/B07YGZ7C1K"><strong>Heckin&apos; Big Monitor</strong></a><strong>.</strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2021/02/monitor.png" class="kg-image" alt="Window Management in the age of Covid-19" loading="lazy"><figcaption>SO BIG :O</figcaption></figure><h2 id="yeah-you-ve-got-a-big-monitor-so-what">Yeah you&apos;ve got a big monitor; so what?</h2><p>So, many people in my line of work have giant monitors, multiple monitors, curved monitors etc, so this might not seem world-breaking. But while I&apos;ve typically had a minimum of 2 monitors at work, I just haven&apos;t ever really given this kind of thing a second thought at home. I&apos;ve stuck to the <strong>absolute</strong> basics. I&apos;ve really refused to engage with the question of computer ergonomics at home. Call it ADHD, laziness or penny-pinching, I&apos;d just honestly rather think about and spend money on something else.<br>So this is a <strong>BIG DEAL</strong> for me.</p><p>The time for looking the other way is over; as a 6&apos;4 sciatica-prone hypermobile person, I have to take this stuff seriously.</p><h2 id="how-do-i-use-this-thing">How do I use this thing?</h2><p>So how do I make good use of this eyewatering investment?<br>I don&apos;t <em>need</em> a 34&quot; text editor or a 34&quot; terminal or 34&quot; anything most of the time, so I want to be able to have multiple things on screen at once. With multiple smaller monitors, you can drag/snap windows between the monitors as they both provide a place for a window to maximize to. Things just work; it&apos;s intuitive, for user and computer program alike.</p><p>A now-commonplace feature in window managers (even Windows 10) is being able to snap a window to half of the screen, or even a quarter, by dragging the window to that side/corner. You can do this with all your windows and boom - you have something like the intuitive flexibility of multiple monitors, but with one monitor. This is pretty great and makes having a giant monitor a whole lot more useful.</p><p>Still, it needs to be better though. Moving things around like this feels clunky, and there&apos;s no elegant way to take minimized/hidden things and move them to a given part of the screen. I don&apos;t want a window limit and I don&apos;t want fixed proportions the window can have; it&apos;s so much better than nothing, but it&apos;s not enough.</p><p>Long ago I used <a href="https://awesomewm.org/">AwesomeWM</a>. Awesome is a tiling window manager - its whole deal is breaking the screen up into separate panels which each have one thing in them. I don&apos;t remember Awesome very well, but I wanted that kind of thing. My manager strongly suggested another popular tiling window manager - <a href="https://i3wm.org/">i3wm</a>, but half way through learning the key combinations, I lost the will grind through what was mostly in my head already...</p><h2 id="emacs-to-the-rescue-">Emacs to the rescue!</h2><p>I use Emacs! Emacs has all the tiling things. Things which I spent a long time learning and am reasonably comfortable with. I didn&apos;t want to do all that hard work again, and I spend a lot of time in Emacs anyway.<br>I remembered a project <a href="https://github.com/ch11ng/exwm">EXWM</a>, which makes Emacs a window manager. Basically Emacs plugs into Xorg like any other WM and when a program wants to make a window, emacs makes a buffer for it and there it is. It can be moved around, hidden, whatever, just like any regular Emacs buffer. I tried it long ago, before I was all that familiar with Emacs, and remembered it not working very well. I don&apos;t know if that was really true or it was just my inexperience. But now, about a month in, I have to say it&apos;s working out pretty well.</p><h2 id="things-to-take-care-of">Things to take care of</h2><p>So it turns out there&apos;s a bit more to a typical desktop environment than a window manager. </p><h3 id="network-management">Network Management</h3><p>While the decisions about what to connect to and other such things are managed by the aptly-named NetworkManager daemon, you need a frontend to control it. Something to give you a list of available wireless networks and let you select one. For most of my Linux usership, this has taken the form of &apos;nm-applet&apos;. This is a gnome applet that you can right click and basically gives you access to all that stuff. Unless I want a gnome-panel in my Emacs, there&apos;s no way I can get nm-applet back. So I googled around and found <a href="https://elpa.gnu.org/packages/enwc.html">enwc</a> - an Emacs-based frontend for NetworkManager. It&apos;s not too big and clever - it just gives you a list of wifi networks and lets you hit enter to connect to them. Seems to work, though as far as I can tell, doesn&apos;t offer any configuration. For that, i&apos;ll have to use the &apos;nmcli&apos; command line tool, which is a rare enough occurrence that I think it&apos;s okay.</p><figure class="kg-card kg-code-card"><pre><code class="language-Emacs Lisp">(require &apos;enwc)
(setq enwc-default-backend &apos;nm)
(condition-case nil
    (enwc)
  (error nil))</code></pre><figcaption>enwc</figcaption></figure><h3 id="audio">Audio</h3><p>When you hit Volume up, Volume down or Mute on your keyboard <em>something</em> has to be listening for that, and know what to do. I googled around and found the <a href="https://github.com/flexibeast/pulseaudio-control">pulseaudio-control</a> package, which provides a means for telling Pulseaudio to do those things from Emacs.</p><figure class="kg-card kg-code-card"><pre><code class="language-Emacs Lisp">; Tell EXWM to send these keys to Emacs
(dolist (k &apos;(XF86AudioLowerVolume
             XF86AudioRaiseVolume
             XF86AudioMute))
  (pushnew k exwm-input-prefix-keys))

; Setup pulseaudio-control&apos;s &quot;C-/&quot; keybinding 
(require &apos;pulseaudio-control)
(pulseaudio-control-default-keybindings)

; Bind the &apos;media keys&apos; to relevant pulseaudio-control functions
(global-set-key (kbd &quot;&lt;XF86AudioRaiseVolume&gt;&quot;) &apos;pulseaudio-control-increase-volume)
(global-set-key (kbd &quot;&lt;XF86AudioLowerVolume&gt;&quot;) &apos;pulseaudio-control-decrease-volume)
(global-set-key (kbd &quot;&lt;XF86AudioMute&gt;&quot;) &apos;pulseaudio-control-toggle-current-sink-mute)</code></pre><figcaption>pulseaudio-control</figcaption></figure><p>The first block is needed because if an X window is active in EXWM, it will send these keys to that window. Most applications will not know what to do with these. So adding these to the <code>exwm-input-prefix-keys</code> list means that EXWM will intercept these and let Emacs handle them directly, with the bindings I set up afterward. Simples!</p><h3 id="backlight-stuff">Backlight stuff</h3><p>Sigh, this was a little annoying to get right. I ended up writing a helper program to do the talking-to-sysfs part of it for me. Seriously rough stuff:</p><pre><code class="language-C">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;

#define BL_PATH &quot;/sys/class/backlight/intel_backlight/brightness&quot;

int main(int argc, char **argv)
{
    if(argc == 1)
    {
        int fd = open(BL_PATH, O_RDONLY);

        char buff[10];
        int chars = read(fd, buff, 10);
        buff[chars-1] = &apos;\0&apos;;
        puts(buff);
    }
    else
    {
        int value = atol(argv[1]);
        char buff[10];
        int s = snprintf(buff, 10, &quot;%d\n&quot;, value);
        buff[9] = &apos;\0&apos;;

        int fd = open(BL_PATH, O_WRONLY);
        write(fd, buff, s);
    }

    return 0;
}</code></pre><p>I built this, and made it setuid root so it could write to the &apos;brightness&apos; file.<br>Now for the second piece:</p><pre><code class="language-Emacs Lisp">(defvar backlight-level 4000)
(defconst backlight-step 500)
(defconst backlight-max 7000)

(defun backlight-fn (value)
  (*
   (expt (/ backlight-level (float backlight-max)) 3)
   backlight-max))

(defun backlight-set ()
  (start-process &quot;backlight-set&quot; nil &quot;set_backlight&quot;
                 (format &quot;%d&quot; (backlight-fn backlight-level)))
  (message (format &quot;Backlight: %d/%d&quot; (backlight-fn backlight-level) backlight-max)))


(defun backlight-inc () (interactive)
  (setq backlight-level (min backlight-max (+ backlight-level backlight-step)))
  (backlight-set))

(defun backlight-dec () (interactive)
  (setq backlight-level (max 0 (- backlight-level backlight-step)))
  (backlight-set))

(global-set-key (kbd &quot;&lt;XF86MonBrightnessUp&gt;&quot;) &apos;backlight-inc)
(global-set-key (kbd &quot;&lt;XF86MonBrightnessDown&gt;&quot;) &apos;backlight-dec)</code></pre><p>PHEW! What&apos;s going on here is I define <code>backlight-set</code>, which calls my &apos;set_backlight&apos; program above, passing the value of <code>backlight-level</code> to it. Then I define <code>backlight-inc</code> and <code>backlight-dec</code> to add/subtract this level before calling <code>backlight-set</code>. Finally, I add keybindings for it (I need to add these keys to the <code>exwm-input-prefix-keys</code> list too). <code>backlight-fn</code> is also there to give me a nonlinear curve to my backlight setting. It works without this but is less useful - there&apos;s a lot more visible difference between levels 1000-1500, and 6500-7000. So this corrects for that and an exponent of 3 feels about right.</p><h3 id="time-date-battery">Time, Date, Battery</h3><p>It took me a couple of days to realise the time, date and battery level weren&apos;t anywhere to be seen! Fortunately, Emacs has something for this:</p><pre><code class="language-Emacs Lisp">(setq display-time-day-and-date t)
(setq display-time-default-load-average nil)
(display-time-mode)

(setq battery-mode-line-format &quot; [ &#x1F50B; %p%% ]&quot;)
(setq battery-update-interval 5)
(display-battery-mode)</code></pre><p>Pretty self-explanatory; shows time, date and battery in mode line. Works fine.</p><h3 id="window-layouts">Window Layouts</h3><p>Not a requirement, but a lot more useful if you have it:</p><pre><code class="language-Emacs Lisp">(winner-mode)</code></pre><p>When you use Emacs for everything, it&apos;s easy to accidentally <code>C-x 1</code> all of your other windows away, which can be frustrating. With <code>winner-mode</code>, you can immediately get the previous layout back with a <code>C-c &lt;left&gt;</code>. This is just great and desktop environments need this in general.</p><p>Also, I like to use <code>ace-window</code> , which is a more intuitive way to jump between windows than regular <code>C-x o</code>, which doesn&apos;t behave very predictably when dealing with more than 2 open ones. It does this by showing a character in the corner of each window, which you can then press to jump to that window. Pretty great...except it doesn&apos;t work for EXWM windows. EXWM covers up/doesn&apos;t have text area for this character to be shown in (i&apos;m no Emacs expert so maybe there is an easy fix to this), so I have switched away to using <code>winum-mode</code> . This simply puts a number in the modeline of each window, and lets you jump between them via <code>C-x w &lt;window number&gt;</code> .</p><h3 id="vpn">VPN</h3><p>I use a corporate VPN for certain things, so I need a way to switch that on and off. I was pleasantly surprised to learn that NetworkManager handles all of this for me - I just wrote some commands to flip the VPN on and off:</p><pre><code class="language-Emacs Lisp">(defun vpn-start () (interactive)
       (shell-command &quot;nmcli c up VPN&quot;))

(defun vpn-stop () (interactive)
       (shell-command &quot;nmcli c down VPN&quot;))</code></pre><p></p><h2 id="final-words">Final Words</h2><p>There are still some nagging issues, like how I haven&apos;t got monitor hotplugging working yet. It&apos;s a bit of an edge case, as I spend the vast majority of my time just using my big monitor, but it&apos;d be good to get it right. There&apos;s also some weirdness around audio sinks appearing/disappearing as my monitor is plugged in/out, sometimes requiring me to open a shell, type <code>cinnamon-settings sound</code> and click around like some n00b to get things straight.</p><p>But it&apos;s pretty good and I strongly recommend giving EXWM a shot to anyone who seriously uses Emacs. It&apos;s a surprisingly low-friction experience and especially useful if you have a big monitor!</p>]]></content:encoded></item><item><title><![CDATA[Fun with E-ink]]></title><description><![CDATA[<p>Having recently completed a project using the excellent <a href="https://en.wikipedia.org/wiki/ESP32">ESP-32</a> microcontroller, I wanted something new to work on.<br><br>After spotting a <a href="https://www.amazon.com/gp/product/B07ZVK2YQV">nice e-ink display</a> on Amazon, I decided it was time to play.</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2020/08/image-3.png" class="kg-image" alt loading="lazy"></figure><p>Helpfully, Amazon also suggested a <a href="https://www.amazon.com/dp/B07LH5L25R">&quot;Universal&quot; e-ink driver board</a> with a built in ESP-32:</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2020/08/image-7.png" class="kg-image" alt loading="lazy"></figure><p>At this</p>]]></description><link>https://routevegetable.com/eink-1/</link><guid isPermaLink="false">5f49c850480a1d55ed11d2b7</guid><category><![CDATA[Electronics]]></category><category><![CDATA[ESP32]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Sat, 29 Aug 2020 20:25:40 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2021/02/image-3.png" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2021/02/image-3.png" alt="Fun with E-ink"><p>Having recently completed a project using the excellent <a href="https://en.wikipedia.org/wiki/ESP32">ESP-32</a> microcontroller, I wanted something new to work on.<br><br>After spotting a <a href="https://www.amazon.com/gp/product/B07ZVK2YQV">nice e-ink display</a> on Amazon, I decided it was time to play.</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2020/08/image-3.png" class="kg-image" alt="Fun with E-ink" loading="lazy"></figure><p>Helpfully, Amazon also suggested a <a href="https://www.amazon.com/dp/B07LH5L25R">&quot;Universal&quot; e-ink driver board</a> with a built in ESP-32:</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2020/08/image-7.png" class="kg-image" alt="Fun with E-ink" loading="lazy"></figure><p>At this point, I wondered if this project would be too easy; I was somewhat mistaken...</p><p>The FFC on the display has 20 pins; the receptacle on the driver board has 24, so immediately I see i&apos;m going to have to do some work. Looking into the <a href="https://www.waveshare.com/w/upload/8/80/E-Paper_ESP32_Driver_Board_Schematic.pdf">schematic for the driver board</a> and what <a href="https://www.plasticlogic.com/helpdownloads/documentationlibrary/#1519714440391-56affa29-5f27">documentation</a> I could find for the display, these do not connect in any trivial way, though the signals seem to be somewhat comparable.</p><p>I&apos;ve so far been unable to find a technical reference manual for the relevant EPSON s1d13541 display controller, but I found some <a href="https://github.com/plasticlogic/pl-mcu-sd-card/tree/v11/_Documentation">documentation from a plasticlogic github repo</a> which explains a good amount around how e-ink displays actually work. I&apos;ve never worked with e-ink displays before and it turns out they aren&apos;t completely trivial.</p><p>Some noteworthy details I didn&apos;t appreciate:</p><ul><li>You need to generate relatively high voltages (the driver board handles this).</li><li>Switching pixels on and off requires factory-generated/calibrated &apos;waveform&apos; data to be fed into the display&apos;s controller at startup.</li><li>This and other such factory-established parameters are stored in an I2C memory which is also stuck to the display in this case.</li><li>The display-&gt;host processor interface is SPI, so the memory must be accessed <em>via </em>the display controller&apos;s SPI-I2C bridge functionality.</li></ul><p>Finally, I found that the code for the PlasticLogic eval kits is <a href="https://github.com/plasticlogic/pl-mcu-epd">available in a github repo!</a><br>This code is nicely structured and looks relatively easy to port to ESP32. It takes care of basically everything and comes with everything you need, even example applications to exercise the screen!</p><p>I&apos;m currently waiting for some FFC breakout boards to arrive; things are pretty hectic at the moment and I have multiple projects going on elsewhere in my life which cannot be deferred. Hopefully i&apos;ll get some time together soon to port some of the demo code to ESP32!</p>]]></content:encoded></item><item><title><![CDATA[Minecraft web server]]></title><description><![CDATA[<p>So I recently set up my minecraft server after a very long hiatus; with the shelter in place not ending any time soon, the conditions are surely perfect to get back into this :)</p><p>Some things seem to have changed since 2015 or whenever I last properly played Minecraft. My previous</p>]]></description><link>https://routevegetable.com/minecraft/</link><guid isPermaLink="false">5eca88e5480a1d55ed11d1d3</guid><category><![CDATA[Minecraft]]></category><category><![CDATA[Linux]]></category><category><![CDATA[UNIX]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Sun, 24 May 2020 16:08:08 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2021/02/2020-05-24_08.16.28-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2021/02/2020-05-24_08.16.28-1.png" alt="Minecraft web server"><p>So I recently set up my minecraft server after a very long hiatus; with the shelter in place not ending any time soon, the conditions are surely perfect to get back into this :)</p><p>Some things seem to have changed since 2015 or whenever I last properly played Minecraft. My previous setup involved the <a href="https://www.feed-the-beast.com/">FTB</a> launcher and the Yogcraft modpack, which included a bunch of silliness including ComputerCraft, BuildCraft and IndustrialCraft. Here&apos;s a <a href="https://www.youtube.com/redirect?v=YZHk0ZUdDvw&amp;event=video_description&amp;q=https%3A%2F%2Fgist.github.com%2Froutevegetable%2F247fa5b105a70c5cdf5c0bb835bcd99e&amp;redir_token=TA3BU9yB3_h--Ke6cO8xdNKuybV8MTU5MDQxODU2N0AxNTkwMzMyMTY3">nugget</a> I found from that time:</p><figure class="kg-card kg-embed-card"><iframe width="480" height="270" src="https://www.youtube.com/embed/YZHk0ZUdDvw?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><p></p><h2 id="you-said-something-about-a-web-server">You said something about a web server?</h2><p>Yeah, so I have a bee in my bonnet - I want a &apos;webserver&apos; in minecraft-land that I can access from the outside world. For no particular reason beyond figuring out if it&apos;s reliably doable and what kind of &quot;horrible stuff&quot; is required to make it happen.</p><h2 id="parts">Parts</h2><p>I&apos;m using the FTB Revelation modpack because frankly, it was the first one on the FTB launcher and Yogcraft isn&apos;t there anymore. I&apos;m also going to be using creative mode and start with a file in a computer that can be served statically. I remember that computer files used to live in a directory that could be read from outside minecraft; hopefully this is still the case, as it will probably make this a whole lot easier. Here it is:</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2020/05/2020-05-24_08.16.28-1.png" width="960" height="540" loading="lazy" alt="Minecraft web server" srcset="https://routevegetable.com/content/images/size/w600/2020/05/2020-05-24_08.16.28-1.png 600w, https://routevegetable.com/content/images/2020/05/2020-05-24_08.16.28-1.png 960w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2020/05/2020-05-24_08.24.41.png" width="960" height="540" loading="lazy" alt="Minecraft web server" srcset="https://routevegetable.com/content/images/size/w600/2020/05/2020-05-24_08.24.41.png 600w, https://routevegetable.com/content/images/2020/05/2020-05-24_08.24.41.png 960w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2020/05/2020-05-24_08.24.59.png" width="960" height="540" loading="lazy" alt="Minecraft web server" srcset="https://routevegetable.com/content/images/size/w600/2020/05/2020-05-24_08.24.59.png 600w, https://routevegetable.com/content/images/2020/05/2020-05-24_08.24.59.png 960w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>I made a new file with some known content; let&apos;s have a poke around the minecraft server directory and try to find it...</p><pre><code>lmarshall@tuvok:~/minecraft/world/computer$ tree
.
&#x251C;&#x2500;&#x2500; 0
&#x2502;&#xA0;&#xA0; &#x2514;&#x2500;&#x2500; myfile.txt
&#x2514;&#x2500;&#x2500; lastid.txt

1 directory, 2 files
lmarshall@tuvok:~/minecraft/world/computer$ cat 0/myfile.txt 
TESTFILE</code></pre><p>Well that was easy! Guess this is going to be a short one :)</p><p>Lets set up nginx</p><figure class="kg-card kg-code-card"><pre><code>lmarshall@tuvok:~/minecraft/world/computer$ apt install nginx
...
lmarshall@tuvok:~/minecraft/world/computer$ sudo nano /etc/nginx/sites-enabled/default</code></pre><figcaption>Install nginx and configure it</figcaption></figure><figure class="kg-card kg-code-card"><pre><code>server { 
        listen 80;
        listen [::]:80;

        server_name mc.routevegetable.com;

        root /home/lmarshall/minecraft/world/computer/0/www;
        index index.html;

        location / {
                try_files $uri $uri/ =404;
        }
}</code></pre><figcaption>Virtual host configuration for &apos;mc.routevegetable.com&apos;</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://routevegetable.com/content/images/2020/05/image-5.png" class="kg-image" alt="Minecraft web server" loading="lazy"><figcaption>Added the port forwarding for nginx to my router</figcaption></figure><p>Annoyingly, I get the router configuration page when I now try to go to http://mc.routevegetable.com in my browser - looks like my router is trying to be helpful. Hmm; gonna have a quick look around for a switch that controls that in the router config...</p><p>Ah-hah! I can add a DNS record for my LAN only:</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2020/05/image-6.png" class="kg-image" alt="Minecraft web server" loading="lazy"></figure><p>Now a re-connection later to flush my local DNS cache and...</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2020/05/2020-05-24_08.53.57.png" width="960" height="540" loading="lazy" alt="Minecraft web server" srcset="https://routevegetable.com/content/images/size/w600/2020/05/2020-05-24_08.53.57.png 600w, https://routevegetable.com/content/images/2020/05/2020-05-24_08.53.57.png 960w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2020/05/2020-05-24_08.54.21.png" width="960" height="540" loading="lazy" alt="Minecraft web server" srcset="https://routevegetable.com/content/images/size/w600/2020/05/2020-05-24_08.54.21.png 600w, https://routevegetable.com/content/images/2020/05/2020-05-24_08.54.21.png 960w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2020/05/Screenshot-from-2020-05-24-08-57-33.png" width="1428" height="494" loading="lazy" alt="Minecraft web server" srcset="https://routevegetable.com/content/images/size/w600/2020/05/Screenshot-from-2020-05-24-08-57-33.png 600w, https://routevegetable.com/content/images/size/w1000/2020/05/Screenshot-from-2020-05-24-08-57-33.png 1000w, https://routevegetable.com/content/images/2020/05/Screenshot-from-2020-05-24-08-57-33.png 1428w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Woot!</figcaption></figure><p>So, there are a couple of things that are unsatisfying about this:</p><ul><li>We hardcoded the path <code>/home/lmarshall/minecraft/world/computer/0/www</code> into the nginx config, meaning that this specific computer is now special, and we can&apos;t make another web server without messing with the nginx config.</li><li>It would be pretty awesome to be able to get some real interaction going, so you can trigger programs you write in minecraft. Like a CGI bin, but sandboxed within minecraft.</li></ul><p>I think that&apos;s enough silliness for this morning.</p>]]></content:encoded></item><item><title><![CDATA[Toilet tank sink]]></title><description><![CDATA[<p>Recently my place got a new bathroom installed; it&apos;s been lacking a sink however, so use has been a bit limited.</p><p>Rather than plumbing + affixing a new sink, we heard about these <a href="https://www.amazon.com/SinkPositive-Touch-Free-Saving-Adjustable-Retrofit/dp/B00NOCGC3K">weird sink things that mount on the toilet tank</a>. For the very tiny bathroom that this</p>]]></description><link>https://routevegetable.com/some-diy/</link><guid isPermaLink="false">5ec848dd480a1d55ed11d17c</guid><category><![CDATA[DIY]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Fri, 22 May 2020 22:08:23 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2021/02/Capture-3.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2021/02/Capture-3.jpeg" alt="Toilet tank sink"><p>Recently my place got a new bathroom installed; it&apos;s been lacking a sink however, so use has been a bit limited.</p><p>Rather than plumbing + affixing a new sink, we heard about these <a href="https://www.amazon.com/SinkPositive-Touch-Free-Saving-Adjustable-Retrofit/dp/B00NOCGC3K">weird sink things that mount on the toilet tank</a>. For the very tiny bathroom that this is, it seemed like a perfect solution.</p><p>Got it ordered, it arrived and lo and behold, it didn&apos;t fit! The top of the toilet tank was too slim and the sink just kinda rocked around:</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2020/05/image.png" class="kg-image" alt="Toilet tank sink" loading="lazy"></figure><p>Fortunately I had some wood lying around, so I set about it with a jigsaw:</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2020/05/99364398_246808223060568_3493087418549010432_n-1.jpg" width="1536" height="2048" loading="lazy" alt="Toilet tank sink" srcset="https://routevegetable.com/content/images/size/w600/2020/05/99364398_246808223060568_3493087418549010432_n-1.jpg 600w, https://routevegetable.com/content/images/size/w1000/2020/05/99364398_246808223060568_3493087418549010432_n-1.jpg 1000w, https://routevegetable.com/content/images/2020/05/99364398_246808223060568_3493087418549010432_n-1.jpg 1536w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://routevegetable.com/content/images/2020/05/98198398_2618848938387470_3516883770751844352_n.jpg" width="1536" height="2048" loading="lazy" alt="Toilet tank sink" srcset="https://routevegetable.com/content/images/size/w600/2020/05/98198398_2618848938387470_3516883770751844352_n.jpg 600w, https://routevegetable.com/content/images/size/w1000/2020/05/98198398_2618848938387470_3516883770751844352_n.jpg 1000w, https://routevegetable.com/content/images/2020/05/98198398_2618848938387470_3516883770751844352_n.jpg 1536w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>Success!</p><figure class="kg-card kg-image-card"><img src="https://routevegetable.com/content/images/2020/05/Capture-3.JPG" class="kg-image" alt="Toilet tank sink" loading="lazy"></figure><p></p><p>Finally, turns out nail polish remover gets errant sharpie marker off of plastic; who knew?</p>]]></content:encoded></item><item><title><![CDATA[Coming out email!]]></title><description><![CDATA[<p>Today I decided to send an email to my colleagues about my non-binary gender identity. I&apos;ll write more later, but for now, here it is:</p><p>Hi all, I wondered what would constitute a good mailing list to send this to. To be honest, I am still not sure</p>]]></description><link>https://routevegetable.com/coming-out-email/</link><guid isPermaLink="false">5ec2df7e480a1d55ed11d145</guid><category><![CDATA[Personal]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Mon, 18 May 2020 19:22:39 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2022/01/300px-Nonbinary_flag.svg.png" medium="image"/><content:encoded><![CDATA[<img src="https://routevegetable.com/content/images/2022/01/300px-Nonbinary_flag.svg.png" alt="Coming out email!"><p>Today I decided to send an email to my colleagues about my non-binary gender identity. I&apos;ll write more later, but for now, here it is:</p><p>Hi all, I wondered what would constitute a good mailing list to send this to. To be honest, I am still not sure but I figured what the hell.<br>I want to bring to light a detail that&apos;s become an increasingly important part of my life and identity over the last few years. After much deliberation, soul searching and consulting with various folks - I&apos;d like to broadcast my status as a non-binary individual.</p><p><strong>&#x1F4BC; Executive summary &#x1F4BC;</strong></p><ul><li>I don&apos;t identify strictly with masculine or feminine gender.</li><li>I greatly prefer the singular gender-neutral pronouns &quot;they/them/their&quot; for talking about myself</li></ul><p>Below is a sort of blog post-style collection of words; I am sure there are many people in &lt;Company Name&gt; who don&apos;t require the whole thing, but it seems to be the easiest format for me to cover everything I want to - this stuff&apos;s hard!</p><p></p><p><strong>Wat?</strong></p><p>Non-binary gender identity refers to how someone, anyone and anybody, may view themselves as neither strictly masculine, nor strictly feminine. What does it mean to be masculine, feminine or neither or both? What even is gender? &#x1F937;<br>I don&apos;t claim have a universal answer that everyone will agree to; I can only try to articulate my experience, that is: I experience gender as a social construct and I find that where behaviour and internal experience doesn&apos;t &quot;match&quot; gender-based expectations, this generates friction and/or shame, and is a bit rubbish. I want to distance this from being a biological conversation of any sort; it&apos;s a common tangent which misses the point and frankly, work is not my preferred venue for such topics ;-) .</p><p></p><p><strong>Why are you telling us this</strong></p><p>This is a difficult one and, as little as anyone may understand exactly why being correctly identified matters, it does appear to matter to humans and I appear to be mostly a human ;-) .<br>In many ways I would *love* for this to be a non issue for me; it would make my life easier! But I want to be a decent, functional blend of realistic, authentic and pragmatic.The experience of fitting in with masculine norms and/or simply tolerating having them applied to me consumes a non-zero amount of my mental + emotional resources; these are resources that I&apos;d rather spend on other things, like &lt;Awful hateful technical task I will have to do soon&gt;. I am honestly tired of holding all of this on my own and would like to give others the opportunity to help me out, even simply reading this and validating my experience makes more of a difference to me than one might expect.</p><p></p><p><strong>On Pronouns</strong></p><p>If you&apos;ve been hanging around the blogosphere for the last ten years, you may have noticed a rise in people who choose to go public with such an identity; perhaps you&apos;ve noticed people using gender neutral pronouns they/them/their as singular when referring to such individuals in the third person.<br>It&apos;s not perfect but for me, this is the best that English has to offer and I prefer to be referred to in this way. &#xA0;This facet is one that some find quite contentious and difficult to get to grips with; there is no pronoun-police and nobody is forcing anyone to do anything; please just know that this is my preference.</p><p></p><p><strong>Final Word</strong></p><p>Identity is a complex subject about which I am absolutely no expert, and gender is but one axis; there are plenty of other important axes including sexuality, race, ethnicity; these are systems of classifying humans which are baked into the collective consciousness, codified into law; these things form the foundations, floors, walls, ceilings, windows and chimney-pots of our society. They are often invisible and not considered, but everything we do is built around them. As such, many people experience issues with identity and many never speak about it; perhaps it isn&apos;t emotionally, professionally or even physically safe to do so. I believe that &lt;Company Name&gt; is a safe place for me to share this message, and while nobody has to come out and not everybody can, I want to offer myself as an ally and a cheerleader for anyone here who experiences an atypical gender identity.</p><p>Thanks for reading, y&apos;all. If anyone has respectful/sensitive questions, I&apos;d like to try to engage with them.</p>]]></content:encoded></item><item><title><![CDATA[Linux as the next application framework?]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Applications are generally built out of libraries which provide generic functionality. These libraries need to be flexible enough to play their necessary parts in your application, but not so generic that doing so requires excessive amounts of plumbing with complex abstractions.<br>
It is this last point which contributes chiefly to</p>]]></description><link>https://routevegetable.com/linux-as-the-next-application-framework/</link><guid isPermaLink="false">5ea505623f8dab4b908ccb10</guid><category><![CDATA[Linux]]></category><category><![CDATA[UNIX]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Sat, 25 Feb 2017 23:56:13 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Applications are generally built out of libraries which provide generic functionality. These libraries need to be flexible enough to play their necessary parts in your application, but not so generic that doing so requires excessive amounts of plumbing with complex abstractions.<br>
It is this last point which contributes chiefly to the disk/memory &apos;bloat&apos; of modern applications, rather than excessive user-facing functionality.</p>
<p>Developing abstractions which strike this balance is tricky, and perhaps a social/psychological issue as much as a technical one. Software which fits the bill needs to be able to expand and evolve as users demand more and different things from it.<br>
I personally think it&apos;s worse for the software to be simple yet rigid, rather than complex yet comprehensive, but only slightly - both are undesirable.</p>
<p>Linux actually provides lots of useful abstractions to build software with such as processes, threads and network sockets, firewall rules, files, mountpoints...<br>
But even if the interactions of these entities with the outside world are quite simple to explain and reason about, they can be highly complex from the application programmer and system integrator&apos;s point of view.</p>
<h2 id="thecentralisationproblem">The Centralisation Problem</h2>
<p>Something which contributes significantly to this complexity is the centralisation of resources in Linux.</p>
<p>Taking the filesystem as an example, a typical Linux user cannot know ahead of time what files or directories a given program is going to need access to. There&apos;s no limit to the scope of what an unknown program may want to do and no way to manage it with ignorance.<br>
The developer of an application is similarly in the dark about what they may or may not be able to do in a given target environment.</p>
<p>There is the <a href="https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard">FHS</a> and similar standards which give guidelines and are generally adhered to about what&apos;s &apos;polite&apos; for an application to do and what&apos;s mandatory for an environment to provide.<br>
Unfortunately, there are still questions without good answers until you have the system in front of you, such as:</p>
<ul>
<li>Is /usr read-only?</li>
<li>Can I make a directory under /tmp and mount things to it?</li>
<li>Are extended attributes available?</li>
<li>Can I open /dev/ttyACM0?</li>
<li>Is usbfs mounted somewhere I can use it?</li>
<li>What local address and port should I bind to?</li>
</ul>
<p>The result is that in order to be robust, applications must do a multitude of checks in their installers and binaries to figure out how the guest system is configured and then, hopefully, &apos;reach an agreement&apos;.<br>
Complimentary to checks is the use of hefty configuration files or environment variables, where many things which are irrelevant to the actual usage of the application must be explicitly specified to make sure the program can do whatever it wants to do, such as what user apache should run as, or where wpa-supplicant should put its control socket.</p>
<h2 id="theresult">The Result</h2>
<p>So to make things easier for both developers and users, functionality present in Linux is duplicated in the application, or libraries/servers the application depends on. Some examples I can think of:</p>
<ul>
<li>App lifecycle management (vs xinet.d/systemd)</li>
<li>Userspace packet-processing/load-balancing (vs iptables)</li>
<li>Document storage in servers (vs the filesystem).</li>
</ul>
<p>Now, i&apos;m not saying that Linux&apos;s support for these kinds of things is totally easy to use or that it&apos;s always flexible enough for any given application to leverage. I think that where the contrary is true however, it is at least partially due to the lack of usage that these features see, thanks to the above centralisation problem - if nobody tries to use it, nobody complains and nothing improves.</p>
<p>So we find ourselves where we are today, effectively giving up on native services, moving the problem of compatibility and conflict avoidance to new servers and frameworks to ensure that a given application will &apos;just work&apos;.<br>
I call it moving the problem, because these replacements for native services must of course be themselves configured by some poor soul - often the package maintainer - to play nicely with other things sitting directly on the system (including alternative replacements).</p>
<h2 id="asolution">A Solution?</h2>
<p>A way around the unfortunate situation outlined above where we can better leverage built in features of Linux and make application development and deployment easier, is the idea of the VM.</p>
<p>To package your application in a VM, you can start with a plain OS image, write a script to configure the environment exactly how you want it, add your own stuff and ship the VM image.</p>
<p>Though a VM may have lots of complexity inside it, the interface it presents to the outside world is indeed quite simple - one of storage volumes, network ports and some allocation of CPU time and memory - and entirely under the developer&apos;s control.</p>
<p>A user can deploy this application with peace of mind, with just a basic understanding of these high-level concepts and application documentation written <em>in those terms</em>.<br>
They don&apos;t have to treat the application like a special snowflake which must be started and stopped in a specific way (Power on/ACPI off), nor do they need to worry about whether an untrusted application must run as root, or whether it can access all the files it needs.</p>
<p>In short: VMs allow you to avoid conflicts over centralized resources, turning deployment into a relatively high-level activity.</p>
<p>So why aren&apos;t we all just using VMs for most things? Some reasons I can think of right now:</p>
<ul>
<li>Speed - VM needs to boot up</li>
<li>Resource requirements - you need a good chunk of memory and throughput can be impacted</li>
<li>Some modes of desirable interaction are hard to achieve, such as using X11 and exposing host directories to the guest</li>
<li>Difficulty of development - every time you change the source code, you can do one of the following undesirable things to test the result:</li>
<li>Rebuild and reboot the VM</li>
<li>Try to completely &apos;clean up&apos; and rerun your vm-customizing script</li>
<li>Install the application directly into your dev machine</li>
<li>Develop inside the VM</li>
</ul>
<p>It feels like some additional tooling could perhaps be used to bridge this gap...</p>
<h2 id="entercontainers">Enter Containers</h2>
<p>I think containers <em>are</em> supposed to be the solution to this; they&apos;re just like VMs, offering the decentralisation of resources, providing a high-level application view to the user whilst simultaneously resolving developer unknowns about the target environment.</p>
<p>A popular solution for containers at the moment is the use of Docker with Linux&apos;s relatively recent namespacing functionality. This provides a very performant alternative to VMs, with docker laying out the high-level view of a container in terms quite similar to those of a VM.<br>
It should be stated that alternative backends to docker exist which are based on VM technology, providing a far more easily securable form of isolation. Security is a whole other thing however, and here I am intentionally focusing on UX for developers and users.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Partition Feng Shui]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Finally got this working today.</p>
<p>Originally I had a Linux Mint installation on my home laptop, with a Windows 10 VM for the rare occasions when I needed to do something windows-only. I&apos;m not a gamer, and so there are few things I can&apos;t simply do</p>]]></description><link>https://routevegetable.com/partition-feng-shui/</link><guid isPermaLink="false">5ea505623f8dab4b908ccb0f</guid><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Tue, 10 Jan 2017 17:24:51 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Finally got this working today.</p>
<p>Originally I had a Linux Mint installation on my home laptop, with a Windows 10 VM for the rare occasions when I needed to do something windows-only. I&apos;m not a gamer, and so there are few things I can&apos;t simply do in a VM. One of the things, however, was watching programmes on the &quot;Now TV&quot; streaming service; it&apos;s based on Silverlight, and utilises HDCP to &apos;ensure&apos; you aren&apos;t recording the content.</p>
<p>My ultimate plan was to get the windows installation onto a separate partition, where GRUB could boot to it. It was in fact in a raw disk image, so I allocated some space in my partition table and used dd to copy the whole raw disk image to the new partition.<br>
Then it was a matter of using fdisk to update my partition table to point at the 2 partitions (&quot;Windows Boot Manager&quot; and &quot;System&quot;), rather than to the whole disk image.</p>
<p>Once this was done, I had a normal pair of NTFS partitions sitting on my disk. &quot;Almost there&quot;, I thought.</p>
<p>After running <code>update-grub2</code> and rebooting, I saw that a menu entry had indeed been generated for the windows partition.<br>
It looked fairly standard for booting a windows system from MSDOS disk, setting the root to the windows boot manaager partition and utilising grub&apos;s &quot;chainloader +1&quot; command to load and execute volume boot record.<br>
Upon running the entry, however, I just got a black screen with a flashing &apos;_&apos; character.</p>
<p>After googling around, it looks like chainloader +1 doesn&apos;t really work any more for booting windows; i had to use grub&apos;s &apos;ntldr&apos; module.<br>
This bypasses the VBR and knows how to run the &apos;bootmgr&apos; executable in the Boot Manager partition.</p>
<p>I added the following to /etc/grub.d/40_custom:</p>
<pre><code>menuentry &apos;Windows 10 (loader) (on /dev/sda2)&apos; {
        insmod part_msdos
        insmod ntfs
        insmod ntldr
        set root=&apos;hd0,msdos2&apos;
        ntldr /bootmgr
}
</code></pre>
<p>Finally, I booted up a VM with a windows 10 installation/recovery ISO, and with /dev/sda mapped to the first hard drive (this is a very risky thing to do and will quickly knacker your Linux filesystem if the guest VM is permitted to boot the host OS).</p>
<p>Inside the Windows 10 recovery environment, I used <a href="https://support.microsoft.com/en-gb/kb/927392">bootrec</a> to rebuild the BCD store, so it would reflect the new location of my windows system partition.</p>
<p>I haven&apos;t diddled with windows boot for quite a long time, and so this all took far longer than it feels like it should have done. It&apos;s all done now, though.</p>
<p>I know GPT is the future and better for various reasons, but this will do for now :)</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Corsa C Wet Carpet]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>A while back, I noticed the carpet in the driver&apos;s side of my 2001 Corsa C was wet. Pushing down on it would reveal a lot of water just sitting there, with a nasty, squelchy sound.</p>
<p>I spent a week trying to dry it out with hot air,</p>]]></description><link>https://routevegetable.com/corsa-c-wet-carpet/</link><guid isPermaLink="false">5ea505623f8dab4b908ccb0e</guid><category><![CDATA[DIY]]></category><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Sat, 22 Oct 2016 09:48:09 GMT</pubDate><media:content url="https://routevegetable.com/content/images/2021/02/seal.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://routevegetable.com/content/images/2021/02/seal.jpg" alt="Corsa C Wet Carpet"><p>A while back, I noticed the carpet in the driver&apos;s side of my 2001 Corsa C was wet. Pushing down on it would reveal a lot of water just sitting there, with a nasty, squelchy sound.</p>
<p>I spent a week trying to dry it out with hot air, to no avail. I then did some research and it turns out this is a <a href="http://carsandcode.blogspot.co.uk/2013/08/corsa-c-water-leak-fixes-drivers-carpet.html">common problem with no easy fix</a>.</p>
<p>The car itself was a steal at less than 900GBP with very little wrong with it, and has served me well for the last 6 months. I wasn&apos;t about to blow potentially more than half of that on labor to resolve this non-serious problem, so either I was going to fix it, or it wouldn&apos;t be fixed.</p>
<p>I&apos;m pretty inexperienced with car repair. Although I&apos;ve always known my way around a socket set and I&apos;ll confidently work with electricals, I still had a big real-world-experience gap. Nevertheless, I had the internet and some helpful colleagues, and I thought it worth a shot. I also found <a href="https://www.youtube.com/watch?v=ChzIbEmGfgU">this fantastic video</a> which shows pretty clearly what needs to be done.</p>
<h2 id="theproblem">The Problem</h2>
<p>Above the pedals, there is a panel in the chassis with a seal around it. Compost and other outside-crap builds up around it, trapping water and rotting the seal. After a decade or so, the seal fails and begins to let water directly into the carpet and soundproofing.</p>
<h2 id="removingthecarpet">Removing the carpet</h2>
<p>The carpet/soundproofing was completely saturated with water and needed to come out before it got too nasty. I set about doing this one weekend, also taking the opportunity to look at the panel and verify the source of the leak using a bucket of water.<br>
Removing the carpet was significantly harder than I had anticipated. The carpet is all in one chunk and needed to be cut out; that is, after various bits of plastic trim and the driver&apos;s seat had been removed.<br>
<img src="https://routevegetable.com/content/images/2016/10/removed.jpg" alt="Corsa C Wet Carpet" loading="lazy"></p>
<p><img src="https://routevegetable.com/content/images/2016/10/drying.jpg" alt="Corsa C Wet Carpet" loading="lazy"></p>
<p>I spent the next few weeks driving around with no carpet/soundproofing, as the chunks of carpet got drier. There were a few sessions of heavy rain, accompanied by puddles as expected.</p>
<h2 id="fixingit">Fixing it</h2>
<p>Last weekend, the weather was finally nice enough to permit the actual fix.<br>
First I had to remove the wipers, plastic panelling under the wipers &amp; wiper motor, detergent bottle and other bits of plastic:<br>
<img src="https://routevegetable.com/content/images/2016/10/parts.jpg" alt="Corsa C Wet Carpet" loading="lazy"><br>
The next step is to get the master cylinder out of the way. This isn&apos;t as simple as unbolting and pulling it away as the feed to the clutch cylinder comes out of the right-hand side of the reservoir, and the pipe has very little slack in it; see the spigot on the right:<br>
<img src="https://routevegetable.com/content/images/2016/10/spigot.jpg" alt="Corsa C Wet Carpet" loading="lazy"><br>
To detach this pipe without brake fluid going everywhere, I had to use a syringe to suck just enough fluid out of the reservoir that the level was below that of the spigot, but not so low as to expose the brake master cylinder inlets.<br>
After pulling off the clutch cylinder feed tube and unclipping the rigid hydraulic lines from the chassis where I could, I unbolted and pulled the master cylinder away:<br>
<img src="https://routevegetable.com/content/images/2016/10/cylinder.jpg" alt="Corsa C Wet Carpet" loading="lazy"></p>
<p>The problematic seal is now clearly visible around the black plate behind the brake servo(round black thing). That needed to come off, which was a bit more straightforward than the brake cylinder. This involves yanking the vacuum pipe out of the front of it, and jamming yourself under the pedals to undo a couple of bolts and remove the pin that attaches the brake pedal to the brake servo:<br>
<img src="https://routevegetable.com/content/images/2016/10/pedals.jpg" alt="Corsa C Wet Carpet" loading="lazy"><br>
To get to one of these bolts, I needed to remove the accelerator pedal; the hardest part of this was figuring out how to unplug it. The answer is to grab the red face on the side of the plug and pull it toward you; this magically pulls the plug upwards off of the pedal.</p>
<p>After removing the brake servo, you can see the whole seal which I painstakingly extracted with a knife/screwdriver. Here it is half-done:<br>
<img src="https://routevegetable.com/content/images/2016/10/dug.jpg" alt="Corsa C Wet Carpet" loading="lazy"><br>
This was oddly relaxing to do, and took most of an hour.<br>
After cleaning it up with soapy water and an old toothbrush, I resealed it with <a href="https://www.amazon.co.uk/Everbuild-PLUMBGCL-Plumbers-Gold-Cartridge/dp/B002SHA04Y">Plumbers Gold</a>:<br>
<img src="https://routevegetable.com/content/images/2016/10/seal.jpg" alt="Corsa C Wet Carpet" loading="lazy"><br>
It ended up a bit messy, particularly in the bottom-right corner which was quite hard to reach, but as far as I could tell it was well-sealed.</p>
<p>It was then just a matter of doing everything in reverse.</p>
<h2 id="puttingthecarpetback">Putting the carpet back</h2>
<p>I&apos;ve been driving around for a week without the carpet back in as I wanted to be sure it wasn&apos;t still leaking. We&apos;ve had a couple of sessions of rain with no puddles, so I&apos;m confident that it&apos;s done. It&apos;ll probably take an hour or two to get the carpet back in, either today or tomorrow.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Why I Love Testing]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Today, I was chatting with some coworkers over tea. We were talking about testing software, and I mentioned that I love testing. One coworker looked at me as if I were unhinged stating, &quot;but everybody hates testing&quot;. I realised that at some point in the last 2 years</p>]]></description><link>https://routevegetable.com/why-i-love-testing-2/</link><guid isPermaLink="false">5ea505623f8dab4b908ccb0d</guid><dc:creator><![CDATA[Lee Marshall]]></dc:creator><pubDate>Thu, 21 Jul 2016 20:56:34 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Today, I was chatting with some coworkers over tea. We were talking about testing software, and I mentioned that I love testing. One coworker looked at me as if I were unhinged stating, &quot;but everybody hates testing&quot;. I realised that at some point in the last 2 years I had completely changed the way I feel about testing.</p>
<p>As a Field Applications Engineer I build proof-of-concepts and demos, some of which can get quite comprehensive/complex and even evolve into part of the production system.<br>
Being part of the sales team, I&apos;m far less insulated from the customer&apos;s opinion than I have been in more typical, programming roles. I also have far more involvement in getting the specification together and helping the customer figure out what they want.</p>
<p>When what I produce is not working, I really, really want to know.<br>
But what do I mean by &apos;not working&apos;?</p>
<p>I don&apos;t mean that my code throws NPEs or segfaults, has race conditions, or posts your password to reddit.<br>
I don&apos;t mean that any single part of the product isn&apos;t functioning as such a part should, according to best practices, or even the specification that the customer provided.<br>
What I mean is that it&apos;s &apos;not working&apos; for the customer.</p>
<p>Quite often, the software may be doing exactly as the customer asked; this fact alone is unfortunately not all that important to the business.</p>
<p>So here are some reasons it might not be working for the customer:</p>
<ul>
<li>The customer is actually satisfied, but pretending to not be as a bargaining tactic - this isn&apos;t my problem</li>
<li>The code is actually broken</li>
<li>I&apos;ve misunderstood the requirements</li>
<li>There are communication problems between companies, perhaps the project management strategy needs some love</li>
<li>The customer has misunderstood their own requirements</li>
<li>The customer has changed their mind (scope creep)</li>
</ul>
<p>Out of these choices, only the first permits any kind of non-action.</p>
<p>In a typical programming role I found it&apos;s very easy fall into the pattern of defending a piece of work, even if it does something the customer doesn&apos;t like, or doesn&apos;t do everything the customer was expecting.<br>
One can say things like, &quot;it passes the unit tests&quot; or, &quot;it&apos;s written according to best practices&quot;. Perhaps, &quot;but that&apos;s what they asked for&quot;.<br>
These claims may be completely correct, and are sometimes even valuable as bargaining chips from a commercial point of view.<br>
But for an effective engineer, these things are an easy distraction from finishing off what you set out to do - to make something that someone else wants.<br>
The customer is disappointed and they want something different; that&apos;s the important point.</p>
<p>So when something gets passed back to you as not working, <em>even if the code is correct</em>:</p>
<ul>
<li>Try not to automatically argue</li>
<li>Forget about the code, <em>why</em> do they have a problem</li>
<li>Try to see what has happened and exactly what disagreement has occurred</li>
<li>Seek a resolution, obviously</li>
</ul>
<p>Of course for all the listening you can do and interest you can show, it can still be embarrassing and in some cases, commercially damaging to give the customer something which doesn&apos;t work for them.</p>
<p>That is where <strong>testing</strong> comes in! Testing is like a customer that you can upset as much as you want. They&apos;re like the &apos;compile&apos; button in your programming environment, except rather than looking for syntax and type errors, they can help you zero in on issues in the management of your project or the communication of the requirements.<br>
Issues which if unnoticed, can cause much bigger problems for the project than a lack of unit tests.</p>
<p>To make the most of testing:</p>
<ul>
<li>Ensure test engineers are educated about the customer&apos;s business, so they can better represent the customer</li>
<li>Empower test engineers to do more than just tick a &apos;verified&apos; box; use their unique perspective to help you work with the customer and deliver something they will actually want</li>
</ul>
<p>Disliking testing is like disliking the compiler because it gives you errors when you forget brackets.<br>
Most programmers have been there, but hopefully outgrow this way of thinking by the time they go to work.</p>
<p>You wouldn&apos;t want to send the customer something which might throw a runtime error as soon as they open it; why is it any more okay for it to throw the CustomerDisappointedException?<br>
Sure, it gets the job off of your desk and perhaps onto someone else&apos;s after a while, but if that&apos;s how you presently spend your 40 hours a week as a programmer, maybe you&apos;re in the wrong job.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>