<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>karstx</title>
    <subtitle>I make things and then write about them</subtitle>
    <link rel="self" type="application/atom+xml" href="https://karstx.net/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://karstx.net"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-16T00:00:00+00:00</updated>
    <id>https://karstx.net/atom.xml</id>
    <entry xml:lang="en">
        <title>Hacking the NuPhy Air60 keyboard: part 3</title>
        <published>2026-09-16T00:00:00+00:00</published>
        <updated>2026-09-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/nuphy-air60-part-3/"/>
        <id>https://karstx.net/nuphy-air60-part-3/</id>
        
        <content type="html" xml:base="https://karstx.net/nuphy-air60-part-3/">&lt;p&gt;It&#x27;s been a long time coming... so this one&#x27;s going to be a bigger one.&lt;&#x2F;p&gt;
&lt;p&gt;This is another update on the long-running project of putting my own firmware on a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nuphy.com&#x2F;products&#x2F;air60&quot;&gt;NuPhy Air60&lt;&#x2F;a&gt;. If you&#x27;re interested in the previous parts, they&#x27;re here: &lt;a href=&quot;&#x2F;nuphy-air60&quot;&gt;part 1&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;nuphy-air60-part-2&quot;&gt;part 2&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So what happened since? Quite a lot, honestly.&lt;&#x2F;p&gt;
&lt;!-- toc --&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;assembled-keyboard.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;assembled-keyboard.0dd5870c6585009b.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;assembled-keyboard.d686080528efa40f.jpg 2x&quot; alt=&quot;a NuPhy Air60 on a wooden desk, with blue and white keycaps, a yellow spacebar and a red enter key, sitting on a black printed base&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;my pimped out work-horse: NuPhy Air60 (v1)&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;timeline-so-far&quot;&gt;Timeline so far&lt;a class=&quot;zola-anchor&quot; href=&quot;#timeline-so-far&quot; aria-label=&quot;Anchor link for: timeline-so-far&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;April 2023&lt;&#x2F;strong&gt; - sinowealth-kb-tool gets its first release.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;December 2023&lt;&#x2F;strong&gt; - USB lands on top of the matrix scanning from October, so &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;smk&quot;&gt;SMK&lt;&#x2F;a&gt; works as an actual USB keyboard for the first time.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;2024 into 2025&lt;&#x2F;strong&gt; - a steady stream of new devices gets added to sinowealth-kb-tool, and it hits 1.0.0 in May 2025. SMK picks up wireless (over the BK3632) and NKRO around the turn of the year.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;January 2026&lt;&#x2F;strong&gt; - reverse engineering the remaining bits of the SinoLink, enough to build sinodude, my own programmer around an Arduino Nano.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;June 2026&lt;&#x2F;strong&gt; - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;hidra&quot;&gt;hidra&lt;&#x2F;a&gt; gets written, the browser flasher at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;smk.carlossless.io&quot;&gt;smk.carlossless.io&lt;&#x2F;a&gt; quietly goes live, and I start designing a new base for the keyboard in FreeCAD.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;July 2026&lt;&#x2F;strong&gt; - everything gets wired together. sinowealth-kb-tool becomes &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sinowisp&quot;&gt;sinowisp&lt;&#x2F;a&gt; and drops hidapi for hidra.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;August 2026&lt;&#x2F;strong&gt; - the LED effect engine, sleep and settings land in SMK, along with the split between the platform layer and keyboard policy.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;September 2026&lt;&#x2F;strong&gt; - ports onto more keyboards and more MCUs (the SH68F881 and SH68F89, a Genesis Thor 300 and a CIY X77), and, thanks to the multiple backends, sinowisp gets to the point where it can talk to every documented ISP bootloader on Windows, macOS and Linux.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Anyway, on to the actual stuff...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;smk-grew-up&quot;&gt;SMK grew up&lt;a class=&quot;zola-anchor&quot; href=&quot;#smk-grew-up&quot; aria-label=&quot;Anchor link for: smk-grew-up&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Part 2 of this series ended with a minimal firmware that booted, jumped back into the bootloader without bricking itself, and not a lot else. That scratchpad (it was called sh68f90a-experiments back then) is now &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;smk&quot;&gt;SMK&lt;&#x2F;a&gt;, a working keyboard firmware, somewhat stable even. Stable enough that the Air60 running it is one of the two keyboards I use day to day.&lt;&#x2F;p&gt;
&lt;p&gt;It didn&#x27;t all happen at once. Matrix scanning and USB came first, which is the point where it&#x27;s a keyboard you can actually type on. A port to an E-YOOSO Z11 came next, and that was what forced the Air60-specific assumptions out of the way, taking the first steps into making this a more general keyboard firmware. Then media keys, NKRO, the LED effect engine, sleep, settings persistence, and fixing a pile of nasty timing bugs (USB-enumeration freezes, the LED scan and matrix scan fighting over the same pins), along with a bunch of cases where the stack would overflow or an interrupt would write into the wrong page. The 8051 isn&#x27;t a forgiving architecture: the stack shares its 256 bytes of internal RAM with everything else, and nothing anywhere will fault on you, so mistakes like that don&#x27;t crash, they just quietly corrupt something you notice a few keystrokes later.&lt;&#x2F;p&gt;
&lt;p&gt;Wireless was its own thing. The Air60 talks 2.4G and Bluetooth through a Beken BK3632, and the protocol between the MCU and that radio wasn&#x27;t documented anywhere, so reproducing it in SMK meant reverse engineering the stock firmware and sitting a logic analyzer on the bus between the two to watch what they actually said to each other. That took a while to get right, but it works now, and it works well enough that I don&#x27;t think about it anymore.&lt;&#x2F;p&gt;
&lt;p&gt;SMK isn&#x27;t tied to the Air60 anymore either, which is what let it spread onto the Z11, a Genesis Thor 300 and a CIY X77, across a few different Sinowealth parts. Every one of those cheap &lt;code&gt;BYKxxx&lt;&#x2F;code&gt; and &lt;code&gt;BYxxxx&lt;&#x2F;code&gt; labelled boards is a potential target.&lt;&#x2F;p&gt;
&lt;p&gt;Testing all of that is the hard part, which is also why I&#x27;ve been holding off on accepting contributions so far. I don&#x27;t own most of these keyboards, and with the amount of refactoring I&#x27;ve been doing, I&#x27;d have no way to tell whether a board I can&#x27;t plug in still works afterwards. I have been experimenting with testing some of the more basic things in a modified build of &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;mazsola.iit.uni-miskolc.hu&#x2F;ucsim&#x2F;&quot;&gt;ucsim&lt;&#x2F;a&gt;, so I think I might be able to start accepting contributions soon.&lt;&#x2F;p&gt;
&lt;p&gt;I should also mention that I started SMK as sort of a QMK clone for 8051, borrowing its keycodes and the general shape of things. But I never got much actual parity with QMK, and since then I&#x27;ve largely diverged from it anyway, so compatibility with QMK isn&#x27;t the aim anymore.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sinowealth-kb-tool-becomes-sinowisp&quot;&gt;sinowealth-kb-tool becomes sinowisp&lt;a class=&quot;zola-anchor&quot; href=&quot;#sinowealth-kb-tool-becomes-sinowisp&quot; aria-label=&quot;Anchor link for: sinowealth-kb-tool-becomes-sinowisp&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The little CLI from part 1 ended up carrying this whole project. Over time it picked up support for a lot more keyboards than I expected: somewhere around fifty of them now, plus a couple of mice.&lt;&#x2F;p&gt;
&lt;p&gt;Most of those entries didn&#x27;t come from keyboards I own. Once the tool was out there, people started showing up with their own boards, filing device reports and dumps, and sometimes pull requests. I was surprised how common a platform this is for relatively inexpensive keyboards.&lt;&#x2F;p&gt;
&lt;p&gt;For a long time, it talked to keyboards through &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;libusb&#x2F;hidapi&quot;&gt;hidapi&lt;&#x2F;a&gt;, a C library. It works and it&#x27;s on every platform, but having a C dependency in the mix got particularly annoying whenever I wanted to cross compile (might just be me). On top of that, I wanted something that could talk WebHID, and something that could give me several different backends on the same platform, so I could switch between them depending on what state the keyboard was in.&lt;&#x2F;p&gt;
&lt;p&gt;So I wrote my own cross-platform HID library in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;hidra&quot;&gt;&lt;strong&gt;hidra&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; talks to the same platform APIs hidapi does: hidraw on Linux, hid.dll and SetupAPI on Windows, and IOKit&#x27;s IOHIDManager on macOS. On top of those it adds &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;WebHID_API&quot;&gt;WebHID&lt;&#x2F;a&gt;, so the same code runs in a browser, which is the whole reason the browser flasher later in this post exists at all. It&#x27;s all one async API.&lt;&#x2F;p&gt;
&lt;p&gt;The part that ended up mattering most, though, is that it can carry several backends at once and switch between them at runtime. A keyboard shows up as a perfectly normal HID device, but the moment you send it into ISP mode its descriptors change, potentially into something the OS doesn&#x27;t consider a valid HID device at all, so the native HID stack can&#x27;t talk to it anymore. To get through you have to drop down to raw USB, which hidra does through &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;nusb&quot;&gt;nusb&lt;&#x2F;a&gt; (a pure-Rust USB library, and the thing that made writing hidra feasible in the first place). So it carries both and picks: HID while the OS still sees a HID device, raw USB once ISP mode has left it undetectable as one.&lt;&#x2F;p&gt;
&lt;p&gt;That fixed some long-standing annoyances. Before, certain devices in ISP mode just couldn&#x27;t be reached at all on some platforms, macOS especially.&lt;&#x2F;p&gt;
&lt;p&gt;The swap came with a restructure. The device-poking logic (read, write, erase, verify, all the bootloader quirks) now lives in a reusable &lt;strong&gt;library&lt;&#x2F;strong&gt;, with the CLI sitting on top as a thin shell. Pulling those apart, on top of hidra, is what lets the library build with no CLI dependencies at all, so it can be compiled for &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;#smk-carlossless-io-flashing-from-a-browser&quot;&gt;the web&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;At that point it wasn&#x27;t really a kb-tool anymore, which was a good excuse to drop a working title I&#x27;d never liked: it&#x27;s now &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sinowisp&quot;&gt;&lt;strong&gt;sinowisp&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-sinolink-to-sinodude&quot;&gt;From SinoLink to sinodude&lt;a class=&quot;zola-anchor&quot; href=&quot;#from-sinolink-to-sinodude&quot; aria-label=&quot;Anchor link for: from-sinolink-to-sinodude&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Time to talk about bricking again...&lt;&#x2F;p&gt;
&lt;p&gt;Part 2 covered how you brick one of these: flash firmware that can&#x27;t jump back into the bootloader and the USB path is gone, leaving a programmer wired straight to the chip as the only way back in. When you&#x27;re iterating on firmware, which involves writing a lot of broken firmware, you end up doing it more than you would expect.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s why I bought the official option back in part 1: a Sinowealth &lt;strong&gt;SinoLink&lt;&#x2F;strong&gt; programmer, the probe the vendor&#x27;s own ProWriter software drives. It works! But it&#x27;s a proprietary black box with a Windows-only host tool, and I really don&#x27;t like having one of those in the middle of an otherwise fully open project.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;sinolink-connected-to-keyboard.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;sinolink-connected-to-keyboard.254abe7b3c45a292.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;sinolink-connected-to-keyboard.2d087a65f981e870.jpg 2x&quot; alt=&quot;a translucent blue SinoLink programmer on a cutting mat, wired through a small adapter board and a ribbon cable into the edge of the Air60&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;the SinoLink, hooked up to the keyboard&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;So, naturally, I took it apart, and spent quite a while with its firmware in Ghidra.&lt;&#x2F;p&gt;
&lt;p&gt;The bit I actually cared about is how it programs the 8051 parts (Sinowealth makes ARM ones too). It does that over ICP, on the four JTAG lines. The annoying part is that these programming headers don&#x27;t expose a reset line, so the only way into ICP is to switch the target&#x27;s power off and back on, and start talking to it at the right moment. The read side of that was already mapped out by gashtaan in his &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gashtaan&#x2F;sinowealth-8051-dumper&quot;&gt;sinowealth-8051-dumper&lt;&#x2F;a&gt;, so what I was after was the rest of it: page-write, mass-erase, the custom regions, and managing the security bits. And once I&#x27;d mapped that out, the obvious thought: if I understand the wire protocol, I don&#x27;t need the dongle at all.&lt;&#x2F;p&gt;
&lt;p&gt;So I released &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sinodude&quot;&gt;&lt;strong&gt;sinodude&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;: an open-source programmer that runs on a plain &lt;strong&gt;Arduino Nano&lt;&#x2F;strong&gt; (though it would take little to get it onto any compatible AVR) and can read and write most of the Sinowealth 8051 chips.&lt;&#x2F;p&gt;
&lt;p&gt;The Nano wasn&#x27;t a random pick. The SinoLink is relatively expensive and, depending on where you are, hard to source, while a Nano is a couple of euros and you can get one anywhere, and anyone willing to crack open their keyboard has probably got one in a drawer already. gashtaan&#x27;s dumper already runs on one too (it&#x27;s the exact setup that I started with back in part 1), so there was a well-trodden path onto that hardware.&lt;&#x2F;p&gt;
&lt;p&gt;It also just made my life a lot better. I really disliked being stuck in the Windows-only ProWriter, and reverse-engineering how ProWriter itself talked to the SinoLink turned out to be harder than I expected. (I got a semi-working version of that going, and maybe I&#x27;ll finish it off one day and add SinoLink support back into sinodude. We&#x27;ll see.) Being able to run this programmer from a CLI, on Linux and macOS, was worth all of it.&lt;&#x2F;p&gt;
&lt;p&gt;The circuit is minimal: the four JTAG lines, ground, and one more pin driving a MOSFET that gates power to the target, so the programmer can time the power cycle these chips need itself. What it doesn&#x27;t have is the circuitry the SinoLink puts around all this: a 3V3 supply alongside the 5V one, level translation between the probe and the target, and draining circuitry on the target&#x27;s rails, without which the power cycle isn&#x27;t always consistent on boards with more capacitance. But it&#x27;s stable enough for me.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
  
  
  &lt;div style=&quot;display: flex; flex-wrap: wrap; gap: 10px; max-width: 100%;&quot;&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;sinodude-nano-connected-to-keyboard.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;sinodude-nano-connected-to-keyboard.aa14cfbd046573b1.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;sinodude-nano-connected-to-keyboard.a9d7713e008452c4.jpg 2x&quot; alt=&quot;an Arduino Nano on a breadboard, wired through jumper wires and a ribbon cable to a NuPhy Air60 next to it&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;sinodude-nano-connected-to-breakout.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;sinodude-nano-connected-to-breakout.d090a3f179a61a90.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;sinodude-nano-connected-to-breakout.b11d1fffac552a02.jpg 2x&quot; alt=&quot;the same Nano on the breadboard, wired by jumper wires to a bare Sinowealth chip on a green breakout board&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;connector-into-keyboard-pcb.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;connector-into-keyboard-pcb.9fe9425f4c769fc9.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;connector-into-keyboard-pcb.af17029d867cdea0.jpg 2x&quot; alt=&quot;a ribbon cable plugged into a white connector on the Air60&amp;#x27;s blue PCB, between the switch sockets&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
  &lt;&#x2F;div&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;sinodude (Arduino Nano) in action&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;On the host side it&#x27;s the usual &lt;code&gt;read&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;write&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;erase&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;verify&lt;&#x2F;code&gt;, with a database of about 370 Sinowealth parts behind it, so it can read the JTAG ID off a target and suggest which parts match it, and with support for the EEPROM and all the custom regions these parts have (customer ID, option bytes, the security key, and so on).&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;sinowealth-chips-on-breakouts.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;sinowealth-chips-on-breakouts.32e90664ae3ebf41.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;sinowealth-chips-on-breakouts.92287868c56d2d37.jpg 2x&quot; alt=&quot;four green breakout boards on a wooden desk, each with a bare Sinowealth QFP chip soldered in the middle and jumper wires running off the pin headers&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;bare Sinowealth parts on breakouts&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;One thing I haven&#x27;t touched yet: the SinoLink can also do on-chip debugging (OCD) on these 8051 targets, not just flashing. That&#x27;s something I&#x27;d like to reverse engineer some day. What I don&#x27;t know yet is how hard it&#x27;d be to wire that up to something standard like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;probe.rs&#x2F;&quot;&gt;probe-rs&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;openocd.org&#x2F;&quot;&gt;OpenOCD&lt;&#x2F;a&gt;, or whether these parts are too far off the beaten path for either to care. A problem for future me.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;smk-carlossless-io-flashing-from-a-browser&quot;&gt;smk.carlossless.io: flashing from a browser&lt;a class=&quot;zola-anchor&quot; href=&quot;#smk-carlossless-io-flashing-from-a-browser&quot; aria-label=&quot;Anchor link for: smk-carlossless-io-flashing-from-a-browser&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This was a fun detour.&lt;&#x2F;p&gt;
&lt;p&gt;Remember how I split the device logic into a sinowisp library, and wrote hidra so it could target WebHID? This is what that was all for. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;smk.carlossless.io&quot;&gt;&lt;strong&gt;smk.carlossless.io&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; is a browser-based flasher for these keyboards. You plug in a HID device with one of these ISP bootloaders, click a button, and read or write its firmware straight from a web page. No CLI, no install, no cables beyond the USB one.&lt;&#x2F;p&gt;
&lt;p&gt;Under the hood it&#x27;s exactly the pieces from above: sinowisp compiled to WebAssembly, talking to the keyboard over WebHID through hidra.&lt;&#x2F;p&gt;
&lt;p&gt;It works largely the same as sinowisp, but:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chromium only.&lt;&#x2F;strong&gt; Firefox still doesn&#x27;t ship WebHID, so it won&#x27;t work there.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;It doesn&#x27;t work on Linux.&lt;&#x2F;strong&gt; This one annoys me, given Linux is the platform I primarily use. The ISP bootloader&#x27;s HID interface has no endpoints, so usbhid never binds it, and without a hidraw node there&#x27;s nothing for WebHID to grab. The obvious fallback would be WebUSB, except Chrome refuses to hand over any interface that claims to be HID. So the device can&#x27;t be reached over HID because the kernel won&#x27;t treat it as one, and can&#x27;t be reached over USB because Chrome insists that it is one.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;a-new-base-for-the-keyboard-with-the-debug-bus-on-the-outside&quot;&gt;A new base for the keyboard, with the debug bus on the outside&lt;a class=&quot;zola-anchor&quot; href=&quot;#a-new-base-for-the-keyboard-with-the-debug-bus-on-the-outside&quot; aria-label=&quot;Anchor link for: a-new-base-for-the-keyboard-with-the-debug-bus-on-the-outside&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Which brings me back to the keyboard itself.&lt;&#x2F;p&gt;
&lt;p&gt;Getting this far meant JTAG leads soldered onto the Air60 (and a few other keyboards), and a whole logic-analyzer harness onto the bit-banged SPI bus to the BK3632. Doing that off flying leads on a half-open keyboard is as annoying as it sounds, especially when you want to be pressing buttons on the other side of it.&lt;&#x2F;p&gt;
&lt;p&gt;All that opening and closing had also wrecked the stock base, with a few of its standoffs disintegrating from being screwed and unscrewed so many times (it wasn&#x27;t that many times...). So I fixed both at once.&lt;&#x2F;p&gt;
&lt;p&gt;First, a combined adapter PCB that lives inside the keyboard permanently, so all that access stays soldered down and I don&#x27;t have to redo it every time.&lt;&#x2F;p&gt;
&lt;p&gt;Then a replacement base designed around it in FreeCAD, with the mounting, standoffs and cutouts worked out against the real PCB, and split into left and right halves so it fits on my printer.&lt;&#x2F;p&gt;
&lt;p&gt;The adapter breaks out:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;the MCU&#x27;s JTAG&lt;&#x2F;strong&gt; - TCK &#x2F; TDI &#x2F; TDO &#x2F; TMS, plus +5V and GND&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;the MCU-to-radio bus&lt;&#x2F;strong&gt; - the SPI lines MOSI &#x2F; MISO &#x2F; SCK &#x2F; CS and the MOT and ACK handshake lines, plus +3V3 and GND&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All of it comes out to headers you can reach with the keyboard fully assembled and running.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
  
  
  &lt;div style=&quot;display: flex; flex-wrap: wrap; gap: 10px; max-width: 100%;&quot;&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;custom-base-inside-battery-and-adapter.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;custom-base-inside-battery-and-adapter.d6fd94d9aca8587e.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;custom-base-inside-battery-and-adapter.00960c82bda33b34.jpg 2x&quot; alt=&quot;the printed base lying open on a cutting mat, with a silver LiPo battery and the purple adapter PCB mounted inside it&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;custom-base-standoffs-and-connectors.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;custom-base-standoffs-and-connectors.08be971a94cdad23.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;custom-base-standoffs-and-connectors.405718905d01954b.jpg 2x&quot; alt=&quot;close-up inside a corner of the base: printed standoffs, the two teal mode switches and the edge of the battery&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;base-exposed-debug-access.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;base-exposed-debug-access.6412989af0ca4372.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;base-exposed-debug-access.83a527eda0881718.jpg 2x&quot; alt=&quot;the back edge of the assembled base, with three square debug access ports below an orange flip-out foot and the two teal mode switches above&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;assembled-keyboard-debug-ribbon.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;assembled-keyboard-debug-ribbon.e84d769449f652fd.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;assembled-keyboard-debug-ribbon.1c93c4c05577da7c.jpg 2x&quot; alt=&quot;the fully assembled keyboard on a cutting mat, a ribbon cable running out of the side of its base to the SinoLink&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;printed-base-split-halves.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;printed-base-split-halves.8fb6bcad80c08281.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;printed-base-split-halves.4aaf5648450a61a6.jpg 2x&quot; alt=&quot;the underside of the printed base, showing the curved seam between the two printed halves, the two orange flip-out feet and the teal rubber strips&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
      
      
      
      &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-3&#x2F;custom-base-feet.jpg&quot; style=&quot;flex: 1 1 200px; min-width: 0;&quot;&gt;
        
          
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;custom-base-feet.93081eedebd14ead.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;custom-base-feet.a5f43cd6a96e8bed.jpg 2x&quot; alt=&quot;the base standing on edge, showing the teal rubber strips and the three square debug access ports in its side&quot; style=&quot;width: 100%;&quot; &#x2F;&gt;
          
        
      &lt;&#x2F;a&gt;
    
  &lt;&#x2F;div&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;the new base, inside and out&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;Here&#x27;s the base (drag to spin it):&lt;&#x2F;p&gt;
&lt;div class=&quot;stl-1&quot;&gt;
    &lt;script type=&quot;module&quot;&gt;
        import * as THREE from &#x27;three&#x27;;
        import { STLLoader } from &#x27;three&#x2F;addons&#x2F;loaders&#x2F;STLLoader.js&#x27;;
        import { OrbitControls } from &#x27;three&#x2F;addons&#x2F;controls&#x2F;OrbitControls.js&#x27;;

        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera( 75, 1.25, 1, 1000);

        const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enablePan = false;
        controls.enableZoom = false;
        &#x2F;&#x2F; renderer.setSize(660, 528);
        document.getElementsByClassName(&#x27;stl-1&#x27;)[0].appendChild(renderer.domElement);

        const pointLight = new THREE.DirectionalLight(0xffffff, 3);
        scene.add(pointLight);

        let mesh

        const loader = new STLLoader();
        loader.load(&quot;nuphy-air60-base.stl&quot;, function (geometry) {
            const material = new THREE.MeshLambertMaterial({color: 0xE752EE});
            mesh = new THREE.Mesh(geometry, material);
            mesh.geometry.center();
            scene.add(mesh);

            const offset = 1.7 &#x2F; 1.35;

            const boundingBox = new THREE.Box3();
            boundingBox.setFromObject(mesh);

            var middle = new THREE.Vector3();
            var size = new THREE.Vector3();
            boundingBox.getSize(size);

            const fov = camera.fov * ( Math.PI &#x2F; 180 );
            const fovh = 2*Math.atan(Math.tan(fov&#x2F;2) * camera.aspect);
            let dx = size.z &#x2F; 2 + Math.abs( size.x &#x2F; 2 &#x2F; Math.tan( fovh &#x2F; 2 ) );
            let dy = size.z &#x2F; 2 + Math.abs( size.y &#x2F; 2 &#x2F; Math.tan( fov &#x2F; 2 ) );
            let cameraZ = Math.max(dx, dy);

            &#x2F;&#x2F; offset the camera, if desired (to avoid filling the whole canvas)
            if( offset !== undefined &amp;&amp; offset !== 0 ) cameraZ *= offset;

            camera.position.set( 0, cameraZ&#x2F;2, cameraZ );

            &#x2F;&#x2F; set the far plane of the camera so that it easily encompasses the whole object
            const minZ = boundingBox.min.z;
            const cameraToFarEdge = ( minZ &lt; 0 ) ? -minZ + cameraZ : cameraZ - minZ;

            camera.far = cameraToFarEdge * 3;
            camera.updateProjectionMatrix();
        });

        function resizeCanvasToDisplaySize() {
            const canvas = renderer.domElement.parentElement;
            &#x2F;&#x2F; look up the size the canvas is being displayed
            const width = canvas.clientWidth;

            &#x2F;&#x2F; adjust displayBuffer size to match
            if (canvas.width !== width) {
                &#x2F;&#x2F; you must pass false here or three.js sadly fights the browser
                renderer.setSize(width, width&#x2F;camera.aspect, false);
                &#x2F;&#x2F; camera.aspect = width &#x2F; height;
                camera.updateProjectionMatrix();

                &#x2F;&#x2F; update any render target sizes here
            }
        }

        &#x2F;&#x2F; camera.position.z = distance;
        controls.autoRotate = true;
        controls.update();
        resizeCanvasToDisplaySize();

        function animate() {
            controls.update();
            pointLight.position.copy(camera.position);
            resizeCanvasToDisplaySize();
            renderer.render( scene, camera );
        }
        renderer.setAnimationLoop( animate );
    &lt;&#x2F;script&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;why-now-though&quot;&gt;Why now, though?&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-now-though&quot; aria-label=&quot;Anchor link for: why-now-though&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;A big reason I came back to this project at all is that LLM agents made the leftover parts finishable in the relatively little free time I have these days. What was left wasn&#x27;t hard so much as tedious, and that&#x27;s exactly the kind of work they&#x27;re good at.&lt;&#x2F;p&gt;
&lt;p&gt;Reverse engineering is the obvious example, the SinoLink&#x27;s firmware above as much as the keyboard&#x27;s own stock firmware. A lot of it is just grinding: stepping through the disassembly, working out what a routine does, annotating it, and moving on to the next one. That&#x27;s the part it&#x27;s great at, and having it do that groundwork with me meant an hour in the evening was enough to get somewhere, instead of just enough to remember where I&#x27;d left off.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-next&quot;&gt;What&#x27;s next&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-s-next&quot; aria-label=&quot;Anchor link for: what-s-next&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&quot;I don&#x27;t like the stock software&quot; turned into a bootloader flasher, a keyboard firmware, an in-circuit programmer for when that bootloader can&#x27;t save you, a cross-platform HID library, the same flasher again in a browser, and a printed base that hands you the keyboard&#x27;s own debug bus on a header. This is probably the deepest and most branching rabbit hole I&#x27;ve been down, and also one of the most rewarding.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s still plenty I want to do:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;An open-source ISP bootloader.&lt;&#x2F;strong&gt; The stock one is what bricks you, and it&#x27;s the reason the browser flasher can&#x27;t touch Linux. I&#x27;d like to replace it with one that presents itself as a proper HID device, which would kill the Linux limitation, and one that&#x27;s actually recoverable: hold a key combination while plugging the keyboard in and you&#x27;re in the bootloader, no programmer needed.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;An open-hardware replacement for the SinoLink.&lt;&#x2F;strong&gt; The Arduino Nano is the only programmer sinodude supports right now, and it&#x27;s bare-bones. I want a proper little board around an RP2xxx, with the 5V &#x2F; 3V3 muxing, level shifting and draining circuitry it&#x27;s missing, and with a lot of the bit-banging living in the PIO instead of being timed by hand. And additionally, one day, hopefully, sinodude talking to a SinoLink directly as well.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A lot more SMK.&lt;&#x2F;strong&gt; More refactoring, more boards, and (fingers crossed) more actual features.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you&#x27;re interested in any of this, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;smk&quot;&gt;SMK is on GitHub&lt;&#x2F;a&gt; and there&#x27;s a small community on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;discord.gg&#x2F;SZFBDBuxrK&quot;&gt;Discord&lt;&#x2F;a&gt; if you want to come say hi.&lt;&#x2F;p&gt;
&lt;p&gt;Many thanks again to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gashtaan&quot;&gt;@gashtaan&lt;&#x2F;a&gt; for releasing his &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gashtaan&#x2F;sinowealth-8051-dumper&quot;&gt;dumper&lt;&#x2F;a&gt;, which enabled me to take the first steps in this project, and to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;swiftgeek&quot;&gt;@swiftgeek&lt;&#x2F;a&gt; for his &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;swiftgeek&#x2F;hykker-re&quot;&gt;reverse engineering work&lt;&#x2F;a&gt; around these chips!&lt;&#x2F;p&gt;
&lt;p&gt;See you in the next part!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>An Interesting Find: STM32 RDP1 &quot;Decryptor&quot;</title>
        <published>2026-03-01T00:00:00+00:00</published>
        <updated>2026-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/stm32-rdp1-decryptor/"/>
        <id>https://karstx.net/stm32-rdp1-decryptor/</id>
        
        <content type="html" xml:base="https://karstx.net/stm32-rdp1-decryptor/">&lt;p&gt;Recently while browsing &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.goofish.com&#x2F;&quot;&gt;Xianyu (闲鱼)&lt;&#x2F;a&gt; looking for BYK-series chips (Sinowealth 8051 MCUs) for another project I&#x27;m working on, I stumbled across something peculiar: a device claiming to bypass STM32 RDP1 (Read-Out Protection Level 1) on F0, F1, F2 and F4 series chips. As it turns out, there&#x27;s a whole market for these if you search for &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.goofish.com&#x2F;search?q=STM32%E8%A7%A3%E5%AF%86&quot;&gt;&quot;STM32解密&quot;&lt;&#x2F;a&gt; (STM32 decryption).&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;xianyu-listing.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;xianyu-listing.8f4b1f41ccf94f3c.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;xianyu-listing.66c3cd2837f7cb0c.jpg 2x&quot; alt=&quot;Xianyu listing photo showing the decryptor kit with USB dongle, multiple adapter PCBs and SWD pinout reference cards&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;a picture from one of the many &amp;quot;STM32 decryptor&amp;quot; listings on Xianyu&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;At about 150 yuan, roughly 19 EUR plus shipping and forwarding on top, I decided to bite the bullet and just buy one to see if it actually works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-arrived&quot;&gt;What arrived&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-arrived&quot; aria-label=&quot;Anchor link for: what-arrived&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The package contained a blue USB dongle (the programmer), two green adapter PCBs, a row of double and a row of single 2.54mm pin headers and a couple of 10K resistors.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;kit-layout.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;kit-layout.9fed67d821d68bbc.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;kit-layout.d88724bacd50e922.jpg 2x&quot; alt=&quot;All components laid out on a cutting mat: USB dongle, two adapter PCBs, pin headers and connector&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;everything that came in the package&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;The adapter boards have footprints for the various packages of F0, F1 and F2&#x2F;F4 chips, along with pads for decoupling capacitors on the necessary VCAP pins and a resistor pulling BOOT1 down. I had to supply the 0.1uF caps for the VCAP pads myself.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;usb-dongle.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;usb-dongle.6a8c4af4c016f7b8.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;usb-dongle.e97b294c23ed14f9.jpg 2x&quot; alt=&quot;Close-up of the blue USB programmer dongle&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;testing-with-an-stm32f205rbt6&quot;&gt;Testing with an STM32F205RBT6&lt;a class=&quot;zola-anchor&quot; href=&quot;#testing-with-an-stm32f205rbt6&quot; aria-label=&quot;Anchor link for: testing-with-an-stm32f205rbt6&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I had an STM32F205RBT6 lying around, so I desoldered it and placed it on the adapter board.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;adapter-board-connected.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;adapter-board-connected.b748169797e3f2da.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;adapter-board-connected.59bd110bda35b172.jpg 2x&quot; alt=&quot;STM32F205RBT6 soldered onto the adapter board and plugged into the USB dongle&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;STM32F205RBT6 soldered onto the adapter board and plugged into the dongle&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;The device comes with a Windows utility. Before I could even get it running, I had to deal with a couple of hurdles. First, the software immediately triggers Windows Defender, probably for good reason. Since I was running this in a throwaway VM anyway, I just turned it off. Second, the application wouldn&#x27;t launch until I changed the system encoding for non-Unicode programs to Chinese Simplified in the Windows 11 regional settings (&lt;code&gt;Settings &amp;gt; Time &amp;amp; language &amp;gt; Language &amp;amp; region &amp;gt; Language for non-Unicode programs &amp;gt; Chinese (Simplified, Mainland China)&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The instructions that came with the device recommended using freeze spray on the chip during the read process. I was ready for that, but it turned out to be unnecessary in my case. It read just fine at room temperature.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;decryptor-utility.png&quot;&gt;
    
        
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;decryptor-utility.36913d8f3074c66f.png&quot; alt=&quot;F0124 Series Decryptor V5.1 Windows utility showing a hex dump of flash contents read from an STM32F2&amp;#x2F;F4 chip&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;the host Windows application showing a successful flash readout. The failed validation message at the bottom is probably related to the overshoot and can be ignored.&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;One quirk: the software would always overshoot when reading. A STM32F205RB has 128KB of flash, but the tool would happily read past that boundary, padding everything beyond it with &lt;code&gt;0xFF&lt;&#x2F;code&gt;. The actual flash contents within the valid 128KB region were correct though, so it&#x27;s easy enough to just trim the output to the right size.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This thing actually works. It successfully dumped the full flash contents of an RDP1-protected STM32F205RBT6 without needing to introduce any external faults like cooling the chip down.&lt;&#x2F;p&gt;
&lt;p&gt;To be clear, this device is not the first to allow circumventing RDP1. There have already been documented ways for most of these devices: voltage glitching on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anvilsecure.com&#x2F;blog&#x2F;glitching-stm32-read-out-protection-with-voltage-fault-injection.html&quot;&gt;STM32F4&lt;&#x2F;a&gt;, the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.zapb.de&#x2F;stm32f1-exceptional-failure&#x2F;&quot;&gt;Exception(al) Failure&lt;&#x2F;a&gt; debug interface exploit on STM32F1, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.aisec.fraunhofer.de&#x2F;en&#x2F;FirmwareProtection.html&quot;&gt;Cold-Boot Stepping&lt;&#x2F;a&gt; on STM32F0, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sec-consult.com&#x2F;blog&#x2F;detail&#x2F;secglitcher-part-1-reproducible-voltage-glitching-on-stm32-microcontrollers&#x2F;&quot;&gt;reproducible glitching setups&lt;&#x2F;a&gt; with open-source tooling. But all of these require understanding the attack, building or buying a glitching rig, and tuning parameters. A turnkey product like this one just lets you solder the chip onto the adapter and click a button. It&#x27;s both concerning and exciting.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, other than glancing at the PCB, which has an SOP-16 IC with the label scraped off (presumably the microcontroller), I haven&#x27;t tried analyzing how this device works yet. The Windows-only host app is not great either, but shouldn&#x27;t be too hard to recreate it if someone wanted to. Might have to take a closer look at what&#x27;s going on under the hood sometime. Or hopefully someone else will!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>racknex UM-SBC-209 + TI LP5012</title>
        <published>2025-03-29T00:00:00+00:00</published>
        <updated>2025-03-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/racknex-lp5012-leds/"/>
        <id>https://karstx.net/racknex-lp5012-leds/</id>
        
        <content type="html" xml:base="https://karstx.net/racknex-lp5012-leds/">&lt;p&gt;As you might have seen from my &lt;a href=&quot;&#x2F;rpi-cluster-at-home&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;, my RPi cluster is housed in a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;racknex.com&#x2F;raspberry-pi-rackmount-kit-4x-slot-19-inch-um-sbc-209&#x2F;&quot;&gt;racknex UM-SBC-209&lt;&#x2F;a&gt; case. It&#x27;s a great case that I utilized to the max by setting up my RPis with poe+ hats, custom &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;qwiic-hat&quot;&gt;hats&lt;&#x2F;a&gt; that I made to expose i2c via two &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sparkfun.com&#x2F;qwiic&quot;&gt;qwiic&lt;&#x2F;a&gt; (jst sh) connectors and an additional 5v fan header that I use to connect to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;noctua.at&#x2F;de&#x2F;products&#x2F;fan&#x2F;nf-a4x10-5v&quot;&gt;Noctua NF-A4x10 5V&lt;&#x2F;a&gt; fans. I had made &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;keystone-oled&quot;&gt;keystone holder&lt;&#x2F;a&gt; for a tiny OLED display and had it connected via the same Qwiic connectors. The only thing left untouched were the holes for the LEDs.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;front.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;front.c50477fc5ba37bf5.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;front.e7f75e0e7af4347e.jpg 2x&quot; alt=&quot;racknex case with LED holes unpopulated&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
&lt;&#x2F;figure&gt;
&lt;p&gt;I wasn’t keen on wiring 3mm LEDs directly to individual GPIOs on the board. That&#x27;s why my Qwiic hat was designed with two connectors instead of just one, though the second connector had been sitting idle for quite some time.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, I decided it was time to put it to good use.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;electronics&quot;&gt;Electronics&lt;a class=&quot;zola-anchor&quot; href=&quot;#electronics&quot; aria-label=&quot;Anchor link for: electronics&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;First off, I found a led controller. The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ti.com&#x2F;lit&#x2F;ds&#x2F;symlink&#x2F;lp5012.pdf&quot;&gt;TI LP50xx&lt;&#x2F;a&gt; seemed like a great choice, since:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;it&#x27;s driven through i2c&lt;&#x2F;li&gt;
&lt;li&gt;the LP5012 supports up to 4 RGB LEDs&lt;&#x2F;li&gt;
&lt;li&gt;the linux kernel has had a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;torvalds&#x2F;linux&#x2F;blob&#x2F;master&#x2F;drivers&#x2F;leds&#x2F;leds-lp50xx.c&quot;&gt;driver&lt;&#x2F;a&gt; for it for years now.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I went ahead and designed a simple board for it, and there&#x27;s not much to say about except that it&#x27;s now &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;racknex-um-sbc-209-addons&#x2F;tree&#x2F;main&#x2F;lp5012-leds&#x2F;pcb&quot;&gt;open source&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When making a board this time around, instead of soldering components onto the board myself like I usually do, I took a gamble on the first revision and ordered it assembled by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jlcpcb.com&#x2F;&quot;&gt;JLCPCB&lt;&#x2F;a&gt; instead of assembling it myself.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;racknex-lp5012-leds&#x2F;.&#x2F;pcb-front.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;pcb-front.57fc03c512679004.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;pcb-front.92cdd7ee2bf8f225.jpg 2x&quot; alt=&quot;PCB with LED side facing upward&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
&lt;&#x2F;figure&gt;

&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;racknex-lp5012-leds&#x2F;pcb-back.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;pcb-back.362bd546939a6c24.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;pcb-back.c27520a2ea675bae.jpg 2x&quot; alt=&quot;PCB with controller and connector facing upward&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Surprisingly, everything worked on the first try!&lt;&#x2F;p&gt;
&lt;p&gt;A big shout-out to the maintainers of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.git.kernel.org&#x2F;pub&#x2F;scm&#x2F;utils&#x2F;i2c-tools&#x2F;i2c-tools.git&#x2F;about&#x2F;&quot;&gt;i2c-tools&lt;&#x2F;a&gt;. This toolset was invaluable for quickly verifying that both the controller and LEDs were functioning correctly before proceeding to load the kernel driver via the device tree.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bracket&quot;&gt;Bracket&lt;a class=&quot;zola-anchor&quot; href=&quot;#bracket&quot; aria-label=&quot;Anchor link for: bracket&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Even though this board works perfectly, it can&#x27;t just float in mid-air. It needs to be securely positioned to align precisely with the LED holes. To solve this, I designed a custom bracket that fits snugly between the keystone frame, the Raspberry Pi and the bends of the front faceplate.&lt;&#x2F;p&gt;
&lt;div class=&quot;stl-1&quot;&gt;
    &lt;script type=&quot;module&quot;&gt;
        import * as THREE from &#x27;three&#x27;;
        import { STLLoader } from &#x27;three&#x2F;addons&#x2F;loaders&#x2F;STLLoader.js&#x27;;
        import { OrbitControls } from &#x27;three&#x2F;addons&#x2F;controls&#x2F;OrbitControls.js&#x27;;

        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera( 75, 1.25, 1, 1000);

        const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enablePan = false;
        controls.enableZoom = false;
        &#x2F;&#x2F; renderer.setSize(660, 528);
        document.getElementsByClassName(&#x27;stl-1&#x27;)[0].appendChild(renderer.domElement);

        const pointLight = new THREE.DirectionalLight(0xffffff, 3);
        scene.add(pointLight);

        let mesh

        const loader = new STLLoader();
        loader.load(&quot;racknex-um-sbc-209-lp5012-bracket.stl&quot;, function (geometry) {
            const material = new THREE.MeshLambertMaterial({color: 0xE752EE});
            mesh = new THREE.Mesh(geometry, material);
            mesh.geometry.center();
            scene.add(mesh);

            const offset = 1.7 &#x2F; 1;

            const boundingBox = new THREE.Box3();
            boundingBox.setFromObject(mesh);

            var middle = new THREE.Vector3();
            var size = new THREE.Vector3();
            boundingBox.getSize(size);

            const fov = camera.fov * ( Math.PI &#x2F; 180 );
            const fovh = 2*Math.atan(Math.tan(fov&#x2F;2) * camera.aspect);
            let dx = size.z &#x2F; 2 + Math.abs( size.x &#x2F; 2 &#x2F; Math.tan( fovh &#x2F; 2 ) );
            let dy = size.z &#x2F; 2 + Math.abs( size.y &#x2F; 2 &#x2F; Math.tan( fov &#x2F; 2 ) );
            let cameraZ = Math.max(dx, dy);

            &#x2F;&#x2F; offset the camera, if desired (to avoid filling the whole canvas)
            if( offset !== undefined &amp;&amp; offset !== 0 ) cameraZ *= offset;

            camera.position.set( 0, cameraZ&#x2F;2, cameraZ );

            &#x2F;&#x2F; set the far plane of the camera so that it easily encompasses the whole object
            const minZ = boundingBox.min.z;
            const cameraToFarEdge = ( minZ &lt; 0 ) ? -minZ + cameraZ : cameraZ - minZ;

            camera.far = cameraToFarEdge * 3;
            camera.updateProjectionMatrix();
        });

        function resizeCanvasToDisplaySize() {
            const canvas = renderer.domElement.parentElement;
            &#x2F;&#x2F; look up the size the canvas is being displayed
            const width = canvas.clientWidth;

            &#x2F;&#x2F; adjust displayBuffer size to match
            if (canvas.width !== width) {
                &#x2F;&#x2F; you must pass false here or three.js sadly fights the browser
                renderer.setSize(width, width&#x2F;camera.aspect, false);
                &#x2F;&#x2F; camera.aspect = width &#x2F; height;
                camera.updateProjectionMatrix();

                &#x2F;&#x2F; update any render target sizes here
            }
        }

        &#x2F;&#x2F; camera.position.z = distance;
        controls.autoRotate = true;
        controls.update();
        resizeCanvasToDisplaySize();

        function animate() {
            controls.update();
            pointLight.position.copy(camera.position);
            resizeCanvasToDisplaySize();
            renderer.render( scene, camera );
        }
        renderer.setAnimationLoop( animate );
    &lt;&#x2F;script&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;racknex-lp5012-leds&#x2F;bracket-front.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;bracket-front.cf9b21c06b430ed1.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;bracket-front.a502a6ef1aa5b88e.jpg 2x&quot; alt=&quot;bracket with half-way inserted pcb from the front&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
&lt;&#x2F;figure&gt;

&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;racknex-lp5012-leds&#x2F;bracket-back.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;bracket-back.41b24583d9541366.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;bracket-back.a54f3c28e4a719e4.jpg 2x&quot; alt=&quot;bracket with fully inserted pcb from the back&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;I also needed some light pipes to transfer and diffuse the light better, fortunately it was easy to find some on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aliexpress.com&#x2F;item&#x2F;32969275348.html&quot;&gt;aliexpress&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;racknex-lp5012-leds&#x2F;bracked-light-pipe.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;bracked-light-pipe.803a17708a326c4c.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;bracked-light-pipe.6272f8db4bb4a5bc.jpg 2x&quot; alt=&quot;bracket with light pipes inserted&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
  &lt;figcaption class=&quot;center&quot;&gt;the front face of the case is about as thick as the light pipes poke out in the picture&lt;&#x2F;figcaption&gt;
  
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;a class=&quot;zola-anchor&quot; href=&quot;#configuration&quot; aria-label=&quot;Anchor link for: configuration&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now that I had everything ready, assembled, and installed, the final step was to build a device-tree overlay that would enable the kernel to drive these LEDs and make them actually indicate something. Fortunately, this was easy to do, and I ended up with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;dts-v1&#x2F;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;plugin&#x2F;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#include &amp;lt;dt-bindings&#x2F;leds&#x2F;common.h&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  compatible = &amp;quot;brcm,bcm2711&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  fragment@0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    target = &amp;lt;&amp;amp;i2c1&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    i2c_bus: __overlay__ {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      led-controller@14 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        compatible = &amp;quot;ti,lp5012&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        reg = &amp;lt;0x14&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        #address-cells = &amp;lt;1&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        #size-cells = &amp;lt;0&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        multi-led@0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          #address-cells = &amp;lt;1&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          #size-cells = &amp;lt;0&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          reg = &amp;lt;0&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          color = &amp;lt;LED_COLOR_ID_RGB&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          function = LED_FUNCTION_POWER;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          default-state = &amp;quot;off&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          linux,default-trigger = &amp;quot;default-on&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          max-brightness = &amp;lt;127&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          led@0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            reg = &amp;lt;0&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            color = &amp;lt;LED_COLOR_ID_RED&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          led@1 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            reg = &amp;lt;1&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            color = &amp;lt;LED_COLOR_ID_GREEN&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          led@2 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            reg = &amp;lt;2&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            color = &amp;lt;LED_COLOR_ID_BLUE&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        multi-led@1 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unfortunately there currently is no way to set the initial color intensity through the device tree, so I had to do that via a oneshot systemd service:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{}: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  systemd&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lp5012-intensity&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    enable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    wantedBy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [ &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;multi-user.target&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; ]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    serviceConfig&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      Type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;oneshot&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      User&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      Group&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      RemainAfterExit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    script&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      if [ -d &#x2F;sys&#x2F;class&#x2F;leds&#x2F;rgb:power ]; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        echo &amp;quot;0 255 0&amp;quot; &amp;gt; &#x2F;sys&#x2F;class&#x2F;leds&#x2F;rgb:power&#x2F;multi_intensity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can find the full nix module which includes the full device-tree overlay in this &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;karstx&#x2F;867fc12315b6f09e82c09430d6eeb63f&quot;&gt;gist&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;end&quot;&gt;End&lt;a class=&quot;zola-anchor&quot; href=&quot;#end&quot; aria-label=&quot;Anchor link for: end&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;racknex-lp5012-leds&#x2F;racknex-rpi-top.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;racknex-rpi-top.02d903ceefd9d0f8.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;karstx.net&amp;#x2F;processed_images&amp;#x2F;racknex-rpi-top.28af69aaea0deb88.jpg 2x&quot; alt=&quot;RPi with several hats in a racknex UM-SBC-209 case&quot; &#x2F;&gt;
        
    
  &lt;&#x2F;a&gt;
  
&lt;&#x2F;figure&gt;

&lt;figure&gt;
  
  
  
  
  
  
    
    
  
  &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;racknex-lp5012-leds&#x2F;racknex-front-leds.gif&quot;&gt;
    
        &lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;racknex-lp5012-leds&#x2F;racknex-front-leds.gif&quot; alt=&quot;indicators in action&quot; &#x2F;&gt;
    
  &lt;&#x2F;a&gt;
  
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s it, I finally feel this project is complete... for now...&lt;&#x2F;p&gt;
&lt;p&gt;You can find all the custom parts used in this project here:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;racknex-um-sbc-209-addons&quot;&gt;racknex-um-sbc-209-addons&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;qwiic-hat&quot;&gt;qwiic-hat&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;keystone-oled&quot;&gt;keystone-oled&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Hacking the NuPhy Air60 keyboard: part 2</title>
        <published>2023-10-19T00:00:00+00:00</published>
        <updated>2023-10-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/nuphy-air60-part-2/"/>
        <id>https://karstx.net/nuphy-air60-part-2/</id>
        
        <content type="html" xml:base="https://karstx.net/nuphy-air60-part-2/">&lt;p&gt;&lt;em&gt;This project continued in &lt;a href=&quot;&#x2F;nuphy-air60-part-3&quot;&gt;part 3&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s time I wrote an update on this project again!&lt;&#x2F;p&gt;
&lt;p&gt;Since my &lt;a href=&quot;&#x2F;nuphy-air60&quot;&gt;last update&lt;&#x2F;a&gt;, I&#x27;ve been working on bootstrapping a development toolchain and producing a minimal firmware where I could initialize and test the core features of the SH68F90A along side of booting back into the ISP bootloader (otherwise the keyboard will become unprogramable via USB).&lt;&#x2F;p&gt;
&lt;p&gt;I am happy to say that I managed to do that, and released everything I have done so far on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&quot;&gt;github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;v2-has-already-been-released&quot;&gt;V2 has already been released&lt;a class=&quot;zola-anchor&quot; href=&quot;#v2-has-already-been-released&quot; aria-label=&quot;Anchor link for: v2-has-already-been-released&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Before I get into what I managed to do, I should note that NuPhy have recently released &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nuphy.com&#x2F;products&#x2F;air60-v2&quot;&gt;V2 of the Air60&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nuphy.com&#x2F;products&#x2F;air75-v2&quot;&gt;Air75&lt;&#x2F;a&gt; keyboards. These new versions are powered by ARM MCUs instead of the 8051-based SH68F90A and comes with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qmk&#x2F;qmk_firmware&quot;&gt;QMK&lt;&#x2F;a&gt; support out of the box.&lt;&#x2F;p&gt;
&lt;p&gt;I originally started this project, because I wanted to have QMK-like firmware on this keyboard, but since these news have come out, it has becomes purely a learning experience.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re interested in this project because of the possibility of running QMK on a Air60 or Air75 I really recommend you to just get the new version of these keyboards!&lt;&#x2F;p&gt;
&lt;p&gt;But anyway, on to the toolchain...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;embracing-open-source-tooling&quot;&gt;Embracing Open-Source Tooling&lt;a class=&quot;zola-anchor&quot; href=&quot;#embracing-open-source-tooling&quot; aria-label=&quot;Anchor link for: embracing-open-source-tooling&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;A core principle of this project is to use all open source tooling to build the firmware. That&#x27;s why I am using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sdcc.sourceforge.net&#x2F;&quot;&gt;SDCC&lt;&#x2F;a&gt; here, instead of the proprietary &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.arm.com&#x2F;Tools%20and%20Software&#x2F;Keil%20PK51&quot;&gt;Keil C51&lt;&#x2F;a&gt; which seems to be a standard for developing for 8051 MCUs.&lt;&#x2F;p&gt;
&lt;p&gt;I have SDCC configured with the smallest device size, so that all variables are put onto the IRAM, unless they are annotated differently (&lt;code&gt;__xdata&lt;&#x2F;code&gt;, &lt;code&gt;__code&lt;&#x2F;code&gt;, etc.).&lt;&#x2F;p&gt;
&lt;p&gt;The firmware size is 61440 leaving the remaining 4096 bytes untouched for the ISP bootloader.&lt;&#x2F;p&gt;
&lt;p&gt;When the ISP bootloader flashes the given firmware the finalisation routine looks for a &lt;code&gt;ljmp&lt;&#x2F;code&gt; instruction at &lt;code&gt;0xeffb&lt;&#x2F;code&gt; and if considers it valid, it will place it at &lt;code&gt;0x0000&lt;&#x2F;code&gt;, otherwise it will place a &lt;code&gt;ljmp&lt;&#x2F;code&gt; to &lt;code&gt;0xf000&lt;&#x2F;code&gt; (back to the bootloader itself). I gather that this is a mechanism to prevent corrupted firmware from being written to the device and then never being able to boot back into itself. Though, if you write non-corrupted, but non-working firmware, you won&#x27;t be able to boot back into the ISP and you will need a programming device, like the sinolink. Be careful!. (Did I mention this is an incredibly brickable device?)&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, because of this reason, I have added &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&#x2F;blob&#x2F;main&#x2F;src&#x2F;preboot.asm&quot;&gt;preboot.asm&lt;&#x2F;a&gt; which places this &lt;code&gt;ljmp&lt;&#x2F;code&gt; that points to the start of the user firmware at the previously mentioned place.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;diving-into-sh68f90a-s-capabilities&quot;&gt;Diving into SH68F90A&#x27;s Capabilities&lt;a class=&quot;zola-anchor&quot; href=&quot;#diving-into-sh68f90a-s-capabilities&quot; aria-label=&quot;Anchor link for: diving-into-sh68f90a-s-capabilities&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;The SH68F90A on the Air60 (and other Air models) come with the following &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&#x2F;blob&#x2F;03552c6c6244f24ed6f9fd129a96ea96d5d76dd5&#x2F;README.md#code-options&quot;&gt;code-options&lt;&#x2F;a&gt; set. Since I would like to be able to load both the stock firmware and my own firmware through USB, I can&#x27;t change these values to something else, but that also means that my firmware needs to do some specific initialization for the functionality these options require.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing that needs to be setup is the 24MHz SYSCLK infrastructure, this involves initializing the PLL and then swiching SYSCLK to use the clock signal that&#x27;s coming out of it, instead of the 128kHz OSC. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&#x2F;blob&#x2F;03552c6c6244f24ed6f9fd129a96ea96d5d76dd5&#x2F;src&#x2F;clock.c&quot;&gt;link&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Next, since we have the watchdog enabled, we need to configure the watchdog to use a comfortable overflow amount and then make sure that our firmware clears the watchdog timer before it overflows. (I wasn&#x27;t able to test the WDT RESET flag, that would&#x27;ve helped in making this firmware a little bit less brickable). &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&#x2F;blob&#x2F;03552c6c6244f24ed6f9fd129a96ea96d5d76dd5&#x2F;src&#x2F;watchdog.h&quot;&gt;link&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;USB signaling also requires 3.3V, so we also need to initialize the internal voltage regulator. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&#x2F;blob&#x2F;03552c6c6244f24ed6f9fd129a96ea96d5d76dd5&#x2F;src&#x2F;ldo.c&quot;&gt;link&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here we&#x27;re already at a point where we have done enough initialization for the ISP bootloader program to work, so already, we could jump into it if we wanted &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&#x2F;blob&#x2F;03552c6c6244f24ed6f9fd129a96ea96d5d76dd5&#x2F;src&#x2F;isp.c&quot;&gt;link&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;GPIO setup is fairly straightforward, we setup the inputs and outputs, pull-ups according to the key matrix rows (input) and columns (output) and the RGB leds per row, per column. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&#x2F;blob&#x2F;03552c6c6244f24ed6f9fd129a96ea96d5d76dd5&#x2F;src&#x2F;gpio.c&quot;&gt;link&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, a pretty important tool for debugging (in absence of on-chip debugging via USB) is getting UART to work. This is fairly straightforward, and explained ok-ish in the datasheet, but the macros I added to calculate &lt;code&gt;SBRT&lt;&#x2F;code&gt; and &lt;code&gt;SFINE&lt;&#x2F;code&gt; values based on the desired baudrate should make it more easy to work with. Also, since the default (TXD, RXD) UART pins are harder to reach, I am setting the &lt;code&gt;MAPPING&lt;&#x2F;code&gt; register to &lt;code&gt;0x5a&lt;&#x2F;code&gt; to use the M_TXD and M_RXD pins instead, because they are also connected to the columns and the removable switch sockets, plugging in header cables for my USB&amp;lt;-&amp;gt;SERIAL device, though it should be noted that PWM signals will interfere with the UART signals and you might get garbage in your serial output.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60-part-2&#x2F;uart.jpg&quot; alt=&quot;uart connected through 5th and 6th key columns&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p align=&quot;center&quot;&gt;
  &lt;img alt=&quot;hello world printed on screen&quot; src=&quot;hello-world.png&quot;&gt;
&lt;&#x2F;p&gt;
&lt;h2 id=&quot;&quot;&gt;On the horizon&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Moving forward I will be continuing work on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sh68f90a-experiments&quot;&gt;sh68f90a-experiments&lt;&#x2F;a&gt; focusing on getting the following functionalities to work:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Key Matrix&lt;&#x2F;li&gt;
&lt;li&gt;PWM + RGB LED Matrix&lt;&#x2F;li&gt;
&lt;li&gt;USB (it&amp;#39;s a working keyboard!)&lt;&#x2F;li&gt;
&lt;li&gt;Wireless (stretch-goal)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Stay tuned for more updates!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Hacking the NuPhy Air60 keyboard: part 1</title>
        <published>2023-04-19T00:00:00+00:00</published>
        <updated>2023-04-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/nuphy-air60/"/>
        <id>https://karstx.net/nuphy-air60/</id>
        
        <content type="html" xml:base="https://karstx.net/nuphy-air60/">&lt;p&gt;&lt;em&gt;This project continued in &lt;a href=&quot;&#x2F;nuphy-air60-part-2&quot;&gt;part 2&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;nuphy-air60-part-3&quot;&gt;part 3&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Not too long ago, I got a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nuphy.com&#x2F;products&#x2F;air60&quot;&gt;NuPhy Air60&lt;&#x2F;a&gt; keyboard. I got it because I think it looks great! It has a mostly aluminum body, low profile switches along with low profile keycaps, switch sockets so that they can be removed without soldering, 2.4G wireless alongside Bluetooth, and RGB backlighting (yay?). Great right? I think so.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60&#x2F;keyboard.jpg&quot; alt=&quot;keyboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;What&amp;#39;s not great about it is its software and its firmware. NuPhy has a Windows-only tool to configure the keyboard and from what I can tell it&amp;#39;s very limited in what sort of key combinations it can support... For a long time, I&amp;#39;ve been using a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;komar007&#x2F;gh60&quot;&gt;GH60&lt;&#x2F;a&gt; with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qmk&#x2F;qmk_firmware&quot;&gt;QMK&lt;&#x2F;a&gt; until it broke on me and since then I&amp;#39;ve been mostly using Apple keyboards.&lt;&#x2F;p&gt;
&lt;p&gt;So I opened up the keyboard and when I was greeted with an IC that was labeled only with a &amp;quot;BYK916&amp;quot; I knew that this won&amp;#39;t be easy... There was barely any information about chips like this. Seemingly Chinese companies would use this sort of labeling to hide away hardware implementation details or make their own custom packages, but I can&amp;#39;t tell for sure.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60&#x2F;mcu.jpg&quot; alt=&quot;BYK916&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I tried looking for any info online and on my first try I found nothing... A little bit of time passed and I tried again - this time there was a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;RedragonGaming&#x2F;comments&#x2F;nsdw7x&#x2F;comment&#x2F;hjwyu8q&quot;&gt;reddit post&lt;&#x2F;a&gt; mentioning that a package like this was found in another keyboard and is actually a relabeled &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sinowealth.com&#x2F;detaile?pro_id=105&quot;&gt;Sinowealth SH68F90&lt;&#x2F;a&gt;. Interesting! But it&amp;#39;s still a dead end for me since I don&amp;#39;t have any tools to program these chips. On my third try, I was lucky enough to find &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gashtaan&#x2F;sinowealth-8051-dumper&quot;&gt;gashtaans sinowealth-8051-dumper&lt;&#x2F;a&gt; which supported my MCU. I didn&amp;#39;t own any Arduinos by this point, so I set out to buy a Nano, and along the way I also learned about the existence of the ATmega328P clone LogicGreen LGT8F328P, but I digress...&lt;&#x2F;p&gt;
&lt;p&gt;I set up my Arduino with the dumper firmware and was able to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gashtaan&#x2F;sinowealth-8051-dumper&#x2F;issues&#x2F;2#issuecomment-1440488904&quot;&gt;semi-successfully read firmware&lt;&#x2F;a&gt;. Nice!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;nuphy-air60&#x2F;flash-dump.jpg&quot; alt=&quot;flash dumping setup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After a bit of rummaging through datasheets, buying a Sinolink programmer off of Taobao, and consulting others interested in this hardware I eventually figured out that I could use the already built-in ISP mode to upload my own firmware via USB, with no additional hardware needed. After a bit of sniffing and analyzing NuPhy&amp;#39;s firmware update utility, I started building my own tool and...&lt;&#x2F;p&gt;
&lt;p&gt;I present you the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;sinowealth-kb-tool&quot;&gt;sinowealth-kb-tool&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;The tool is not only capable of replacing the existing device firmware but also reading it completely verbatim. Also, while working on the tool I became familiar with different variations of this bootloader in other keyboards out there in the wild and I hope to add support for more of them in the future!&lt;&#x2F;p&gt;
&lt;p&gt;Many thanks to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gashtaan&quot;&gt;@gashtaan&lt;&#x2F;a&gt; for the dumper and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;swiftgeek&quot;&gt;@swiftgeek&lt;&#x2F;a&gt; for his documentation efforts!&lt;&#x2F;p&gt;
&lt;p&gt;Now on to writing some firmware... See you in the &lt;a href=&quot;&#x2F;nuphy-air-60-part-2&quot;&gt;next part&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Raspberry Pi PoE+ hat with nixos</title>
        <published>2022-08-07T00:00:00+00:00</published>
        <updated>2022-08-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/nix-rpi-poe-plus-hat/"/>
        <id>https://karstx.net/nix-rpi-poe-plus-hat/</id>
        
        <content type="html" xml:base="https://karstx.net/nix-rpi-poe-plus-hat/">&lt;p&gt;As previously mentioned in &lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;&quot;&gt;my last post&lt;&#x2F;a&gt;, I&#x27;ve been using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;&quot;&gt;nixos&lt;&#x2F;a&gt; to run my raspberry-pi k3s cluster.&lt;&#x2F;p&gt;
&lt;p&gt;Things have been working great and managing these machines has never been this pleasant, &lt;strong&gt;except for one thing&lt;&#x2F;strong&gt; - the cooling fans which come with the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.raspberrypi.com&#x2F;products&#x2F;poe-plus-hat&#x2F;&quot;&gt;PoE+ hats&lt;&#x2F;a&gt; refuse to work out of the box with nixos.&lt;&#x2F;p&gt;
&lt;p&gt;These fans are enabled without any extra configuration under &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.raspberrypi.com&#x2F;software&#x2F;&quot;&gt;Raspberry Pi OS&lt;&#x2F;a&gt;, so I know that they &lt;em&gt;can&lt;&#x2F;em&gt; work, it just leaves me to figure out how to make them work...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;journey&quot;&gt;Journey&lt;a class=&quot;zola-anchor&quot; href=&quot;#journey&quot; aria-label=&quot;Anchor link for: journey&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;After doing a bit of research I found that due to an incompatibility with the RPi bootloader and how nixos is designed to be used, the device tree cannot be passed down from the bootloader to the kernel, and thus a dtb must be &quot;pre-baked&quot; before some of the optional hardware, like these fans, can be used. This means that all overlays must be applied at compile time before the final dtb is produced. Nixos provides &lt;code&gt;hardware.deviceTree.overlays&lt;&#x2F;code&gt; to do just that.&lt;&#x2F;p&gt;
&lt;p&gt;Naturally, using &lt;code&gt;hardware.deviceTree.overlay&lt;&#x2F;code&gt; would be the way to go, and there&#x27;s already &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixos-hardware&#x2F;blob&#x2F;09ed30ff3bb67f5efe9c77e0d79aca01793526ca&#x2F;raspberry-pi&#x2F;4&#x2F;poe-hat.nix#L18&quot;&gt;examples of taking almost unchanged overlays from rpi&#x2F;linux&lt;&#x2F;a&gt; and applying them through this mechanism.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, some of the overlays that are available in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;linux&#x2F;tree&#x2F;rpi-5.15.y&#x2F;arch&#x2F;arm&#x2F;boot&#x2F;dts&#x2F;overlays&quot;&gt;raspberrypi&#x2F;linux&lt;&#x2F;a&gt; can not be successfully applied with the &lt;code&gt;fdtoverlay&lt;&#x2F;code&gt; tool used &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;blob&#x2F;master&#x2F;pkgs&#x2F;os-specific&#x2F;linux&#x2F;device-tree&#x2F;default.nix#L24&quot;&gt;here&lt;&#x2F;a&gt;. It just fails with barely any output other than a not-so-helpful &lt;code&gt;FDT_NOT_FOUND&lt;&#x2F;code&gt; error, and even running it in verbose mode with &lt;code&gt;fdtoverlay -v&lt;&#x2F;code&gt; does not provide any additional hints.&lt;&#x2F;p&gt;
&lt;p&gt;Digging into it more, I found that these overlays actually require RPiFs own &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;userland&#x2F;blob&#x2F;master&#x2F;host_applications&#x2F;linux&#x2F;apps&#x2F;dtmerge&#x2F;dtmerge.c&quot;&gt;dtmerge&lt;&#x2F;a&gt; tool for successfully application.&lt;&#x2F;p&gt;
&lt;p&gt;After a bit of fiddling, I found that exchanging the implementation of applyOverlay with one that uses &lt;code&gt;dtmerge&lt;&#x2F;code&gt; instead of &lt;code&gt;fdtoverlay&lt;&#x2F;code&gt; was enough to successfully produce a valid dtb, and with it, kick my rpi fans into motion.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;result&quot;&gt;Result&lt;a class=&quot;zola-anchor&quot; href=&quot;#result&quot; aria-label=&quot;Anchor link for: result&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I have created &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixos-hardware&#x2F;pull&#x2F;442&quot;&gt;a pull-request in nixos-hardware&lt;&#x2F;a&gt; using the previously mentioned findings as a solution. &lt;del&gt;I&#x27;m not sure if this will ever be merged, but even if it won&#x27;t be, it should serve as an example to anyone who would like to get their PoE+ hat fans working under nixos&lt;&#x2F;del&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;UPDATE: It&#x27;s been merged!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Raspberry Pi Cluster @ Home</title>
        <published>2022-07-16T00:00:00+00:00</published>
        <updated>2022-07-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/rpi-cluster-at-home/"/>
        <id>https://karstx.net/rpi-cluster-at-home/</id>
        
        <content type="html" xml:base="https://karstx.net/rpi-cluster-at-home/">&lt;p&gt;I recently decided to move most of my meager server workloads from the cloud back to my own home.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re asking &lt;strong&gt;&quot;why???&quot;&lt;&#x2F;strong&gt; Then I would have to ask you to settle down and inform you that it&#x27;s much more a &lt;strong&gt;&quot;why not???&quot;&lt;&#x2F;strong&gt; situation.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to try and learn &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;&quot;&gt;nixos&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;&quot;&gt;k8s&lt;&#x2F;a&gt; (through &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;k3s.io&#x2F;&quot;&gt;k3s&lt;&#x2F;a&gt;) and I like the idea of owning and having control over my hardware, that&#x27;s pretty much the whole reason.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not the first to do something like this and there are plenty of resources from people like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.jeffgeerling.com&#x2F;tags&#x2F;k3s&quot;&gt;Jeff Geerling&lt;&#x2F;a&gt; that are doing the same with similar setups.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hardware&quot;&gt;Hardware&lt;a class=&quot;zola-anchor&quot; href=&quot;#hardware&quot; aria-label=&quot;Anchor link for: hardware&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I wanted to have a nice clean rack-mountable enclosure for this cluster, but that took me on a path to design and produce several accessories to get more utility out of it, like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;keystone-oled&quot;&gt;keystone-oled&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;qwiic-hat&quot;&gt;qwiic-hat&lt;&#x2F;a&gt;. Here are a few images of the project in it&#x27;s current state.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Enclosure&lt;&#x2F;th&gt;&lt;th&gt;Front&lt;&#x2F;th&gt;&lt;th&gt;Qwiic Hat&lt;&#x2F;th&gt;&lt;th&gt;Mounted&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;enclosure.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;enclosure.jpg&quot; alt=&quot;enclosure&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;front.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;front.jpg&quot; alt=&quot;front&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;qwiic-hat.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;qwiic-hat.jpg&quot; alt=&quot;i2c-hat&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;mounted.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;rpi-cluster-at-home&#x2F;mounted.jpg&quot; alt=&quot;mounted&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;&quot;&gt;BOM&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;1x &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;shop.racknex.com&#x2F;19-inch-raspberry-pi-rackmount-kit-um-sbc-209&#x2F;&quot;&gt;racknex UM-SBC-209&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;4x &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.raspberrypi.com&#x2F;products&#x2F;raspberry-pi-4-model-b&#x2F;&quot;&gt;Raspberry Pi 4B&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;4x &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.raspberrypi.com&#x2F;products&#x2F;poe-plus-hat&#x2F;&quot;&gt;POE+ hat&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;16x M2.5 15mm standoffs&lt;&#x2F;li&gt;
&lt;li&gt;8x M2.5 5mm standoffs&lt;&#x2F;li&gt;
&lt;li&gt;16x M2.5 flathead philips screws&lt;&#x2F;li&gt;
&lt;li&gt;4x &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reichelt.de&#x2F;sg&#x2F;de&#x2F;buchsenleisten-2-54-mm-2x02-gerade-mpe-094-2-004-p119926.html?&amp;amp;trstct=pos_0&amp;amp;nbc=1&quot;&gt;2x2 2.54mm socket&lt;&#x2F;a&gt; - for RPi POE pins&lt;&#x2F;li&gt;
&lt;li&gt;4x &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reichelt.de&#x2F;sg&#x2F;de&#x2F;raspberry-pi-gpio-header-40-polig-rm-2-54-farblich-kodiert-rpi-header-cg2-p266032.html&quot;&gt;2x20 2.54mm socket with long pins&lt;&#x2F;a&gt; - for RPi GPIO pins&lt;&#x2F;li&gt;
&lt;li&gt;4x &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;keystone-oled&quot;&gt;keystone-oled&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;4x &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.buydisplay.com&#x2F;i2c-white-0-49-inch-oled-display-module-64x32-arduino-raspberry-pi&quot;&gt;0.49 inch OLED SSD1306 32x64&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;4x &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;qwiic-hat&quot;&gt;qwiic-hat&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;-1&quot;&gt;Software&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The software driving the OLED screens is a small custom rust app using the userspace i2cdev interface. It shows node IPs, CPU temps and supports animated transitions, but it&amp;#39;s not really finished and I haven&amp;#39;t released it, &lt;em&gt;yet&lt;&#x2F;em&gt;...&lt;&#x2F;p&gt;
&lt;p&gt;I have tried using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;torvalds&#x2F;linux&#x2F;blob&#x2F;master&#x2F;drivers&#x2F;video&#x2F;fbdev&#x2F;ssd1307fb.c&quot;&gt;ssd1307fb&lt;&#x2F;a&gt; driver to expose it as a linux framebuffer device, but I couldn&amp;#39;t get it working perfectly and decided to drop it all together. I am looking it forward to trying &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;torvalds&#x2F;linux&#x2F;blob&#x2F;master&#x2F;drivers&#x2F;gpu&#x2F;drm&#x2F;solomon&#x2F;ssd130x-i2c.c&quot;&gt;the drm rewrite of the driver&lt;&#x2F;a&gt; though.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-2&quot;&gt;Future Improvements &amp;amp; Notes&lt;a class=&quot;zola-anchor&quot; href=&quot;#-2&quot; aria-label=&quot;Anchor link for: -2&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;LEDs: In the future I would also like to mount RGB LEDs in those currently vacant holes. I have yet to design a board for them, but that&amp;#39;s why I have a second unused qwiic&#x2F;I2C port.&lt;&#x2F;p&gt;
&lt;p&gt;fans: There are mounting holes on the UM-SBC-209 case for 40mm fans, but I don&amp;#39;t yet have a way of powering them. I am considering expanding the qwiic-hat to include a 4-pin PWM fan connector to power and control the fan.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>APFS Volumes for your git projects</title>
        <published>2019-06-10T15:02:00+00:00</published>
        <updated>2019-06-10T15:02:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/solving-that-pesky-file-rename-in-git-with-apfs-volumes/"/>
        <id>https://karstx.net/solving-that-pesky-file-rename-in-git-with-apfs-volumes/</id>
        
        <content type="html" xml:base="https://karstx.net/solving-that-pesky-file-rename-in-git-with-apfs-volumes/">&lt;p&gt;I&#x27;ve been using this setup for over 2 years now and it saved me from a large number of small to medium headaches that used to haunt me every so often. Because of this, I think it&#x27;s worth talking about in a blog post.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;so-what-am-i-talking-about&quot;&gt;So what am I talking about?&lt;a class=&quot;zola-anchor&quot; href=&quot;#so-what-am-i-talking-about&quot; aria-label=&quot;Anchor link for: so-what-am-i-talking-about&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;Ever had to commit a file only to realize that you got the capitalization wrong? I&#x27;ve certainly been in that situation.&lt;&#x2F;p&gt;
&lt;p&gt;Well you&#x27;d think that you could just go back, edit the filename, &lt;code&gt;git commit --commit&lt;&#x2F;code&gt; and you&#x27;re good, right? Wrong.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;asciinema.org&#x2F;a&#x2F;AXQ3HyaE4vz6G4HUUeN2HJvg7&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;asciinema.org&#x2F;a&#x2F;AXQ3HyaE4vz6G4HUUeN2HJvg7.svg&quot; alt=&quot;asciicast&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Well... Wrong for most users at least, because most of them will notice that the naming change wasn&amp;#39;t picked up by git.&lt;&#x2F;p&gt;
&lt;p&gt;The reason why? It&amp;#39;s probably because you&amp;#39;re using a case-insensitive file system. It used to be the default option for HFS+, and it still is the default for APFS. Some applications rely on this to be the case, like the Adobe suite, so you don&amp;#39;t want to change case-sensitivity for your whole system drive.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;&quot;&gt;Volumes to the rescue!&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;APFS redefines partitions with the introduction of &lt;em&gt;volumes&lt;&#x2F;em&gt;. Normal partitions and APFS volumes differ in many ways, but the two that we care about in this case are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Space sharing - volumes don&amp;#39;t have predetermined sizes and will be able to &amp;quot;grow&amp;quot; until there&amp;#39;s no space left in the container.&lt;&#x2F;li&gt;
&lt;li&gt;Independent configuration - different volumes can have different variants of APFS setup. In our case we can have a case-insensitive volume and a case-sensitive one.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So, in my case I created a new volume APFS called &lt;strong&gt;Projects&lt;&#x2F;strong&gt; with case-sensitive filenames and put all of my code and repositories in it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;solving-that-pesky-file-rename-in-git-with-apfs-volumes&#x2F;hZ6ABYkF5ngLZ49NUt8qa10xspap.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;solving-that-pesky-file-rename-in-git-with-apfs-volumes&#x2F;hZ6ABYkF5ngLZ49NUt8qa10xspap.png&quot; alt=&quot;Screenshot 2019-06-10 at 15.53.17.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Et Voilà! All filename changes are now getting picked up by &lt;code&gt;git status&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;asciinema.org&#x2F;a&#x2F;j22jhjqBkIstyWy24LVT8blyg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;asciinema.org&#x2F;a&#x2F;j22jhjqBkIstyWy24LVT8blyg.svg&quot; alt=&quot;asciicast&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Xcode 9 and Carthage - stripping out llvm instrument symbols</title>
        <published>2017-09-17T03:32:00+00:00</published>
        <updated>2017-09-17T03:32:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/xcode-9-and-carthage-coverage-data/"/>
        <id>https://karstx.net/xcode-9-and-carthage-coverage-data/</id>
        
        <content type="html" xml:base="https://karstx.net/xcode-9-and-carthage-coverage-data/">&lt;p&gt;Like any other year the new Xcode GM came out and everybody started rushing to submit their apps. This year, I was also one of these early adopters. Things were going relatively smoothly, except for a weird issue with &lt;code&gt;xattr&lt;&#x2F;code&gt; when trying to export archives. Regardless, I uploaded the build and was ready to see it processed... And then...&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-problem&quot;&gt;The Problem&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-problem&quot; aria-label=&quot;Anchor link for: the-problem&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;xcode-9-and-carthage-coverage-data&#x2F;ic3junrykhonww.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;xcode-9-and-carthage-coverage-data&#x2F;ic3junrykhonww.png&quot; alt=&quot;Screen Shot 2017-09-14 at 12.42.56.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Invalid Bundle&lt;&#x2F;strong&gt; - Disallowed LLVM instrumentation. Do not submit apps with LLVM profiling instrumentation or coverage collection enabled. Turn off LLVM profiling or code coverage, rebuild your app and resubmit the app.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;LLVM instrumentation? What? I thought that gets striped out on Archive?&lt;&#x2F;p&gt;
&lt;p&gt;Well it turns out, that it does get stripped out, but only for the main application. I use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Carthage&#x2F;Carthage&quot;&gt;Carthage&lt;&#x2F;a&gt; for dependency management and Carthage doesn&amp;#39;t build targets with the Archive action (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Carthage&#x2F;Carthage&#x2F;issues&#x2F;169#issuecomment-68624884&quot;&gt;or rather it can&amp;#39;t&lt;&#x2F;a&gt;) and Xcode 9 enables code coverage by default:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;xcode-9-and-carthage-coverage-data&#x2F;3sxvt5m7mcmzfq.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;xcode-9-and-carthage-coverage-data&#x2F;3sxvt5m7mcmzfq.png&quot; alt=&quot;Screen Shot 2017-09-14 at 19.03.43.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;&quot;&gt;The Solution?&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;code&gt;xcodebuild&lt;&#x2F;code&gt; flags don&amp;#39;t seem to affect this issue, meaning that every framework developer that makes their libraries available through Carthage will have to manually change this setting.&lt;&#x2F;p&gt;
&lt;p&gt;For the time being you&amp;#39;ll have to checkout all of the dependencies and manually change &lt;code&gt;CLANG_ENABLE_CODE_COVERAGE&lt;&#x2F;code&gt; to &lt;code&gt;NO&lt;&#x2F;code&gt; for every dependency before building them with &lt;code&gt;carthage build&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;-1&quot;&gt;Survival through Tooling&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;I&amp;#39;ve made &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;karstx&#x2F;9492d8e20938cfd1ee8163d7cdbfab9b&quot;&gt;a little script&lt;&#x2F;a&gt; that streamlines checking for LLVM instrument symbols. Change your working directory to the root of your project and you can pipe this script straight into bash (if you dare):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -fsSL https:&#x2F;&#x2F;gist.githubusercontent.com&#x2F;karstx&#x2F;9492d8e20938cfd1ee8163d7cdbfab9b&#x2F;raw&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hopefully we&amp;#39;ll see improvements in later versions of Xcode and &lt;code&gt;xcodebuild&lt;&#x2F;code&gt;, but for now we&amp;#39;ll have to live with this.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;-2&quot;&gt;Resources&lt;a class=&quot;zola-anchor&quot; href=&quot;#-2&quot; aria-label=&quot;Anchor link for: -2&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;library&#x2F;content&#x2F;qa&#x2F;qa1964&#x2F;_index.html#&#x2F;&#x2F;apple_ref&#x2F;doc&#x2F;uid&#x2F;DTS40017675-CH1-INSPECT&quot;&gt;Apple Developer Docs - Technical Q&amp;amp;A QA1964: Resolving App Rejections for GCC and LLVM Instrumentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Carthage&#x2F;Carthage&#x2F;issues&#x2F;2056&quot;&gt;GitHub Issues - Carthage - Targets built with coverage data in Xcode 9 #2056&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Reverse Hackintosh Pro</title>
        <published>2017-06-17T15:08:00+00:00</published>
        <updated>2017-06-17T15:08:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/reverse-hackintosh-pro/"/>
        <id>https://karstx.net/reverse-hackintosh-pro/</id>
        
        <content type="html" xml:base="https://karstx.net/reverse-hackintosh-pro/">&lt;p&gt;Well it&#x27;s been awhile, but I&#x27;m back to doing my own projects again.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;prelude&quot;&gt;Prelude&lt;a class=&quot;zola-anchor&quot; href=&quot;#prelude&quot; aria-label=&quot;Anchor link for: prelude&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;So lately I&#x27;ve been feeling left out of the gaming world and thought to myself: &quot;Hey why not build a sweet new gaming rig and jump right back into all of the fun?&quot;. Well, knowing myself I knew that after playing a couple of games, I would get bored and this rig won&#x27;t see much use after that.&lt;&#x2F;p&gt;
&lt;p&gt;To counteract that I need to be able to do work on it. But I&#x27;m an iOS developer and practically there&#x27;s only one platform that I can do my work on - macOS.&lt;&#x2F;p&gt;
&lt;p&gt;Alright, so it&#x27;s a Hackintosh then!&lt;&#x2F;p&gt;
&lt;p&gt;Apple hasn&#x27;t released significantly improved hardware for &quot;pros&quot; in years now, so this might actually be good timing to build one.&lt;&#x2F;p&gt;
&lt;p&gt;But let&#x27;s not make things too simple. Remember those older Mac Pros? The cheese graters? Those cases look awesome and sleek, wouldn&#x27;t it be awesome to build a pc in one of them? There&#x27;s other people doing it also? SIGN ME UP!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;vlfs0cslbsouw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;vlfs0cslbsouw.jpg&quot; alt=&quot;cheese-grater.JPG&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;&quot;&gt;Table of Contents&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;!-- toc --&gt;
&lt;h1 id=&quot;-1&quot;&gt;Build&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;After doing some research I found a guy in Berlin who sold me his broken 2016 Mac Pro for 50€. After taking it home I immediately stripped most of the parts from it and started looking for suitable components.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-2&quot;&gt;BOM&lt;a class=&quot;zola-anchor&quot; href=&quot;#-2&quot; aria-label=&quot;Anchor link for: -2&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I had simple requirements for the motherboard:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;It had to be Micro ATX form factor. So I wouldn&amp;#39;t have to cut the case to make room for a full ATX motherboard.&lt;&#x2F;li&gt;
&lt;li&gt;It had to have Thunderbolt compatibility, preferably Thunderbolt 2, so I could use my Thunderbolt display with it.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is what I ended up with:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Part&lt;&#x2F;th&gt;&lt;th&gt;Brand&lt;&#x2F;th&gt;&lt;th&gt;Name&lt;&#x2F;th&gt;&lt;th&gt;Quantity&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Motherboard&lt;&#x2F;td&gt;&lt;td&gt;GIGABYTE&lt;&#x2F;td&gt;&lt;td&gt;GA-Z170MX-Gaming 5&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CPU&lt;&#x2F;td&gt;&lt;td&gt;Intel&lt;&#x2F;td&gt;&lt;td&gt;Core™ i7-6700K&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GPU&lt;&#x2F;td&gt;&lt;td&gt;EVGA&lt;&#x2F;td&gt;&lt;td&gt;GeForce GTX 980 Ti HYBRID GAMING&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RAM&lt;&#x2F;td&gt;&lt;td&gt;Corsair&lt;&#x2F;td&gt;&lt;td&gt;Vengeance® LPX 32GB (4 x 8GB) DDR4 DRAM 2400MHz&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;M2&lt;&#x2F;td&gt;&lt;td&gt;Samsung&lt;&#x2F;td&gt;&lt;td&gt;950 PRO M.2 256GB&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SATA&lt;&#x2F;td&gt;&lt;td&gt;Samsung&lt;&#x2F;td&gt;&lt;td&gt;850-EVO 500GB&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PCIE&lt;&#x2F;td&gt;&lt;td&gt;AsRock&lt;&#x2F;td&gt;&lt;td&gt;Thunderbolt™ 2 AIC&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PCIE&lt;&#x2F;td&gt;&lt;td&gt;Wdxxfu Studio Design&lt;&#x2F;td&gt;&lt;td&gt;BCM943602CS (WIFI+BT)&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PSU&lt;&#x2F;td&gt;&lt;td&gt;EVGA&lt;&#x2F;td&gt;&lt;td&gt;850 GQ Power Supply&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CPU Cooler&lt;&#x2F;td&gt;&lt;td&gt;Alpenföhn&lt;&#x2F;td&gt;&lt;td&gt;Ben Nevis&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Case Fan&lt;&#x2F;td&gt;&lt;td&gt;Noctua&lt;&#x2F;td&gt;&lt;td&gt;NF-S12B redux-700&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Case Fan&lt;&#x2F;td&gt;&lt;td&gt;Noctua&lt;&#x2F;td&gt;&lt;td&gt;NF-S12B redux-1200&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MISC&lt;&#x2F;td&gt;&lt;td&gt;NewerTech&lt;&#x2F;td&gt;&lt;td&gt;AdaptaDrive&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;irj7mosz2bjiea.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;irj7mosz2bjiea.jpg&quot; alt=&quot;bom.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-3&quot;&gt;Hardware&lt;a class=&quot;zola-anchor&quot; href=&quot;#-3&quot; aria-label=&quot;Anchor link for: -3&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;-4&quot;&gt;mATX Motherboard Tray&lt;a class=&quot;zola-anchor&quot; href=&quot;#-4&quot; aria-label=&quot;Anchor link for: -4&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I went and got the mATX kit from &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.thelaserhive.com&#x2F;product&#x2F;mac-pro-matx-120-kit&#x2F;&quot;&gt;the laser hive&lt;&#x2F;a&gt; (plastic grill version). They provide pretty comprehensive instructions with the kit, so inserting and fastening the tray was a breeze. Cutting out and the back and attaching the back panel wasn&amp;#39;t too hard either.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;2ixet7kyer79a.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;2ixet7kyer79a.jpg&quot; alt=&quot;empty-case.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;yyrnypby6d6rq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;yyrnypby6d6rq.jpg&quot; alt=&quot;back-stripped.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-5&quot;&gt;Power Supply&lt;a class=&quot;zola-anchor&quot; href=&quot;#-5&quot; aria-label=&quot;Anchor link for: -5&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;The PSU was probably one of the components that I had to do the most work on in order to get it inside the case.&lt;&#x2F;p&gt;
&lt;p&gt;At first I thought I could stick in the internals of a standard power supply into the case of the original Mac Pro PSU. However, that didn&amp;#39;t work out because the PSU would overheat after a few minutes under intense load. I had to scrap the original PSU I had bought and get another one.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;m5qomtedsseow.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;m5qomtedsseow.jpg&quot; alt=&quot;psu-oem.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;-6&quot;&gt;Cable&lt;a class=&quot;zola-anchor&quot; href=&quot;#-6&quot; aria-label=&quot;Anchor link for: -6&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;I wanted to reuse the original AC port, so I had to make a little low profile adapter to solve the different placement of the cable port.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;vjjlmpmygwoz1q.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;vjjlmpmygwoz1q.jpg&quot; alt=&quot;psu-cable-front.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;rdmcatkv3z6sq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;rdmcatkv3z6sq.jpg&quot; alt=&quot;psu-cable-back.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;ickhzmms8il1q.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;ickhzmms8il1q.jpg&quot; alt=&quot;psu-connection-closeup.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;-7&quot;&gt;Case&lt;a class=&quot;zola-anchor&quot; href=&quot;#-7&quot; aria-label=&quot;Anchor link for: -7&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;I had to cut off one end of the original PSU case in order for it to house the new longer PSU. I also had to remove the PSU fan assembly from the case to fit the new PSU.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;adzbhnvjyubsw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;adzbhnvjyubsw.jpg&quot; alt=&quot;psu-case.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;lwiowvar0qzhyg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;lwiowvar0qzhyg.jpg&quot; alt=&quot;psu-tray-cutoff.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;vgfjnnyyvabsba.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;vgfjnnyyvabsba.jpg&quot; alt=&quot;psu-connection.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;xtzoae7ocmcpgg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;xtzoae7ocmcpgg.jpg&quot; alt=&quot;psu-assembled.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-8&quot;&gt;Front Panel&lt;a class=&quot;zola-anchor&quot; href=&quot;#-8&quot; aria-label=&quot;Anchor link for: -8&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I wanted to reuse the Mac Pros front panel interface. To do that neatly I had to make a couple PCBs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;3oikcvg9eybdq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;3oikcvg9eybdq.jpg&quot; alt=&quot;12pin-adapter-pcb.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;gc2g1vzdp4uhva.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;gc2g1vzdp4uhva.jpg&quot; alt=&quot;usb-adapter-pcb.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The designs for these PCBs are free and available on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;karstx&#x2F;mac-pro-conversion&quot;&gt;GitHub&lt;&#x2F;a&gt;, you can use any PCB manufacturing service to make these, but I personally prefer &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;oshpark.com&#x2F;&quot;&gt;OSH Park&lt;&#x2F;a&gt; for prototypes.&lt;&#x2F;p&gt;
&lt;p&gt;Here are the adapters in action:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;it9goyyx18yfq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;it9goyyx18yfq.jpg&quot; alt=&quot;usb-adapter-in-action.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;9whphqhnbhaaw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;9whphqhnbhaaw.jpg&quot; alt=&quot;12pin-adapter-pcb-in-action.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;oscndcpxp67yq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;oscndcpxp67yq.jpg&quot; alt=&quot;front-panel-pcb.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;One important note:&lt;&#x2F;strong&gt; the original 8 pin Micro-FIT cable that caries power for the panel from the original motherboard has it&amp;#39;s pins mirrored on both ends. The pcb is designed for that cable, so you should be good if you use it. However, if you&amp;#39;re making your own adapter, please check which pin on one end corresponds to what pin on the other end.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-9&quot;&gt;SATA&lt;a class=&quot;zola-anchor&quot; href=&quot;#-9&quot; aria-label=&quot;Anchor link for: -9&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;The SATA slots in the mac pro are pretty frigging cool, I wanted to make them functional with the new motherboard. Fortunately this was pretty easy (but pricey). I had to buy &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.maxupgrades.com&#x2F;istore&#x2F;index.cfm?fuseaction=product.display&amp;amp;product_ID=330&amp;amp;ParentCat=332&quot;&gt;this adapter&lt;&#x2F;a&gt;. Making one doesn&amp;#39;t make sense as the parts themselves cost almost as much as this fully build adapter.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;ba9jkpmignshq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;ba9jkpmignshq.jpg&quot; alt=&quot;scsi-adapter.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;orzkkspssxgzcw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;orzkkspssxgzcw.jpg&quot; alt=&quot;scsi-adapter-with-sata.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;vofbqzldrzxw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;vofbqzldrzxw.jpg&quot; alt=&quot;scsi-adapter-in-action.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The drawers obviously also need SATA power, so I had to make a little adapter from the PSU to the custom apple connector. Sadly, I did not take a picture of it, and it&amp;#39;s pretty deep in the case to remove it.&lt;&#x2F;p&gt;
&lt;p&gt;As there&amp;#39;s not too many reasons to go with a mechanical hard drive and SATA SSDs only come in 2.5&amp;quot; I had to buy a few 3.5&amp;quot; to 2.5&amp;quot; adapters. There are plenty of these available to buy on Amazon.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-10&quot;&gt;Front Fan Assembly&lt;a class=&quot;zola-anchor&quot; href=&quot;#-10&quot; aria-label=&quot;Anchor link for: -10&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Because of a very nice deal, I got an air-cooled, water-cooled hybrid GPU. One problem is that it comes with a gigantic radiator that needs to go somewhere in the case. Fortunately the original fan assembly was ideal for this. Just after a few modifications to (with a handy dremel) it I could easily hold the radiator and fan on top of it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;cworxxwnziszg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;cworxxwnziszg.jpg&quot; alt=&quot;fan-assembly-back.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;arnyygt280haqg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;arnyygt280haqg.jpg&quot; alt=&quot;fan-assembly-front.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;euisgplvzl6q.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;euisgplvzl6q.jpg&quot; alt=&quot;gpu-fan-assembly.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-11&quot;&gt;Wifi&lt;a class=&quot;zola-anchor&quot; href=&quot;#-11&quot; aria-label=&quot;Anchor link for: -11&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;After some research, it became obvious that the best WIFI adapter for macOS is an original one. Fortunately for me, China if full of them. I got mine from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;world.taobao.com&#x2F;item&#x2F;38195333521.htm?fromSite=main&amp;amp;spm=a230r.1.0.0.M8souu&quot;&gt;TaoBao&lt;&#x2F;a&gt;. No additional steps needed to get WI-FI working. Although iMessage is another story...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;sfcoeatsoebc2g.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;sfcoeatsoebc2g.jpg&quot; alt=&quot;wifi.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-12&quot;&gt;Thunderbolt&lt;a class=&quot;zola-anchor&quot; href=&quot;#-12&quot; aria-label=&quot;Anchor link for: -12&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I wanted to use my Apple Thunderbolt Display with this machine, so thunderbolt support was imperative.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;h2msvivladnqlg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;h2msvivladnqlg.jpg&quot; alt=&quot;thunderbolt.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;However macOS support for third party controllers is very... very... flaky. I had different levels of success, but nothing came close to being truly stable. Either the displays USB hub wouldn&amp;#39;t work, or daisy chaining a hard drive wouldn&amp;#39;t work, or the display wouldn&amp;#39;t turn on in general. You can get it to work though and that&amp;#39;s good enough for now.&lt;&#x2F;p&gt;
&lt;p&gt;The controller itself wouldn&amp;#39;t ever get recognized by System Information, although it&amp;#39;s children peripherals would show up as if they&amp;#39;re hooked in directly in the system.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-13&quot;&gt;Back Fan&lt;a class=&quot;zola-anchor&quot; href=&quot;#-13&quot; aria-label=&quot;Anchor link for: -13&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I had to cut off sides of the original backside fan grill in order to make it fit with the ATX motherboard backplate. But the amount of flat plastic surface left is enough to drill holes into the other side of the grill and attach the actual new fan to itself.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;7ofbcld3rk4bsg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;7ofbcld3rk4bsg.jpg&quot; alt=&quot;back-fan-back.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;bjgg7o3ampac2a.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;bjgg7o3ampac2a.jpg&quot; alt=&quot;back-fan-front.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-14&quot;&gt;Other Pictures&lt;a class=&quot;zola-anchor&quot; href=&quot;#-14&quot; aria-label=&quot;Anchor link for: -14&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;pcrkonxob92j3g.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;pcrkonxob92j3g.jpg&quot; alt=&quot;finished.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;jhwqlc8pszpnq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;jhwqlc8pszpnq.jpg&quot; alt=&quot;drawer-out.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;itibyi2498boew.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;itibyi2498boew.jpg&quot; alt=&quot;case-backside.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;qn5kitdqf2nxla.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;qn5kitdqf2nxla.jpg&quot; alt=&quot;items.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;fqffuoienz1yw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;fqffuoienz1yw.jpg&quot; alt=&quot;case-backside-front.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-15&quot;&gt;Software&lt;a class=&quot;zola-anchor&quot; href=&quot;#-15&quot; aria-label=&quot;Anchor link for: -15&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;-16&quot;&gt;BIOS Options&lt;a class=&quot;zola-anchor&quot; href=&quot;#-16&quot; aria-label=&quot;Anchor link for: -16&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Before installing macOS it&amp;#39;s important to change a few BIOS settings from their default values:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Enable XHCI Handoff (important for USB to work)&lt;&#x2F;li&gt;
&lt;li&gt;Disable Serial IO&lt;&#x2F;li&gt;
&lt;li&gt;Enable Thunderbolt
&lt;ul&gt;
&lt;li&gt;Security: Legacy&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;-17&quot;&gt;Installation, Clover&lt;a class=&quot;zola-anchor&quot; href=&quot;#-17&quot; aria-label=&quot;Anchor link for: -17&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I used &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.tonymacx86.com&#x2F;resources&#x2F;categories&#x2F;tonymacx86-downloads.3&#x2F;&quot;&gt;UniBeast&lt;&#x2F;a&gt; to install macOS and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.tonymacx86.com&#x2F;resources&#x2F;categories&#x2F;tonymacx86-downloads.3&#x2F;&quot;&gt;MultiBeast&lt;&#x2F;a&gt; to configure all the options, injected kexts and etc. There are a number of guides on the web that cover this hardware, and some of the options depends on taste, so I won&amp;#39;t cover them here.&lt;&#x2F;p&gt;
&lt;p&gt;It&amp;#39;s generally a good idea to have the latest version of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sourceforge.net&#x2F;projects&#x2F;cloverefiboot&#x2F;&quot;&gt;Clover&lt;&#x2F;a&gt; installed. Multibeast usually comes with a version that&amp;#39;s stable, but pretty outdated.&lt;&#x2F;p&gt;
&lt;p&gt;A very helpful tool if you don&amp;#39;t want to deal with plists all the time when tweaking your Clover settings is the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;mackie100projects.altervista.org&#x2F;download-clover-configurator&#x2F;&quot;&gt;Clover Configurator&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-18&quot;&gt;iMessage, iCloud, App Store&lt;a class=&quot;zola-anchor&quot; href=&quot;#-18&quot; aria-label=&quot;Anchor link for: -18&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;This is probably what gives people the most headaches in getting their hackintoshes fully working. I used a couple techniques to get this finally working.&lt;&#x2F;p&gt;
&lt;p&gt;I had success in following &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.fitzweekly.com&#x2F;2016&#x2F;02&#x2F;hackintosh-imessage-tutorial.html&quot;&gt;this guide&lt;&#x2F;a&gt;. But before I got everything working, I had my Apple ID account locked multiple times, so beware! It&amp;#39;s no big deal of course, you just need to come up with a new password every time, but it&amp;#39;s SEVERELY ANNOYING.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-19&quot;&gt;NVMe Storage&lt;a class=&quot;zola-anchor&quot; href=&quot;#-19&quot; aria-label=&quot;Anchor link for: -19&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;To get the NVMe storage drive to work (including installing macOS on that drive) I just used RehabMan&amp;#39;s wonderful &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RehabMan&#x2F;patch-nvme&quot;&gt;kext patches&lt;&#x2F;a&gt;. He has very comprehensive instructions on what needs to be done.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-20&quot;&gt;GPU&lt;a class=&quot;zola-anchor&quot; href=&quot;#-20&quot; aria-label=&quot;Anchor link for: -20&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Getting the GPU to work is pretty straightforward. All I had to do is install the latest &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.tonymacx86.com&#x2F;nvidia-drivers&#x2F;&quot;&gt;NVIDIA Web Drivers&lt;&#x2F;a&gt;. And making sure that the clover flag to use them is set &amp;quot;nvda_drv=1&amp;quot;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;-21&quot;&gt;Other Stuff&lt;a class=&quot;zola-anchor&quot; href=&quot;#-21&quot; aria-label=&quot;Anchor link for: -21&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;Like any project, this one has it&amp;#39;s share of notes and fails. Here&amp;#39;s a few of them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-22&quot;&gt;Original Build&lt;a class=&quot;zola-anchor&quot; href=&quot;#-22&quot; aria-label=&quot;Anchor link for: -22&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This is what I had planned to use initially:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Part&lt;&#x2F;th&gt;&lt;th&gt;Brand&lt;&#x2F;th&gt;&lt;th&gt;Name&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Motherboard&lt;&#x2F;td&gt;&lt;td&gt;AsRock&lt;&#x2F;td&gt;&lt;td&gt;Fatal1ty X99M Killer&#x2F;3.1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CPU&lt;&#x2F;td&gt;&lt;td&gt;Intel&lt;&#x2F;td&gt;&lt;td&gt;Core™ i7-6800K&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GPU&lt;&#x2F;td&gt;&lt;td&gt;EVGA&lt;&#x2F;td&gt;&lt;td&gt;GeForce GTX 980 Ti HYBRID GAMING&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RAM&lt;&#x2F;td&gt;&lt;td&gt;Corsair&lt;&#x2F;td&gt;&lt;td&gt;Vengeance® LPX 32GB (4 x 8GB) DDR4 DRAM 2400MHz&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Drive&lt;&#x2F;td&gt;&lt;td&gt;Samsung&lt;&#x2F;td&gt;&lt;td&gt;950 PRO M.2 256GB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PCIE&lt;&#x2F;td&gt;&lt;td&gt;AsRock&lt;&#x2F;td&gt;&lt;td&gt;Thunderbolt™ 2 AIC&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PSU&lt;&#x2F;td&gt;&lt;td&gt;EVGA&lt;&#x2F;td&gt;&lt;td&gt;850 GQ Power Supply&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CPU Cooler&lt;&#x2F;td&gt;&lt;td&gt;Alpenföhn&lt;&#x2F;td&gt;&lt;td&gt;Ben Nevis&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Case Fans&lt;&#x2F;td&gt;&lt;td&gt;Noctua&lt;&#x2F;td&gt;&lt;td&gt;2x NF-S12B redux-700 + 1x NF-S12B redux-1200&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;-23&quot;&gt;Chipset &amp;amp; Thunderbolt&lt;a class=&quot;zola-anchor&quot; href=&quot;#-23&quot; aria-label=&quot;Anchor link for: -23&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Now I know what you&amp;#39;re thinking. X99? That&amp;#39;s going to be a pain to install macOS on, if possible at all. And, well you&amp;#39;re right, but the reason I picked the Fatal1ty X99M Killer was because that was the only Micro ATX board with thunderbolt a capability and AsRock had it&amp;#39;s AIC card for sale. In comparison Gigabyte had a Z170 Micro ATX motherboard with a Thunderbolt header, but Gigabytes AIC card wasn&amp;#39;t being sold ANYWHERE. Only later did I find out that most of these thunderbolt cards are intercompatible between different brands...&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;X99 support proved to be to difficult, and the interchangeability of the thunderbolt cards pushed me to use Z170 instead.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-24&quot;&gt;Standoffs&lt;a class=&quot;zola-anchor&quot; href=&quot;#-24&quot; aria-label=&quot;Anchor link for: -24&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;In order to stuff some components in and connect others I had to make some modifications to the case. The first of these modifications was to remove the existing motherboard standoffs. This was fairly simple, you can remove the standoffs with pliers or a hammer. The next step was to to glue my own standoffs with epoxy, I did it by screwing in all of the standoffs to the motherboard and then covering their bottom ends with a small layer of epoxy, I put the motherboard into the case and aligned it, waited for some time and then undid the screws and took out the motherboard, I covered the base of the standoffs with more epoxy around them to secure them in place. You need to be careful when screwing your motherboard back in, because even though the epoxy has a pretty firm grip on the standoffs you can still break them off with enough force when screwing in the screws.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;After breaking a few of them, and ultimately needing the back facing IO ports more than I expected I got a ATX conversion kit from lazer hive.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-25&quot;&gt;The Perfect Build&lt;a class=&quot;zola-anchor&quot; href=&quot;#-25&quot; aria-label=&quot;Anchor link for: -25&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Before doing this project I did some research on already existing builds. One build I found was absolutely amazing.&lt;&#x2F;p&gt;
&lt;p&gt;Skin008 - a Chinese electrical engineer and serial mac pro modder, made a one of a kind mac pro retrofit kit that reuses the same ports on the original 2008 and 2010 macs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;jjqpu8ly9azjow.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;jjqpu8ly9azjow.jpg&quot; alt=&quot;skin008-board.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;q0yltbzvuc0kw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;karstx.net&#x2F;reverse-hackintosh-pro&#x2F;q0yltbzvuc0kw.jpg&quot; alt=&quot;skin008-case.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I reached out to him, but found out that he only did 10 of these boards, sold them and was too busy with his personal stuff to make new ones this year. He did mention however that he may do another batch next year. I hope that’s true and I’ll try to keep in touch with him. You can find more pictures of his boards showcased &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;acidluna.tistory.com&#x2F;295&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Convenient Dependency Injection in Swift</title>
        <published>2015-10-17T05:09:00+00:00</published>
        <updated>2015-10-17T05:09:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/convenient-di-in-swift/"/>
        <id>https://karstx.net/convenient-di-in-swift/</id>
        
        <content type="html" xml:base="https://karstx.net/convenient-di-in-swift/">&lt;p&gt;Ever since Swift 1.0 was released, I have been struggling with finding a way to introduce some proper dependency injection into my code. The previous methods that were popular in objective-C like Swizzling or property overloading no longer works or require far too many changes to your code to make them actually worth it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;natashatherobot&quot;&gt;Natasha Murashev&lt;&#x2F;a&gt; posted some nice ideas about dependency injection through default property values in functions, you can read more about that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20151113113136&#x2F;http:&#x2F;&#x2F;natashatherobot.com&#x2F;unit-testing-swift-dependency-injection&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But there&#x27;s one problem with this solution, the default values require that the concrete implementation be dragged in and linked with your testing target, and that might be something that you don&#x27;t want to do.&lt;&#x2F;p&gt;
&lt;p&gt;Today I bring you a way to solve these issues: by using default property values, (convenience) initilizers and type extensions to introduce some really convenient dependency injection.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-example&quot;&gt;The Example&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-example&quot; aria-label=&quot;Anchor link for: the-example&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;Let&#x27;s start with the dependant type:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public struct&lt;&#x2F;span&gt;&lt;span&gt; Farm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private let&lt;&#x2F;span&gt;&lt;span&gt; animals:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;&#x2F;span&gt;&lt;span&gt;Animal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    init&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;animals&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Animal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span&gt;.animals&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; animals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; feedAnimals&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span&gt; animals.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; $0&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;feed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Farm houses a bunch of generic animals, &lt;code&gt;Animal&lt;&#x2F;code&gt; is just a protocol for our dependencies - the actual farm animals. Here&#x27;s the protocol itself:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public protocol&lt;&#x2F;span&gt;&lt;span&gt; Animal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; feed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let&#x27;s add some concrete implementations of this protocol that we&#x27;ll use in our production app:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public struct&lt;&#x2F;span&gt;&lt;span&gt; Cow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; Animal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; feed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Moooo!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Duck&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; Animal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; feed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Quack!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We ended up with a fully testable &lt;code&gt;Farm&lt;&#x2F;code&gt; type which we can use in our application by passing the right set of dependencies:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Farm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;animals&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Cow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Duck&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But &lt;em&gt;DI&lt;&#x2F;em&gt; isn&#x27;t really &lt;em&gt;DI&lt;&#x2F;em&gt; unless you don&#x27;t have to care about what you&#x27;re passing to the constructor in your actual use case.&lt;&#x2F;p&gt;
&lt;p&gt;This is where class extensions come in. With Swift we can extend &lt;em&gt;classes&lt;&#x2F;em&gt; with convenience initializers and &lt;em&gt;structs&lt;&#x2F;em&gt; with just regular initializers wherever we like! So to do that create a separate swift file to house your DI initializers (you need to keep this in a different file to include it in your application and exclude it form your testing target, so you don&#x27;t include the whole dependency tree for the type you&#x27;re testing). In this file we would have:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;extension&lt;&#x2F;span&gt;&lt;span&gt; Farm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    init&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;init&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;animals&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Cow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Duck&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since this is a swift extension, we can have whatever we want here, even returning a singleton instance of the interface you want to use. To put it simply: you&#x27;re only limited by Swift itself when it comes to deciding how you want your dependencies executed and your dependency tree handled. For the sake of this example I chose to use the most simple case.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;on-to-the-tests&quot;&gt;On to the Tests!&lt;a class=&quot;zola-anchor&quot; href=&quot;#on-to-the-tests&quot; aria-label=&quot;Anchor link for: on-to-the-tests&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;Now we want to unit test the Farm struct. We didn&#x27;t import the source file that contains conveniences and the dependency tree, so we don&#x27;t have to import types for &lt;code&gt;Cow&lt;&#x2F;code&gt; and &lt;code&gt;Duck&lt;&#x2F;code&gt;. Instead let&#x27;s create a new mock type for our &lt;code&gt;Animal&lt;&#x2F;code&gt; protocol and execute the test with that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; TestAnimal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; Animal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; feed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;This isn&amp;#39;t an actual animal, it&amp;#39;s just a test&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; InjectTests&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; XCTestCase&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; testFeeding&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; farm &lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Farm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;animals&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;TestAnimal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; result &lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; farm.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;feedAnimals&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        XCTAssertEqual&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;result, [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;This is not an actual animal, it&amp;#39;s just a test&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And here you go, a fully contained and convenient dependency injection method, that works without the need of any framework, objective-c code, var&#x27;s (instead of lets) or dynamism (instead of static dispatch).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;project-source&quot;&gt;Project Source&lt;a class=&quot;zola-anchor&quot; href=&quot;#project-source&quot; aria-label=&quot;Anchor link for: project-source&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;del&gt;I&#x27;ve made a simple iOS project as a proof of concept for this: download&lt;&#x2F;del&gt; the project is out of date and no longer hosted&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Linking OpenSSL for the iOS Simulator (1.0.2a)</title>
        <published>2015-04-26T13:56:00+00:00</published>
        <updated>2015-04-26T13:56:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://karstx.net/ios-openssl-support/"/>
        <id>https://karstx.net/ios-openssl-support/</id>
        
        <content type="html" xml:base="https://karstx.net/ios-openssl-support/">&lt;h1 id=&quot;intro&quot;&gt;Intro&lt;a class=&quot;zola-anchor&quot; href=&quot;#intro&quot; aria-label=&quot;Anchor link for: intro&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;I&#x27;ve been doing some work with a fair amount of crypto for an my upcoming application. Now as you all probably know, the go-to for doing any crypto is with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.openssl.org&#x2F;&quot;&gt;OpenSSL&lt;&#x2F;a&gt;. I&#x27;m not much of a hipster, so I immediately went with that.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-good&quot;&gt;The Good&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-good&quot; aria-label=&quot;Anchor link for: the-good&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;x2on&quot;&gt;x2on&lt;&#x2F;a&gt;&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;x2on&#x2F;OpenSSL-for-iPhone&quot;&gt;OpenSSL-for-iPhone&lt;&#x2F;a&gt; is an excellent tool of convenience. It downloads the latest version of OpenSSL, builds both libssl and libcrypto for all available architectures and glues all slices into one universal library each. It even comes with a script to generate &lt;code&gt;openssl.framework&lt;&#x2F;code&gt; from the resulting libraries.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-bad&quot;&gt;The Bad&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-bad&quot; aria-label=&quot;Anchor link for: the-bad&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;The resulting framework runs great on any device, sadly, the linker just didn&#x27;t want to link for the simulator. The linker spewing:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Undefined symbols for architecture x86_64:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;_OPENSSL_ia32cap_P&amp;quot;, referenced from:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      _AES_cbc_encrypt in openssl(aes-x86_64.o)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ld: symbol(s) not found for architecture x86_64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;clang: error: linker command failed with exit code 1 (use -v to see invocation)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I was at a complete loss, as I hadn&#x27;t referenced anything of the like. In my code at least. But a bit more digging revealed the culprit.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;and-the-de-uglyfied&quot;&gt;And the de-uglyfied&lt;a class=&quot;zola-anchor&quot; href=&quot;#and-the-de-uglyfied&quot; aria-label=&quot;Anchor link for: and-the-de-uglyfied&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;It turns out this is a bug in the generated code for x86_84. The linker doesn&#x27;t know that the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;openssl&#x2F;openssl&#x2F;blob&#x2F;e0fc7961c4fbd27577fb519d9aea2dc788742715&#x2F;crypto&#x2F;aes&#x2F;asm&#x2F;aes-x86_64.pl#L1651&quot;&gt;_OPENSSL_ia32cap_P&lt;&#x2F;a&gt; external symbol needs to be linked in from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;openssl&#x2F;openssl&#x2F;blob&#x2F;e0fc7961c4fbd27577fb519d9aea2dc788742715&#x2F;crypto&#x2F;x86_64cpuid.pl#L26&quot;&gt;x86_64cpuid.o&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We can force this by referencing another method that&#x27;s in &lt;code&gt;x86_64cpuid.o&lt;&#x2F;code&gt;, like &lt;code&gt;OPENSSL_cleanse(void *, size_t)&lt;&#x2F;code&gt;. I did like so:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#if TARGET_IPHONE_SIMULATOR&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; this is just so openssl links properly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    extern int OPENSSL_cleanse(void *ptr, size_t len);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    OPENSSL_cleanse(nil, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pasting the following anywhere in your code (that won&#x27;t be discarded by compiler optimizations) should work.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-end&quot;&gt;The End?&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-end&quot; aria-label=&quot;Anchor link for: the-end&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;I&#x27;m hoping that this will get resolved in the future. If not as a mainline release, then at least as a publicly available patch. But until then, I guess we&#x27;re stuck with this.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
