<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>carlossless</title>
    <subtitle>I make things and then write about them</subtitle>
    <link rel="self" type="application/atom+xml" href="https://carlossless.io/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://carlossless.io"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-03-01T00:00:00+00:00</updated>
    <id>https://carlossless.io/atom.xml</id>
    <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://carlossless.io/stm32-rdp1-decryptor/"/>
        <id>https://carlossless.io/stm32-rdp1-decryptor/</id>
        
        <content type="html" xml:base="https://carlossless.io/stm32-rdp1-decryptor/">&lt;p&gt;Recently while browsing &lt;a 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 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;carlossless.io&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;xianyu-listing.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;xianyu-listing.d44a82aa6be1f02e.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;xianyu-listing.c2b8c2fb46c352cb.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;carlossless.io&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;kit-layout.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;kit-layout.aa072b1f31c4a064.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;kit-layout.f73b1a93c374354f.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;carlossless.io&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;usb-dongle.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;usb-dongle.85704b2a03d345b7.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;usb-dongle.21e975e5866d4248.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;carlossless.io&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;adapter-board-connected.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;adapter-board-connected.317987499e585679.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;adapter-board-connected.12f6dd29936aa8bc.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;carlossless.io&#x2F;stm32-rdp1-decryptor&#x2F;.&#x2F;decryptor-utility.png&quot;&gt;
    
        
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;decryptor-utility.0c4226949961c343.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 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 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 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 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://carlossless.io/racknex-lp5012-leds/"/>
        <id>https://carlossless.io/racknex-lp5012-leds/</id>
        
        <content type="html" xml:base="https://carlossless.io/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 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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#x2F;qwiic-hat&quot;&gt;hats&lt;&#x2F;a&gt; that I made to expose i2c via two &lt;a 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 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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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;carlossless.io&#x2F;rpi-cluster-at-home&#x2F;front.jpg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;front.a4d2324c154115ac.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;front.8117140fc7af0210.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 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 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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 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;carlossless.io&#x2F;racknex-lp5012-leds&#x2F;.&#x2F;pcb-front.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;pcb-front.f65966c3b01a5f1f.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;pcb-front.decfc0540531f9e0.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;carlossless.io&#x2F;racknex-lp5012-leds&#x2F;pcb-back.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;pcb-back.7d63424e4a4c8520.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;pcb-back.984141c89a7f645b.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 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;

            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;carlossless.io&#x2F;racknex-lp5012-leds&#x2F;bracket-front.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;bracket-front.2c8ccda726452b33.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;bracket-front.b311c7a07082fdc7.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;carlossless.io&#x2F;racknex-lp5012-leds&#x2F;bracket-back.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;bracket-back.68ebb94732a38587.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;bracket-back.3e4ada3122d863b7.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 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;carlossless.io&#x2F;racknex-lp5012-leds&#x2F;bracked-light-pipe.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;bracked-light-pipe.d699380261b24836.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;bracked-light-pipe.6a6887c738373b0c.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 data-lang=&quot;dts&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-dts &quot;&gt;&lt;code class=&quot;language-dts&quot; data-lang=&quot;dts&quot;&gt;&lt;span&gt;&#x2F;dts-v1&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;plugin&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#include &amp;lt;dt-bindings&#x2F;leds&#x2F;common.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;  compatible = &amp;quot;brcm,bcm2711&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  fragment@0 {
&lt;&#x2F;span&gt;&lt;span&gt;    target = &amp;lt;&amp;amp;i2c1&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    i2c_bus: __overlay__ {
&lt;&#x2F;span&gt;&lt;span&gt;      led-controller@14 {
&lt;&#x2F;span&gt;&lt;span&gt;        compatible = &amp;quot;ti,lp5012&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;        reg = &amp;lt;0x14&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        #address-cells = &amp;lt;1&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        #size-cells = &amp;lt;0&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        multi-led@0 {
&lt;&#x2F;span&gt;&lt;span&gt;          #address-cells = &amp;lt;1&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          #size-cells = &amp;lt;0&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          reg = &amp;lt;0&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          color = &amp;lt;LED_COLOR_ID_RGB&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          function = LED_FUNCTION_POWER;
&lt;&#x2F;span&gt;&lt;span&gt;          default-state = &amp;quot;off&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;          linux,default-trigger = &amp;quot;default-on&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;          max-brightness = &amp;lt;127&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          led@0 {
&lt;&#x2F;span&gt;&lt;span&gt;            reg = &amp;lt;0&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            color = &amp;lt;LED_COLOR_ID_RED&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          led@1 {
&lt;&#x2F;span&gt;&lt;span&gt;            reg = &amp;lt;1&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            color = &amp;lt;LED_COLOR_ID_GREEN&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          led@2 {
&lt;&#x2F;span&gt;&lt;span&gt;            reg = &amp;lt;2&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            color = &amp;lt;LED_COLOR_ID_BLUE&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          };
&lt;&#x2F;span&gt;&lt;span&gt;        };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        multi-led@1 {
&lt;&#x2F;span&gt;&lt;span&gt;          ...
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        ...
&lt;&#x2F;span&gt;&lt;span&gt;      };
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;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 data-lang=&quot;nix&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;{}: {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;systemd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;lp5012-intensity &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;wantedBy &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;quot;multi-user.target&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;];
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;serviceConfig &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;Type &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;quot;oneshot&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;User &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;quot;root&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;Group &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;quot;root&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;RemainAfterExit &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    };
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;script &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;      if [ -d &#x2F;sys&#x2F;class&#x2F;leds&#x2F;rgb:power ]; then
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&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;span style=&quot;color:#ffd700;&quot;&gt;      fi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;      ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;    &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;  };
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&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 href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;carlossless&#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;carlossless.io&#x2F;racknex-lp5012-leds&#x2F;racknex-rpi-top.jpeg&quot;&gt;
    
        
            
            
            &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;racknex-rpi-top.88eed664e83a7821.jpg&quot; srcset=&quot;https:&amp;#x2F;&amp;#x2F;carlossless.io&amp;#x2F;processed_images&amp;#x2F;racknex-rpi-top.d3f558ece341ffb4.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;carlossless.io&#x2F;racknex-lp5012-leds&#x2F;racknex-front-leds.gif&quot;&gt;
    
        &lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#x2F;qwiic-hat&quot;&gt;qwiic-hat&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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://carlossless.io/nuphy-air60-part-2/"/>
        <id>https://carlossless.io/nuphy-air60-part-2/</id>
        
        <content type="html" xml:base="https://carlossless.io/nuphy-air60-part-2/">&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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 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 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 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 href=&quot;https:&#x2F;&#x2F;sdcc.sourceforge.net&#x2F;&quot;&gt;SDCC&lt;&#x2F;a&gt; here, instead of the proprietary &lt;a 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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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;carlossless.io&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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://carlossless.io/nuphy-air60/"/>
        <id>https://carlossless.io/nuphy-air60/</id>
        
        <content type="html" xml:base="https://carlossless.io/nuphy-air60/">&lt;p&gt;Not too long ago, I got a &lt;a 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;carlossless.io&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;komar007&#x2F;gh60&quot;&gt;GH60&lt;&#x2F;a&gt; with &lt;a 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;carlossless.io&#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 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 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 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 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;carlossless.io&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gashtaan&quot;&gt;@gashtaan&lt;&#x2F;a&gt; for the dumper and &lt;a 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://carlossless.io/nix-rpi-poe-plus-hat/"/>
        <id>https://carlossless.io/nix-rpi-poe-plus-hat/</id>
        
        <content type="html" xml:base="https://carlossless.io/nix-rpi-poe-plus-hat/">&lt;p&gt;As previously mentioned in &lt;a href=&quot;https:&#x2F;&#x2F;carlossless.io&#x2F;rpi-cluster-at-home&#x2F;&quot;&gt;my last post&lt;&#x2F;a&gt;, I&#x27;ve been using &lt;a 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 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 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 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 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 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 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 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://carlossless.io/rpi-cluster-at-home/"/>
        <id>https://carlossless.io/rpi-cluster-at-home/</id>
        
        <content type="html" xml:base="https://carlossless.io/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 href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;&quot;&gt;nixos&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;&quot;&gt;k8s&lt;&#x2F;a&gt; (through &lt;a 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 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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#x2F;keystone-oled&quot;&gt;keystone-oled&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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;carlossless.io&#x2F;rpi-cluster-at-home&#x2F;enclosure.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;rpi-cluster-at-home&#x2F;front.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;rpi-cluster-at-home&#x2F;qwiic-hat.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;rpi-cluster-at-home&#x2F;mounted.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 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 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 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 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 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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#x2F;keystone-oled&quot;&gt;keystone-oled&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;4x &lt;a 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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 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 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://carlossless.io/solving-that-pesky-file-rename-in-git-with-apfs-volumes/"/>
        <id>https://carlossless.io/solving-that-pesky-file-rename-in-git-with-apfs-volumes/</id>
        
        <content type="html" xml:base="https://carlossless.io/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 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;carlossless.io&#x2F;solving-that-pesky-file-rename-in-git-with-apfs-volumes&#x2F;hZ6ABYkF5ngLZ49NUt8qa10xspap.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 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://carlossless.io/xcode-9-and-carthage-coverage-data/"/>
        <id>https://carlossless.io/xcode-9-and-carthage-coverage-data/</id>
        
        <content type="html" xml:base="https://carlossless.io/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;carlossless.io&#x2F;xcode-9-and-carthage-coverage-data&#x2F;ic3junrykhonww.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 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 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;carlossless.io&#x2F;xcode-9-and-carthage-coverage-data&#x2F;3sxvt5m7mcmzfq.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;carlossless&#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 data-lang=&quot;bash&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8aa6c1;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; https:&#x2F;&#x2F;gist.githubusercontent.com&#x2F;carlossless&#x2F;9492d8e20938cfd1ee8163d7cdbfab9b&#x2F;raw &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;bash
&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 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 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://carlossless.io/reverse-hackintosh-pro/"/>
        <id>https://carlossless.io/reverse-hackintosh-pro/</id>
        
        <content type="html" xml:base="https://carlossless.io/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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;vlfs0cslbsouw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;irj7mosz2bjiea.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;2ixet7kyer79a.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;yyrnypby6d6rq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;m5qomtedsseow.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;vjjlmpmygwoz1q.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;rdmcatkv3z6sq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;ickhzmms8il1q.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;adzbhnvjyubsw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;lwiowvar0qzhyg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;vgfjnnyyvabsba.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;xtzoae7ocmcpgg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;3oikcvg9eybdq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;gc2g1vzdp4uhva.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlossless&#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 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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;it9goyyx18yfq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;9whphqhnbhaaw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;oscndcpxp67yq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;ba9jkpmignshq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;orzkkspssxgzcw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;vofbqzldrzxw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;cworxxwnziszg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;arnyygt280haqg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;euisgplvzl6q.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;sfcoeatsoebc2g.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;h2msvivladnqlg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;7ofbcld3rk4bsg.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;bjgg7o3ampac2a.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;pcrkonxob92j3g.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;jhwqlc8pszpnq.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;itibyi2498boew.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;qn5kitdqf2nxla.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;fqffuoienz1yw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 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 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 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 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 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 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 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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;jjqpu8ly9azjow.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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;carlossless.io&#x2F;reverse-hackintosh-pro&#x2F;q0yltbzvuc0kw.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlossless.io&#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 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://carlossless.io/convenient-di-in-swift/"/>
        <id>https://carlossless.io/convenient-di-in-swift/</id>
        
        <content type="html" xml:base="https://carlossless.io/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 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 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 data-lang=&quot;swift&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; Farm {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span&gt;private &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; animals: [Animal]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span&gt;init&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;(animals: [Animal]) {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span&gt;self.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;animals &lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; animals
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;feedAnimals() &lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8aa6c1;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;] {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; animals&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;map { $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eddd5a;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;feed() }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&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 data-lang=&quot;swift&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;protocol&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; Animal {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;feed() &lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8aa6c1;&quot;&gt;String
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&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 data-lang=&quot;swift&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; Cow: Animal {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;feed() &lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8aa6c1;&quot;&gt;String &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;quot;Moooo!&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; Duck: Animal {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;feed() &lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8aa6c1;&quot;&gt;String &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;quot;Quack!&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&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 data-lang=&quot;swift&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;Farm(animals: [Cow(), Duck()]))
&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 data-lang=&quot;swift&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;extension&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; Farm {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span&gt;init&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;() {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span&gt;self.init&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;(animals: [Cow(), Duck()])
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&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 data-lang=&quot;swift&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; TestAnimal: Animal {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;feed() &lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8aa6c1;&quot;&gt;String &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;quot;This isn&amp;#39;t an actual animal, it&amp;#39;s just a test&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; InjectTests: XCTestCase {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;testFeeding() {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; farm &lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; Farm(animals: [TestAnimal()])
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; result &lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; farm&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;feedAnimals()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;        XCTAssertEqual(result, [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd700;&quot;&gt;&amp;quot;This is not an actual animal, it&amp;#39;s just a test&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;])
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&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://carlossless.io/ios-openssl-support/"/>
        <id>https://carlossless.io/ios-openssl-support/</id>
        
        <content type="html" xml:base="https://carlossless.io/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 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 href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;x2on&quot;&gt;x2on&lt;&#x2F;a&gt;&#x27;s &lt;a 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 style=&quot;background-color:#191919;color:#ffffff;&quot;&gt;&lt;code&gt;&lt;span&gt;Undefined symbols for architecture x86_64:
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;_OPENSSL_ia32cap_P&amp;quot;, referenced from:
&lt;&#x2F;span&gt;&lt;span&gt;      _AES_cbc_encrypt in openssl(aes-x86_64.o)
&lt;&#x2F;span&gt;&lt;span&gt;ld: symbol(s) not found for architecture x86_64
&lt;&#x2F;span&gt;&lt;span&gt;clang: error: linker command failed with exit code 1 (use -v to see invocation)
&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 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 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 data-lang=&quot;m&quot; style=&quot;background-color:#191919;color:#ffffff;&quot; class=&quot;language-m &quot;&gt;&lt;code class=&quot;language-m&quot; data-lang=&quot;m&quot;&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;#if&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt; TARGET_IPHONE_SIMULATOR
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#171717;color:#616161;&quot;&gt;&#x2F;&#x2F; this is just so openssl links properly.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;extern int &lt;&#x2F;span&gt;&lt;span&gt;OPENSSL_cleanse&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8aa6c1;&quot;&gt;ptr&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8aa6c1;&quot;&gt;size_t &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8aa6c1;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;    OPENSSL_cleanse(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eddd5a;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#cccccc;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#80d500;&quot;&gt;#endif
&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>
