<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Posts on Jakub Duchniewicz</title>
        <link>https://jduchniewicz.com/posts/</link>
        <description>Recent content in Posts on Jakub Duchniewicz</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright>
        <lastBuildDate>Fri, 31 May 2024 11:33:33 -0700</lastBuildDate>
        <atom:link href="https://jduchniewicz.com/posts/index.xml" rel="self" type="application/rss+xml" />
        
        <item>
            <title>Embedded Open Source Summit 2024 - US, WA trip etc.</title>
            <link>https://jduchniewicz.com/posts/2024/05/embedded-open-source-summit-2024-us-wa-trip-etc./</link>
            <pubDate>Fri, 31 May 2024 11:33:33 -0700</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2024/05/embedded-open-source-summit-2024-us-wa-trip-etc./</guid>
            <description>&lt;h2 id=&#34;opening-words&#34;&gt;Opening words&lt;/h2&gt;
&lt;p&gt;Another month another post? &lt;em&gt;I wish&amp;hellip;&lt;/em&gt; This time, I got sucked into an almost-month long black hole of a trip and when I was spewed back into regular Warsaw reality it turned out I needed to dedicate 200% of my time to my day job. Scraping some free time I had (it&amp;rsquo;s Corpus Christi holiday in Poland as I am writing this) - I hence publish this blogpost where you can find some key discoveries of mine from &lt;strong&gt;Embedded Open Source Summit 2024&lt;/strong&gt;, the &lt;strong&gt;Linux Foundation&amp;rsquo;s ONE Summit 2024&lt;/strong&gt; and a meetup talk of mine from &lt;strong&gt;Digital Futures 2024&lt;/strong&gt; happening here in Warsaw. All this is sprinkled with pictures from the beautiful &lt;strong&gt;Washington State&lt;/strong&gt; which I started discovering during my week-long roadtrip!&lt;/p&gt;</description>
            <content type="html"><![CDATA[<h2 id="opening-words">Opening words</h2>
<p>Another month another post? <em>I wish&hellip;</em> This time, I got sucked into an almost-month long black hole of a trip and when I was spewed back into regular Warsaw reality it turned out I needed to dedicate 200% of my time to my day job. Scraping some free time I had (it&rsquo;s Corpus Christi holiday in Poland as I am writing this) - I hence publish this blogpost where you can find some key discoveries of mine from <strong>Embedded Open Source Summit 2024</strong>, the <strong>Linux Foundation&rsquo;s ONE Summit 2024</strong> and a meetup talk of mine from <strong>Digital Futures 2024</strong> happening here in Warsaw. All this is sprinkled with pictures from the beautiful <strong>Washington State</strong> which I started discovering during my week-long roadtrip!</p>
<p>Buckle up, here we go!</p>

    <img src="/eoss_lfone/me_seattle.jpeg"  alt="Mt Rainier in the distance and me!"  class="center"  style="border-radius: 8px;"  />


<h2 id="embedded-open-source-summit-2024">Embedded Open Source Summit 2024</h2>
<p>This was my <a href="https://jduchniewicz.com/posts/2023/07/embedded-open-source-summit-2023/">second</a> <strong>EOSS</strong> and also the second one where I had the pleasure of being a speaker. <strong>You probably already guessed the <a href="https://github.com/JDuchniewicz/zled-frame">topic</a></strong>! &#x1f601; I was delighted to see quite the audience of makers/hackers and tinkering enthusiasts, and discussing all kind of tangents to the project after the presentation. Hopefully, the presentation and the project will serve as a good source of tips/ways of work when coming up with a great project idea and reduce the struggles in realizing it.</p>
<p>As for the rest of the conference - I mostly attended <em>Zephyr/Embedded Linux</em> topics although one could get lost in the myriad halls of co-located <em>Open Source Summit</em> and other smaller Summits.
Prevailing topics were focused around supply chain safety and healthy contributor ecosystem <em>(looking at you XZ backdoor)</em>, some other notable highlights include:</p>
<ul>
<li>the widespread adoption of <a href="https://spdx.dev/">SPDX</a> as the de-facto <strong>SBOM tool</strong> which was not the case a few years ago</li>
<li>we have a <em>lot</em> of <strong>Linux in Space</strong> - <strong>80 running copies more</strong> every time a SpaceX&rsquo;s Starlink is commissioned to work!</li>
<li>Zephyr is becoming even <a href="https://docs.zephyrproject.org/latest/releases/release-notes-3.7.html">more mature</a> and <a href="https://zephyrproject.org/renesas-stmicroelectronics-and-ac6-join-the-zephyr-project-as-it-launches-the-3-6-release/">widely adopted</a> - the long awaited <strong><a href="https://github.com/zephyrproject-rtos/zephyr/pull/64465">HTTP server support</a></strong> has been added recently forcing me to rewrite parts of <a href="https://jduchniewicz.com/posts/2024/01/z-led-frame-or-how-to-illuminate-your-art-with-zephyr-part-1-intro-and-prototyping/">ZLED Frame</a> &#x1f926;</li>
</ul>
<h2 id="zled-frame---how-to-illuminate-your-artwork">ZLED Frame - how to Illuminate your artwork</h2>
<p>In case you have not been following my project (<strong>yet!</strong> &#x1f440;) or missed my talk (it was streamed online &#x1f601;) - <strong><a href="https://www.youtube.com/watch?v=qBMhLtfuny4">here is the video</a></strong>! After long chats with my audience after the talk I got some words of wisdom and encouragement (that I oh so need sometimes &#x1f604;). What I really enjoyed was to see that people always stumble upon similar issues, like measurements errors, messing the cabling up and other blunders - but <em>that is something worth appreciating or even loving about making/hacking and computer science in general!</em> I also got some helpful tips regarding a nasty bug where LEDs would not be lighted to a proper color/configuration - apparently there is a driver that is <a href="https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/">very picky</a> about proper timing and whenever something disrupts it (interrupt request?) - utter rubbish will be displayed on the strip.</p>
<p><strong><a href="https://github.com/JDuchniewicz/zled-frame">Link to the repository and project page</a></strong></p>
<h2 id="wa-travelling">WA travelling</h2>
<p>I won&rsquo;t bore you with very succinct descriptions of my trip around the <strong>Washington State</strong> (although maybe I should) - rather, grab some best-of pictures from the trip, along descriptions of locations and marvel at them &#x1f601;</p>
<p>After leaving Seattle, I headed for Mt. Rainier, but since winter was still abound (apparently so), I ended in Packwood and explored nearby trails (with <strong>nobody</strong> but game and bears around <em>yikes</em>). From left to right: Lake Glacier, Vista of Mt. St. Adams and marvelous Lake Wallupt!</p>
<div class="image-container">
  
      <img src="/eoss_lfone/lake_glacier.jpeg"  alt="Glacier lake."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/mt_st_adams.jpeg"  alt="Mt. St. Adams"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/lake_wallupt.jpeg"  alt="Brussels station."  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>Afterwards I had to travel a couple of hours to Wenatchee to see some more praire&rsquo;ish vistas. Lake Packwood, A great vista of Mt. Rainier (which I will visit one day) and the rocky way to Wenatchee.</p>
<div class="image-container">
  
      <img src="/eoss_lfone/lake_packwood.jpeg"  alt="Lake Packwood."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/mt_rainier.jpeg"  alt="Mt. Rainier vista"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/way_wenatchee.jpeg"  alt="Way to Wenatchee"  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>In Wenatchee and then Chelan, I went hiking and marvelling at the landscapes of great-nothing until the horizon. First picture - Saddle Rock, then two more of the Chelan Lake Trail.</p>
<div class="image-container">
  
      <img src="/eoss_lfone/wenatchee.jpeg"  alt="Saddle Rock"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/chelan.jpeg"  alt="Chelan Lake Trail 1."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/chelan_2.jpeg"  alt="Chelan Lake Trail 2."  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>The next leg was a fairly long and beautiful loop through the Cascadia Mountains which took me just over 3 hours to cross! The weather ranged from full sun, through rain and snow to finally end with a misty and gloomy view on the Western side of the mountains. You can see the stark difference in the pictures below.</p>
<div class="image-container">
  
      <img src="/eoss_lfone/cascadia.jpeg"  alt="Snowy Cascadia"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/cascadia_2.jpeg"  alt="Misty Cascadia"  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>Right after crossing Cascadia, I headed for Anacortes where I took some strolls around the coastline and caught a ferry to the south-western part of WA - ending my voyage in Port Angeles.</p>
<div class="image-container">
  
      <img src="/eoss_lfone/anacortes.jpeg"  alt="Anacortes views"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/anacortes_2.jpeg"  alt="Anacortes views 2."  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>If you are not already astonished by the sheer variety of weather conditions this state had to offer at this time of the yer, here comes the big punch! During the same day I waded through knee-deep snow and at the same time was under Olympic Rainforest&rsquo;s torrential rain (kudos to me for buying the raincoat a couple of days before). Below - views from the melting Olympic Mountains.</p>
<div class="image-container">
  
      <img src="/eoss_lfone/olympic.jpeg"  alt="Olympic Mountains"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/olympic_2.jpeg"  alt="Olympic Mountains 2."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/olympic_3.jpeg"  alt="Olympic Mountains 3."  class="center"  style="border-radius: 8px;"  />
  

</div>
<p><em>It was really soaking wet there!</em></p>
<div class="image-container">
  
      <img src="/eoss_lfone/rainforest.jpeg"  alt="Me driving through the rainforest"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/rainforest_2.jpeg"  alt="Olympic Rainforest"  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>Glad I managed to hike a long way to see the Deer Lake where I met some folks who were so nice to offer me something warm to drink! Fishing, cooking and living their life, waist-deep in the snow but warm and cozy in their tent!</p>
<div class="image-container">
  
      <img src="/eoss_lfone/rainforest_3.jpeg"  alt="Olympic Rainforest 2."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/eoss_lfone/deer_lake.jpeg"  alt="Deer Lake"  class="center"  style="border-radius: 8px;"  />
  

</div>
<h2 id="lf-one-summit">LF ONE Summit</h2>
<p>Visiting the venue of this year&rsquo;s <strong>NVIDIA GTC</strong> (which I unfortunately missed) left me in awe at how big these conference centres can be (and most of the time just a fraction of them is filled with people). This was a slightly more niche Summit, mostly focused around <strong>Core Network</strong> and futureproofing it against the <strong>6G</strong> with widespread adoption of Network APIs, through even wider usage of Open Source to clever and safe usage of AI to achieve tasks. To my disappointment - not much revolved around Baseband there - so I can share with you only two projects that I have been keeping tabs on: <strong><a href="https://github.com/srsran/srsRAN_Project">SRSRAN Project</a></strong> an open source L1/2/3 implementation on commodity Hardware, and the project <strong><a href="https://www.opencompute.org/projects/evenstar">EvenStar</a></strong> which was initially conceived by <strong>Meta</strong> to allow anyone to rollout their own Open Source and Hardware Radio Unit (currently stewarded by the <strong>Open Compute Project</strong>).</p>
<h2 id="digital-futures-2024">Digital Futures 2024</h2>
<p>This edition of the <strong>Digital Futures</strong> Meetup was happening in Warsaw so this time all I had to do was spend a short time commuting &#x1f604; Compare that with 20/24+ hours of flight when travelling for overseas conferences and you will see why I am mentioning it!</p>
<p>Topics covered included LLMs, their usage, limitations and implications for other jobs, such as data processing and collection; this was paired with my (longer-than-intended) talk on Telecommunications and the role <strong>Open Source</strong> plays in shaping its future. <a href="https://www.digital-futures.eu/meetups/tech-fusion-enterprise-ai-and-telecom-trends/">Krzysztof and Tomasz</a> delved deep into the various roles LLMs have inside <strong><a href="https://www.tietoevry.com/">Tietoevry</a></strong> and why they are only a complement to other more traditional ways of data collection and processing. This resonates heavily with my take on them - yet another <em>(fast, amazing, powerful)</em> tool in my engineering toolbelt.</p>

    <img src="/eoss_lfone/df.jpeg"  alt="Me speaking at Digital Futures."  class="center"  style="border-radius: 8px;"  />


<h2 id="my-talk">My talk</h2>
<p>In my presentation I tried merging what I talked about in Košice about <strong>FlexRAN</strong> and it&rsquo;s importance in bringing the <strong>OpenRAN</strong> revolution to the Baseband side of 5G/LTE(<a href="https://jduchniewicz.com/posts/2024/02/fosdem-2024-first-trip-to-brussels/">FOSDEM 2024 talk</a>), while showcasing how Open Source developments in the Core Network and Baseband helped bring the long-awaited shift in productivity and quality of code to these areas. Time proved to be my enemy and I had to skip a big part of what I wanted to present, but the avid discussion and genuine curiosity of the audience after the talk proved that I managed to sneak just the content that would provoke such discussions &#x1f601; The big question is: <strong>What do the telecom vendors have to gain from Open Sourcing their Baseband parts of code?</strong> - My answer to that is clear: open just the most crucial parts and innovate in terms of hardware/algorithms or unique value propositions and take a look at how creating projects like <strong>ONAP</strong> or <strong>CNTi</strong> helped make the Core Network a more unified and resilient part of the 5G/LTE system.</p>
<h2 id="summary">Summary</h2>
<p>As always, thank for staying with me until now - I hope you learned something and we that <em>might</em> see each other on upcoming events/travels &#x1f601;
Like I promised - the <a href="https://jduchniewicz.com/posts/2024/01/z-led-frame-or-how-to-illuminate-your-art-with-zephyr-part-1-intro-and-prototyping/">ZLED Frame</a> updates are on their way and since there were some exciting updates to the Zephyr project - I will be busy rewriting the project to adhere to them! See you next time!</p>
<p><em>P.S. I plan to be writing some recommendations regarding what I have been (quite intensively) recently reading.</em>
Also, a small fastfoody reward (In-N-Out Animal Style!) for you who stayed for so long here &#x1f604;</p>

    <img src="/eoss_lfone/innout.jpeg"  alt="In-N-Out burger set - Animal Style!"  class="center"  style="border-radius: 8px;"  />


]]></content>
        </item>
        
        <item>
            <title>Z LED Frame, or how to illuminate your art with Zephyr - part 2: Zephyr, LEDs and networking</title>
            <link>https://jduchniewicz.com/posts/2024/03/z-led-frame-or-how-to-illuminate-your-art-with-zephyr-part-2-zephyr-leds-and-networking/</link>
            <pubDate>Wed, 27 Mar 2024 19:12:34 +0100</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2024/03/z-led-frame-or-how-to-illuminate-your-art-with-zephyr-part-2-zephyr-leds-and-networking/</guid>
            <description>&lt;p&gt;Warm welcome to you all after &lt;em&gt;the long dark&lt;/em&gt; of wintry nights. I managed to get a couple of powder days (despite terribly dry spell this winter) and as I am writing this post my Prusa MK3S 3D Printer is doing &lt;strong&gt;brr&lt;/strong&gt; rarely having any rest these days. In this blogpost we will focus on the core of the project which is serving an HTTP server over a Wi-Fi connection, receiving an image from the user, loading it to MCU&amp;rsquo;s memory and finally displaying it on the LED strip. As always, engineering misconceptions and errors are abound so be sure to learn from my mistakes &amp;#x1f601;&lt;/p&gt;</description>
            <content type="html"><![CDATA[<p>Warm welcome to you all after <em>the long dark</em> of wintry nights. I managed to get a couple of powder days (despite terribly dry spell this winter) and as I am writing this post my Prusa MK3S 3D Printer is doing <strong>brr</strong> rarely having any rest these days. In this blogpost we will focus on the core of the project which is serving an HTTP server over a Wi-Fi connection, receiving an image from the user, loading it to MCU&rsquo;s memory and finally displaying it on the LED strip. As always, engineering misconceptions and errors are abound so be sure to learn from my mistakes &#x1f601;</p>
<p>This is the <em>second</em> part of the <strong>ZLED Frame</strong> series:</p>
<ul>
<li><strong><a href="https://jduchniewicz.com/posts/2024/01/z-led-frame-or-how-to-illuminate-your-art-with-zephyr-part-1-intro-and-prototyping/">First part</a></strong> - Project introduction and early prototyping</li>
<li><strong>Third part</strong> - Coming soon! - FreeCAD + 3D printing</li>
<li><strong>Fourth part</strong> - Coming soon! - Extras</li>
</ul>
<p>Now have a nice early March Austrian sunset to accompany your reading:

    <img src="/zledframe/2/sunset.jpeg"  alt="Yet again a sunset in Krimml (Zillertal)."  class="center"  style="border-radius: 8px;"  />

</p>
<h2 id="zephyr-how-to-and-project-set-up">Zephyr How-To and project set-up</h2>
<p>We got so far without really digging into what <em>exactly</em> <a href="https://www.zephyrproject.org/">Zephyr</a> is doing in this project. First of all, what is Zephyr? To me it has always been akin to a younger brother of Linux having equally strong virality and momentum but targeted more for embedded devices. The thing that really bought me is that you <em>usually can get any off-the-shelf development board and it will work</em> assuming the example is supported for this board(most of which are available for a plethora of devices). Compare that to installing dubious toolchains &#x1f928; or binaries accessible only after you sell your data, kidney and a cut on your profits &#x1f604;</p>
<p>(Yes I am biased towards proprietary software, why do you ask?) - no, but really? <strong>Licensed compiler??? - yes - companies do that, yes - you know the big names</strong></p>
<p>I won&rsquo;t go into details on how to obtain the code itself (come on, we are all grown-up here), rather I will point out my preferred ways of working with this project. I usually checkout the latest stable branch and optionally create a new branch for some modifications to the project&rsquo;s code that might arise during hacking around. <em>Always</em> be sure to be working in the virtual environment in which <strong>west</strong> has all the paths and variables set up properly - refer to <a href="https://docs.zephyrproject.org/latest/develop/getting_started/index.html">the official guide</a> on how to set up that.</p>
<p>Since I am using an out-of-tree project structure basing on existing <a href="https://github.com/zephyrproject-rtos/example-application">project repository</a> where I specify overlays for my board, the best course of action for you is to follow my step. Trust me, this way you will probably save yourself from painful decoupling if you would like to move your project to be something bigger. What I don&rsquo;t recommend though, is working outside the Zephyr&rsquo;s virtual environment - don&rsquo;t go this path of pain&hellip;</p>
<p>Once we have our project set up, we should create an <code>app.overlay</code> file with following contents:</p>
<pre tabindex="0"><code>/*
 * Copyright (c) 2024 Jakub Duchniewicz
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include &lt;zephyr/dt-bindings/led/led.h&gt;

&amp;spi2 {
	/* Workaround to support WS2812 driver */
	line-idle-low;

        led_strip: ws2812@0 {
                compatible = &#34;worldsemi,ws2812-spi&#34;;

                /* SPI */
                reg = &lt;0&gt;; /* ignored, but necessary for SPI bindings */
                spi-max-frequency = &lt;6400000&gt;;

                /* WS2812 */
                chain-length = &lt;256&gt;; /* arbitrary; change at will */
                spi-cpha;
                spi-one-frame = &lt;0xf0&gt;; /* 11110000: 625 ns high and 625 ns low */
                spi-zero-frame = &lt;0xc0&gt;; /* 11000000: 312.5 ns high and 937.5 ns low */
                color-mapping = &lt;LED_COLOR_ID_GREEN
                                 LED_COLOR_ID_RED
                                 LED_COLOR_ID_BLUE&gt;;
        };
};

$wifi {
    status = &#34;okay&#34;;
};

/ {
        aliases {
                led-strip = &amp;led_strip;
        };
};
</code></pre><p>In case you are not familiar with the <em>Device Tree Structure</em> files I recommend(as always) great <strong>Bootlin&rsquo;s</strong> <a href="https://bootlin.com/pub/conferences/2021/webinar/petazzoni-device-tree-101/petazzoni-device-tree-101.pdf">presentations</a> that very concisely describe what&rsquo;s what.</p>
<p>The overlay above initializes the <strong>SPI</strong> connected Data pin of the LED strip, enables the Wi-Fi and creates an alias for the LED strip node in the Device Tree. Overlays are special entities that are used to add or alter nodes of the Device Tree that are added during compilation. In our case we have a standalone <strong>ESP32-Wroom</strong> board that has some fixed peripherals and settings specified first in the <a href="https://github.com/zephyrproject-rtos/zephyr/blob/main/dts/xtensa/espressif/esp32/esp32_common.dtsi">SoC&rsquo;s device tree file</a> and then the <a href="https://github.com/zephyrproject-rtos/zephyr/blob/main/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_procpu.dts">board itself</a> and we simply add additional external peripheral that we have to configure during compilation. (There have been recently some changes since Espressif introduced a new hardware model which I still need to go over - so expect me explaining that in a future post).</p>
<p>Assuming you want to use the same LED strip with ESP32 you will simply need to adjust the <code>chain-length</code> parameter at will.</p>
<p>Device tree is just one part of the configuration - we also need to add several basic config defines to augment those included in the default app:</p>
<pre tabindex="0"><code>CONFIG_LOG=y
CONFIG_SPI=y
CONFIG_LED_STRIP=y
CONFIG_WS2812_STRIP=y

## Copied over from the sample - to reduce
# POSIX options
CONFIG_POSIX_MAX_FDS=20

# Networking config
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=n # it is set to yes either way
CONFIG_NET_TCP=y
CONFIG_NET_UDP=n
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_MAX_CONN=20
CONFIG_NET_MAX_CONTEXTS=20
CONFIG_NET_STATISTICS=y
CONFIG_NET_CONNECTION_MANAGER=y

# Network buffers
CONFIG_NET_PKT_RX_COUNT=96
CONFIG_NET_PKT_TX_COUNT=96
CONFIG_NET_BUF_RX_COUNT=128
CONFIG_NET_BUF_TX_COUNT=128
CONFIG_NET_CONTEXT_NET_PKT_POOL=y
CONFIG_NET_BUF_POOL_USAGE=y

# IP address options
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4

# Network address config
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_NEED_IPV4=y
CONFIG_NET_CONFIG_MY_IPV4_ADDR=&#34;192.168.0.230&#34;
CONFIG_NET_CONFIG_PEER_IPV4_ADDR=&#34;192.168.0.231&#34;
CONFIG_NET_CONFIG_NEED_IPV6=y
CONFIG_NET_CONFIG_MY_IPV6_ADDR=&#34;2001:db8::1&#34;
CONFIG_NET_CONFIG_PEER_IPV6_ADDR=&#34;2001:db8::2&#34;

# Network debug config
CONFIG_NET_LOG=y
CONFIG_NET_SHELL=y

# This is needed so that the sample app can respond to queries
# as fast as possible.
CONFIG_NET_TCP_TIME_WAIT_DELAY=0

# This is needed for Wi-Fi connections
CONFIG_NET_L2_WIFI_SHELL=y

CONFIG_ESP_HEAP_MEM_POOL_REGION_1_SIZE=1024
# is this necessary?
CONFIG_HEAP_MEM_POOL_SIZE=98304


## overlays for ESP32
CONFIG_WIFI=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_DHCPV4=y
CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4=y
</code></pre><p>Most importantly, we need to enable logging, Wi-Fi, IPv4 capabilities, the WS2812 LED strip support, and change the <code>CONFIG_ESP_HEAP_MEM_POOL_REGION_1_SIZE</code> to be 1024 otherwise we will be hitting errors binary creation due to too small memory regions. Lastly, we need to set up the IPv4 address that we will be connecting to from our client (be careful not to overlap with any existing one on your local network).</p>
<h3 id="application-logical-split">Application logical split</h3>
<p>Even though it is not a grand project, I would be neglecting my computer science background without partitioning it into <em>encapsulated</em> components, so here they are:</p>
<ul>
<li><strong>main</strong> - self-explanatory, calls the interface functions and spawns threads</li>
<li><strong>pixels</strong> - arranging the pixels, creating frames and pushing them to the LED driver</li>
<li><strong>network</strong> - basing on the <a href="https://github.com/zephyrproject-rtos/zephyr/tree/main/samples/net/sockets/dumb_http_server">dumb_http_server</a> sample, establishes the HTTP server and responds to API calls, also parses the incoming data and informs the <code>pixels</code> module that the data was obtained</li>
</ul>
<p>As you can see it is really basic but allows us to freely add more components if we wish without cluttering the main file too much. Thread-wise we also don&rsquo;t have much going on and we only need to synchronize the threads whenever a new image is provided over the network so that proper data is displayed on the screen.</p>
<h2 id="interfacing-ws2812">Interfacing WS2812</h2>
<p>As we have already seen above, we are using the LED strip containing the WS2812 LEDs having a <a href="https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf">very tiny datasheet</a>. Even though the datasheet is tiny (and does not really tell us what is the <em>factual</em> power consumption of a single LED) it shows that we have just 3 wires, namely VCC(Voltage input), GND, and a Data in pin that is interfaced from our ESP.</p>
<p>The driver is also fairly simple, uses bit banging? (verify that) - we won&rsquo;t go into details, and that&rsquo;s also one thing that is so great about Zephyr - when you have drivers, it just works! When you don&rsquo;t have the drivers, well then that&rsquo;s a different story, but then usually you are experienced enough to at least tackle it on your own &#x1f601;</p>
<p>For the prototype I used a battery pack that initially supplied 6V (4 * 1.5V battery) so I had to use several voltage dropping diodes (those I had laying around were of the <a href="https://en.wikipedia.org/wiki/Schottky_diode">Schottky type</a> so they had slightly lower voltage drop). One thing that I <strong>must warn you about</strong> when you would like to use such a battery pack is that the batteries yield lower voltage over time (as they discharge), so after several hours of debugging I stumbled into a very weird error: <strong>I could not turn the LEDs blue</strong>&hellip;</p>
<p>Dumb as it may sound, I was thinking that maybe there was a mistake in the driver or the hardware itself was faulty, only after several hours of digging around and learning about <a href="https://www.youtube.com/watch?v=AF8d72mA41M&amp;pp=ygUTYmx1ZSBsZWQgcHJvZHVjdGlvbg%3D%253">blue LED production difficulties</a> - I realized that maybe the voltage is simply too low for the blue LED to light up. Removing several of the voltage dropping diodes solved the problem &#x1f926;</p>
<p><strong>There is a lesson in this for all of us - never trust your batteries &#x1f601;</strong></p>
<p>After making sure the LEDs can shine in their entirety of the spectrum, one can start giving them something more lofty than just test patterns, but before we go into displaying images from memory, let&rsquo;s go briefly over the code of how to interface them. As I said before the beauty of working with a full-fledged system is that you <em>usually</em> have most things abstracted in the form of API (as long as it works &#x1f604;)</p>
<p>In my case it was as simple as getting the device from the device tree, initializing it and calling <code>led_strip_update_rgb</code> with the data I want to display.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span>   <span style="color:#75715e">#define STRIP_NODE DT_ALIAS(led_strip)
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">const</span> <span style="color:#66d9ef">struct</span> device <span style="color:#f92672">*</span><span style="color:#66d9ef">const</span> strip <span style="color:#f92672">=</span> <span style="color:#a6e22e">DEVICE_DT_GET</span>(STRIP_NODE);
</span></span></code></pre></div><p>Then we call a simple calibration routine:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">display_preset_pattern</span>(<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">struct</span> device <span style="color:#f92672">*</span><span style="color:#66d9ef">const</span> strip)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> rc;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">memset</span>(<span style="color:#f92672">&amp;</span>pixels, <span style="color:#ae81ff">0x00</span>, <span style="color:#66d9ef">sizeof</span>(pixels));
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">memcpy</span>(<span style="color:#f92672">&amp;</span>pixels[cursor], <span style="color:#f92672">&amp;</span>colors[color], <span style="color:#66d9ef">sizeof</span>(<span style="color:#66d9ef">struct</span> led_rgb));
</span></span><span style="display:flex;"><span>    rc <span style="color:#f92672">=</span> <span style="color:#a6e22e">led_strip_update_rgb</span>(strip, pixels, STRIP_NUM_PIXELS);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> (rc)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> rc;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    cursor<span style="color:#f92672">++</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> (cursor <span style="color:#f92672">&gt;=</span> STRIP_NUM_PIXELS)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        cursor <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>        color<span style="color:#f92672">++</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> (color <span style="color:#f92672">==</span> <span style="color:#a6e22e">ARRAY_SIZE</span>(colors))
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            color <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>My code is <em>slightly more complex</em> because I am running it in a thread and waiting for the data to arrive from the client and then I need to reverse the data as the LED is soldered in a snake pattern like in the below figure while the data is ordered sequentially in the memory buffer.</p>











    



    


<span style="display: flex; justify-content: center; align-items: center;">
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 442.4333343505855 352" width="60%" height="60%">
  <!-- svg-source:excalidraw -->
  
  <defs>
    <style class="style-fonts">
      @font-face {
        font-family: "Virgil";
        src: url("https://excalidraw.com/Virgil.woff2");
      }
      @font-face {
        font-family: "Cascadia";
        src: url("https://excalidraw.com/Cascadia.woff2");
      }
      @font-face {
        font-family: "Assistant";
        src: url("https://excalidraw.com/Assistant-Regular.woff2");
      }
    </style>
    
  </defs>
  <rect x="0" y="0" width="442.4333343505855" height="352" fill="#ffffff"></rect><g stroke-linecap="round"><g transform="translate(39.10527622143536 46) rotate(0 187.00152868310545 0)"><path d="M0.74 0.65 C63.05 0.78, 312.87 0.19, 374.9 0.23 M-0.33 -0.05 C61.81 -0.26, 311.83 -1.61, 374.43 -1.77" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(39.10527622143536 46) rotate(0 187.00152868310545 0)"><path d="M350.97 6.88 C361.14 4.9, 369.47 -1.72, 374.43 -1.77 M350.97 6.88 C360.55 3.58, 368.89 1.15, 374.43 -1.77" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(39.10527622143536 46) rotate(0 187.00152868310545 0)"><path d="M350.9 -10.22 C361.01 -5.61, 369.37 -5.65, 374.43 -1.77 M350.9 -10.22 C360.38 -7.16, 368.75 -3.21, 374.43 -1.77" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(406.19201486744464 82.5511450490082) rotate(0 -187.0000000000049 0)"><path d="M0.21 0.5 C-62.09 0.74, -312.06 0.48, -374.27 0.36 M-1.14 -0.28 C-63.58 -0.33, -313.33 -1.79, -375.36 -1.58" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(406.19201486744464 82.5511450490082) rotate(0 -187.0000000000049 0)"><path d="M-351.85 -10.09 C-357.17 -8.29, -363.51 -4.01, -375.36 -1.58 M-351.85 -10.09 C-359.18 -8.6, -364.36 -6.24, -375.36 -1.58" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(406.19201486744464 82.5511450490082) rotate(0 -187.0000000000049 0)"><path d="M-351.88 7.01 C-357.05 4.38, -363.37 4.23, -375.36 -1.58 M-351.88 7.01 C-359.33 3.68, -364.5 1.23, -375.36 -1.58" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(36.03900863043668 118.2041728131324) rotate(0 189.5 0)"><path d="M-0.55 0.18 C62.45 0.03, 315.37 -0.69, 378.62 -0.74 M1.37 -0.78 C64.12 -0.79, 314.68 0.09, 377.47 0.41" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(36.03900863043668 118.2041728131324) rotate(0 189.5 0)"><path d="M353.94 8.87 C362.5 5.36, 369.26 2.89, 377.47 0.41 M353.94 8.87 C361.45 5.69, 367.64 4.31, 377.47 0.41" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(36.03900863043668 118.2041728131324) rotate(0 189.5 0)"><path d="M354.01 -8.24 C362.57 -5.72, 369.3 -2.18, 377.47 0.41 M354.01 -8.24 C361.58 -6.43, 367.75 -2.84, 377.47 0.41" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(413.1226899102346 154.75531786214066) rotate(0 -189.5000000000049 0)"><path d="M-0.38 -0.74 C-63.47 -0.78, -316.08 -0.38, -379.08 -0.11 M1.62 1.49 C-61.59 1.62, -316.66 1.78, -380.07 1.38" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(413.1226899102346 154.75531786214066) rotate(0 -189.5000000000049 0)"><path d="M-356.56 -7.12 C-363.76 -5.17, -368.69 -1.9, -380.07 1.38 M-356.56 -7.12 C-365.31 -3.51, -374.11 -1.76, -380.07 1.38" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(413.1226899102346 154.75531786214066) rotate(0 -189.5000000000049 0)"><path d="M-356.6 9.98 C-363.82 7.58, -368.74 6.5, -380.07 1.38 M-356.6 9.98 C-365.45 7.16, -374.24 2.47, -380.07 1.38" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(37.32029712714666 190.84399345133426) rotate(0 189.5 0)"><path d="M-0.4 0.41 C63.03 0.4, 316.83 0.53, 380.18 0.47 M1.59 -0.42 C65 -0.84, 316.91 -1.7, 379.85 -1.41" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(37.32029712714666 190.84399345133426) rotate(0 189.5 0)"><path d="M356.36 7.14 C363.26 6.91, 369.61 3.8, 379.85 -1.41 M356.36 7.14 C363.27 3.68, 370.46 2.8, 379.85 -1.41" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(37.32029712714666 190.84399345133426) rotate(0 189.5 0)"><path d="M356.36 -9.96 C363.34 -5.64, 369.68 -4.2, 379.85 -1.41 M356.36 -9.96 C363.35 -8.29, 370.54 -4.03, 379.85 -1.41" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(414.40397840694504 227.3951385003424) rotate(0 -189.5000000000049 0)"><path d="M1.18 0.47 C-61.81 0.4, -315.05 -0.04, -378.32 0 M0.34 -0.33 C-62.71 -0.23, -315.71 1.69, -378.91 1.54" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(414.40397840694504 227.3951385003424) rotate(0 -189.5000000000049 0)"><path d="M-355.45 -7.08 C-360.89 -3.42, -367.91 -1.3, -378.91 1.54 M-355.45 -7.08 C-363.95 -3.19, -372.35 -0.63, -378.91 1.54" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(414.40397840694504 227.3951385003424) rotate(0 -189.5000000000049 0)"><path d="M-355.39 10.02 C-360.91 9.12, -367.94 6.7, -378.91 1.54 M-355.39 10.02 C-363.89 7.71, -372.31 4.05, -378.91 1.54" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(39.250972169937086 263.0481662644667) rotate(0 189.5 0)"><path d="M0.68 0 C63.75 0.05, 316.55 0.91, 379.58 0.75 M-0.42 -1.04 C62.43 -1.37, 315.86 -1.14, 378.93 -0.97" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(39.250972169937086 263.0481662644667) rotate(0 189.5 0)"><path d="M355.43 7.54 C364.77 4.98, 375.38 0.41, 378.93 -0.97 M355.43 7.54 C360.86 5.77, 366.51 3.82, 378.93 -0.97" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(39.250972169937086 263.0481662644667) rotate(0 189.5 0)"><path d="M355.45 -9.56 C364.85 -5.31, 375.45 -3.07, 378.93 -0.97 M355.45 -9.56 C360.88 -7.48, 366.53 -5.57, 378.93 -0.97" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(416.334653449735 299.5993113134749) rotate(0 -189.5000000000049 0)"><path d="M0.58 0.75 C-62.73 0.6, -315.87 -0.96, -379.13 -0.9 M-0.58 0.11 C-64.11 0.08, -316.96 0.29, -380.15 0.17" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(416.334653449735 299.5993113134749) rotate(0 -189.5000000000049 0)"><path d="M-356.65 -8.37 C-363.78 -5.43, -374.91 -2.12, -380.15 0.17 M-356.65 -8.37 C-365.4 -4.59, -374.82 -2.22, -380.15 0.17" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(416.334653449735 299.5993113134749) rotate(0 -189.5000000000049 0)"><path d="M-356.66 8.73 C-363.78 5.57, -374.91 2.78, -380.15 0.17 M-356.66 8.73 C-365.43 5.78, -374.85 1.41, -380.15 0.17" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g transform="translate(205.10833358764626 317) rotate(0 18.875 12.5)"><text x="0" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">etc.</text></g><g transform="translate(19.28127658764629 10) rotate(0 6.883333206176758 12.5)"><text x="0" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">0</text></g><g transform="translate(414.01019638146954 10) rotate(0 8.891666412353516 12.5)"><text x="0" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">15</text></g><g transform="translate(414.2166671752925 66.5) rotate(0 9.108333587646484 12.5)"><text x="0" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">16</text></g><g transform="translate(10 63.5) rotate(0 9.516666412353516 12.5)"><text x="0" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">31</text></g></svg>
</span>


<p>This can be also done on the client side to reduce the workload on the MCU &#x1f601;</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">display_network_image</span>(<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">struct</span> device <span style="color:#f92672">*</span><span style="color:#66d9ef">const</span> strip)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> rc;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Wait for the semaphore indicating a new image is ready
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">k_sem_take</span>(<span style="color:#f92672">&amp;</span>image_semaphore, K_NO_WAIT) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Received image - semaphore taken&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//  Copy the received image to the pixels array
</span></span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">memset</span>(pixels, <span style="color:#ae81ff">0x00</span>, <span style="color:#66d9ef">sizeof</span>(pixels));
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// convert pixel data to led_rgb
</span></span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">size_t</span> index <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">int</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; i <span style="color:#f92672">&lt;</span> STRIP_LINE_LENGTH; <span style="color:#f92672">++</span>i)
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">int</span> j <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; j <span style="color:#f92672">&lt;</span> STRIP_LINE_LENGTH; <span style="color:#f92672">++</span>j)
</span></span><span style="display:flex;"><span>            {
</span></span><span style="display:flex;"><span>                <span style="color:#75715e">// since the led strip is sequential, we have to reverse every second line
</span></span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">if</span> (i <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>                {
</span></span><span style="display:flex;"><span>                    pixels[index] <span style="color:#f92672">=</span> <span style="color:#a6e22e">RGB</span>(received_image[index <span style="color:#f92672">*</span> <span style="color:#ae81ff">3</span>], received_image[index <span style="color:#f92672">*</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>], received_image[index <span style="color:#f92672">*</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>]);
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>                {
</span></span><span style="display:flex;"><span>                    <span style="color:#66d9ef">size_t</span> reversed_index <span style="color:#f92672">=</span> i <span style="color:#f92672">*</span> STRIP_LINE_LENGTH <span style="color:#f92672">+</span> STRIP_LINE_LENGTH <span style="color:#f92672">-</span> j <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>                    pixels[index] <span style="color:#f92672">=</span> <span style="color:#a6e22e">RGB</span>(received_image[reversed_index <span style="color:#f92672">*</span> <span style="color:#ae81ff">3</span>], received_image[reversed_index <span style="color:#f92672">*</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>], received_image[reversed_index <span style="color:#f92672">*</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>]);
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">++</span>index;
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Update the LED strip with the new image
</span></span></span><span style="display:flex;"><span>        rc <span style="color:#f92672">=</span> <span style="color:#a6e22e">led_strip_update_rgb</span>(strip, pixels, STRIP_NUM_PIXELS);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> (rc)
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> rc;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Finished image drawing&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
</span></span></code></pre></div><p>As you can see the pixel displaying code is really simple, we will extend (and optimize &#x1f604;) it in the near future.</p>
<h2 id="networking-primer">Networking primer</h2>
<p>Networking-wise, the ESP works as a <em>server</em> - meaning that it provides the <strong>HTML</strong> + <strong>CSS</strong> + <strong>Javascript</strong> code needed to display the website on the <em>client</em> which may be your PC, mobile phone or even another microcontroller (of course assuming it has a browser capabilities). The server is running on the Wi-Fi network with a static IP so everyone on the network can access it (yes, it is not the most secure <em>thing</em> but since my network is fairly well isolated from the outside world I am not really afraid - besides it is not a drug injector). Also, implementing full network security is beyond this blogpost, but you are always encouraged to read up on it &#x1f604;.</p>
<p>When I connect to the server, I make a request to the root endpoint - <code>/</code> and the server transfers the binary blob containing the code to be run on the client. The HTML code is rendered by the browser and the <strong>Javascript</strong> code executes either immediately or when special action is undertaken (i.e) button press. The code runs on the client so we can leverage a more powerful machine to do our dirty data processing &#x1f601;</p>
<p>In our case we offload image pre-processing and massaging it to be a raw-byte array that we receive on the server via an API-call to the <code>/api/image</code> endpoint. There are some caveats that we have to consider when we are implementing networking ourselves - such as, parsing (or ignoring) message headers and knowing when we receive desired data.</p>
<p>Overall, the flow looks like that: <em>(basic functionality for now</em>)











    



    


<span style="display: flex; justify-content: center; align-items: center;">
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 617.3786615818358 617.3786615818356" width="60%" height="60%">
  <!-- svg-source:excalidraw -->
  
  <defs>
    <style class="style-fonts">
      @font-face {
        font-family: "Virgil";
        src: url("https://excalidraw.com/Virgil.woff2");
      }
      @font-face {
        font-family: "Cascadia";
        src: url("https://excalidraw.com/Cascadia.woff2");
      }
      @font-face {
        font-family: "Assistant";
        src: url("https://excalidraw.com/Assistant-Regular.woff2");
      }
    </style>
    
  </defs>
  <rect x="0" y="0" width="617.3786615818358" height="617.3786615818356" fill="#ffffff"></rect><g stroke-opacity="0" fill-opacity="0" stroke-linecap="round" transform="translate(490.62133841816444 91.62133841816438) rotate(0 58.37866158183567 58.378661581835615)"><path d="M116.76 58.38 C116.76 60.72, 116.61 63.09, 116.33 65.42 C116.05 67.74, 115.62 70.07, 115.06 72.35 C114.5 74.63, 113.8 76.89, 112.96 79.08 C112.13 81.27, 111.16 83.43, 110.07 85.51 C108.98 87.59, 107.76 89.61, 106.42 91.54 C105.09 93.47, 103.63 95.34, 102.08 97.09 C100.52 98.85, 98.85 100.52, 97.09 102.08 C95.34 103.63, 93.47 105.09, 91.54 106.42 C89.61 107.76, 87.59 108.98, 85.51 110.07 C83.43 111.16, 81.27 112.13, 79.08 112.96 C76.89 113.8, 74.63 114.5, 72.35 115.06 C70.07 115.62, 67.74 116.05, 65.42 116.33 C63.09 116.61, 60.72 116.76, 58.38 116.76 C56.03 116.76, 53.67 116.61, 51.34 116.33 C49.01 116.05, 46.69 115.62, 44.41 115.06 C42.13 114.5, 39.87 113.8, 37.68 112.96 C35.48 112.13, 33.33 111.16, 31.25 110.07 C29.17 108.98, 27.15 107.76, 25.22 106.42 C23.29 105.09, 21.42 103.63, 19.67 102.08 C17.91 100.52, 16.24 98.85, 14.68 97.09 C13.13 95.34, 11.67 93.47, 10.33 91.54 C9 89.61, 7.78 87.59, 6.69 85.51 C5.6 83.43, 4.63 81.27, 3.79 79.08 C2.96 76.89, 2.26 74.63, 1.7 72.35 C1.14 70.07, 0.71 67.74, 0.43 65.42 C0.14 63.09, 0 60.72, 0 58.38 C0 56.03, 0.14 53.67, 0.43 51.34 C0.71 49.01, 1.14 46.69, 1.7 44.41 C2.26 42.13, 2.96 39.87, 3.79 37.68 C4.63 35.48, 5.6 33.33, 6.69 31.25 C7.78 29.17, 9 27.15, 10.33 25.22 C11.67 23.29, 13.13 21.42, 14.68 19.67 C16.24 17.91, 17.91 16.24, 19.67 14.68 C21.42 13.13, 23.29 11.67, 25.22 10.33 C27.15 9, 29.17 7.78, 31.25 6.69 C33.33 5.6, 35.48 4.63, 37.68 3.79 C39.87 2.96, 42.13 2.26, 44.41 1.7 C46.69 1.14, 49.01 0.71, 51.34 0.43 C53.67 0.14, 56.03 0, 58.38 0 C60.72 0, 63.09 0.14, 65.42 0.43 C67.74 0.71, 70.07 1.14, 72.35 1.7 C74.63 2.26, 76.89 2.96, 79.08 3.79 C81.27 4.63, 83.43 5.6, 85.51 6.69 C87.59 7.78, 89.61 9, 91.54 10.33 C93.47 11.67, 95.34 13.13, 97.09 14.68 C98.85 16.24, 100.52 17.91, 102.08 19.67 C103.63 21.42, 105.09 23.29, 106.42 25.22 C107.76 27.15, 108.98 29.17, 110.07 31.25 C111.16 33.33, 112.13 35.48, 112.96 37.68 C113.8 39.87, 114.5 42.13, 115.06 44.41 C115.62 46.69, 116.05 49.01, 116.33 51.34 C116.61 53.67, 116.76 56.03, 116.76 58.38" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(520.3868839459433 108.91484092628417) rotate(0 29.07051933023172 19.380346220154507)"><path d="M9.69 0 C18.34 0, 26.99 0, 48.45 0 M9.69 0 C18.85 0, 28.01 0, 48.45 0 M48.45 0 C54.91 0, 58.14 3.23, 58.14 9.69 M48.45 0 C54.91 0, 58.14 3.23, 58.14 9.69 M58.14 9.69 C58.14 16.22, 58.14 22.75, 58.14 29.07 M58.14 9.69 C58.14 14.93, 58.14 20.17, 58.14 29.07 M58.14 29.07 C58.14 35.53, 54.91 38.76, 48.45 38.76 M58.14 29.07 C58.14 35.53, 54.91 38.76, 48.45 38.76 M48.45 38.76 C38.31 38.76, 28.17 38.76, 9.69 38.76 M48.45 38.76 C35.18 38.76, 21.91 38.76, 9.69 38.76 M9.69 38.76 C3.23 38.76, 0 35.53, 0 29.07 M9.69 38.76 C3.23 38.76, 0 35.53, 0 29.07 M0 29.07 C0 23.4, 0 17.74, 0 9.69 M0 29.07 C0 23.78, 0 18.49, 0 9.69 M0 9.69 C0 3.23, 3.23 0, 9.69 0 M0 9.69 C0 3.23, 3.23 0, 9.69 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(514.8415750915751 151.98980624310826) rotate(0 34.15842490842488 4.6756779342329935)"><path d="M2.34 0 C15.72 0, 29.11 0, 65.98 0 M2.34 0 C21.47 0, 40.61 0, 65.98 0 M65.98 0 C67.54 0, 68.32 0.78, 68.32 2.34 M65.98 0 C67.54 0, 68.32 0.78, 68.32 2.34 M68.32 2.34 C68.32 3.45, 68.32 4.57, 68.32 7.01 M68.32 2.34 C68.32 4.2, 68.32 6.06, 68.32 7.01 M68.32 7.01 C68.32 8.57, 67.54 9.35, 65.98 9.35 M68.32 7.01 C68.32 8.57, 67.54 9.35, 65.98 9.35 M65.98 9.35 C49.55 9.35, 33.13 9.35, 2.34 9.35 M65.98 9.35 C42.16 9.35, 18.34 9.35, 2.34 9.35 M2.34 9.35 C0.78 9.35, 0 8.57, 0 7.01 M2.34 9.35 C0.78 9.35, 0 8.57, 0 7.01 M0 7.01 C0 5.89, 0 4.76, 0 2.34 M0 7.01 C0 5.76, 0 4.5, 0 2.34 M0 2.34 C0 0.78, 0.78 0, 2.34 0 M0 2.34 C0 0.78, 0.78 0, 2.34 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(565.2093826976679 155.4142464202933) rotate(0 6.120820957724504 1.1798952533570173)"><path d="M0.59 0 C4.5 0, 8.41 0, 11.65 0 M0.59 0 C4.26 0, 7.94 0, 11.65 0 M11.65 0 C12.04 0, 12.24 0.2, 12.24 0.59 M11.65 0 C12.04 0, 12.24 0.2, 12.24 0.59 M12.24 0.59 C12.24 0.97, 12.24 1.36, 12.24 1.77 M12.24 0.59 C12.24 1.01, 12.24 1.43, 12.24 1.77 M12.24 1.77 C12.24 2.16, 12.04 2.36, 11.65 2.36 M12.24 1.77 C12.24 2.16, 12.04 2.36, 11.65 2.36 M11.65 2.36 C8.93 2.36, 6.22 2.36, 0.59 2.36 M11.65 2.36 C9.39 2.36, 7.14 2.36, 0.59 2.36 M0.59 2.36 C0.2 2.36, 0 2.16, 0 1.77 M0.59 2.36 C0.2 2.36, 0 2.16, 0 1.77 M0 1.77 C0 1.36, 0 0.95, 0 0.59 M0 1.77 C0 1.36, 0 0.95, 0 0.59 M0 0.59 C0 0.2, 0.2 0, 0.59 0 M0 0.59 C0 0.2, 0.2 0, 0.59 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(543.5212615754976 148.27999605115753) rotate(0 6.120820957724504 1.1798952533570173)"><path d="M0.59 0 C5 0, 9.41 0, 11.65 0 M0.59 0 C4.31 0, 8.03 0, 11.65 0 M11.65 0 C12.04 0, 12.24 0.2, 12.24 0.59 M11.65 0 C12.04 0, 12.24 0.2, 12.24 0.59 M12.24 0.59 C12.24 0.97, 12.24 1.35, 12.24 1.77 M12.24 0.59 C12.24 0.84, 12.24 1.09, 12.24 1.77 M12.24 1.77 C12.24 2.16, 12.04 2.36, 11.65 2.36 M12.24 1.77 C12.24 2.16, 12.04 2.36, 11.65 2.36 M11.65 2.36 C8.44 2.36, 5.23 2.36, 0.59 2.36 M11.65 2.36 C9.38 2.36, 7.11 2.36, 0.59 2.36 M0.59 2.36 C0.2 2.36, 0 2.16, 0 1.77 M0.59 2.36 C0.2 2.36, 0 2.16, 0 1.77 M0 1.77 C0 1.31, 0 0.85, 0 0.59 M0 1.77 C0 1.5, 0 1.24, 0 0.59 M0 0.59 C0 0.2, 0.2 0, 0.59 0 M0 0.59 C0 0.2, 0.2 0, 0.59 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(525.3800515946284 113.3990669967398) rotate(0 24.114462888662388 15.125362843360563)"><path d="M7.56 0 C20.09 0, 32.63 0, 40.67 0 M7.56 0 C19.64 0, 31.71 0, 40.67 0 M40.67 0 C45.71 0, 48.23 2.52, 48.23 7.56 M40.67 0 C45.71 0, 48.23 2.52, 48.23 7.56 M48.23 7.56 C48.23 12.52, 48.23 17.47, 48.23 22.69 M48.23 7.56 C48.23 10.61, 48.23 13.67, 48.23 22.69 M48.23 22.69 C48.23 27.73, 45.71 30.25, 40.67 30.25 M48.23 22.69 C48.23 27.73, 45.71 30.25, 40.67 30.25 M40.67 30.25 C30.11 30.25, 19.55 30.25, 7.56 30.25 M40.67 30.25 C33.31 30.25, 25.94 30.25, 7.56 30.25 M7.56 30.25 C2.52 30.25, 0 27.73, 0 22.69 M7.56 30.25 C2.52 30.25, 0 27.73, 0 22.69 M0 22.69 C0 18.53, 0 14.37, 0 7.56 M0 22.69 C0 16.71, 0 10.72, 0 7.56 M0 7.56 C0 2.52, 2.52 0, 7.56 0 M0 7.56 C0 2.52, 2.52 0, 7.56 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(526.8666667938232 166.08515907371572) rotate(0 22.133333206176758 12.5)"><text x="22.133333206176758" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Host</text></g><g stroke-opacity="0" fill-opacity="0" stroke-linecap="round" transform="translate(240.62133841816444 94.62133841816438) rotate(0 58.37866158183567 58.378661581835615)"><path d="M116.76 58.38 C116.76 60.72, 116.61 63.09, 116.33 65.42 C116.05 67.74, 115.62 70.07, 115.06 72.35 C114.5 74.63, 113.8 76.89, 112.96 79.08 C112.13 81.27, 111.16 83.43, 110.07 85.51 C108.98 87.59, 107.76 89.61, 106.42 91.54 C105.09 93.47, 103.63 95.34, 102.08 97.09 C100.52 98.85, 98.85 100.52, 97.09 102.08 C95.34 103.63, 93.47 105.09, 91.54 106.42 C89.61 107.76, 87.59 108.98, 85.51 110.07 C83.43 111.16, 81.27 112.13, 79.08 112.96 C76.89 113.8, 74.63 114.5, 72.35 115.06 C70.07 115.62, 67.74 116.05, 65.42 116.33 C63.09 116.61, 60.72 116.76, 58.38 116.76 C56.03 116.76, 53.67 116.61, 51.34 116.33 C49.01 116.05, 46.69 115.62, 44.41 115.06 C42.13 114.5, 39.87 113.8, 37.68 112.96 C35.48 112.13, 33.33 111.16, 31.25 110.07 C29.17 108.98, 27.15 107.76, 25.22 106.42 C23.29 105.09, 21.42 103.63, 19.67 102.08 C17.91 100.52, 16.24 98.85, 14.68 97.09 C13.13 95.34, 11.67 93.47, 10.33 91.54 C9 89.61, 7.78 87.59, 6.69 85.51 C5.6 83.43, 4.63 81.27, 3.79 79.08 C2.96 76.89, 2.26 74.63, 1.7 72.35 C1.14 70.07, 0.71 67.74, 0.43 65.42 C0.14 63.09, 0 60.72, 0 58.38 C0 56.03, 0.14 53.67, 0.43 51.34 C0.71 49.01, 1.14 46.69, 1.7 44.41 C2.26 42.13, 2.96 39.87, 3.79 37.68 C4.63 35.48, 5.6 33.33, 6.69 31.25 C7.78 29.17, 9 27.15, 10.33 25.22 C11.67 23.29, 13.13 21.42, 14.68 19.67 C16.24 17.91, 17.91 16.24, 19.67 14.68 C21.42 13.13, 23.29 11.67, 25.22 10.33 C27.15 9, 29.17 7.78, 31.25 6.69 C33.33 5.6, 35.48 4.63, 37.68 3.79 C39.87 2.96, 42.13 2.26, 44.41 1.7 C46.69 1.14, 49.01 0.71, 51.34 0.43 C53.67 0.14, 56.03 0, 58.38 0 C60.72 0, 63.09 0.14, 65.42 0.43 C67.74 0.71, 70.07 1.14, 72.35 1.7 C74.63 2.26, 76.89 2.96, 79.08 3.79 C81.27 4.63, 83.43 5.6, 85.51 6.69 C87.59 7.78, 89.61 9, 91.54 10.33 C93.47 11.67, 95.34 13.13, 97.09 14.68 C98.85 16.24, 100.52 17.91, 102.08 19.67 C103.63 21.42, 105.09 23.29, 106.42 25.22 C107.76 27.15, 108.98 29.17, 110.07 31.25 C111.16 33.33, 112.13 35.48, 112.96 37.68 C113.8 39.87, 114.5 42.13, 115.06 44.41 C115.62 46.69, 116.05 49.01, 116.33 51.34 C116.61 53.67, 116.76 56.03, 116.76 58.38" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(268.1499996185303 177.57262149586967) rotate(0 30.850000381469727 12.5)"><text x="30.850000381469727" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Server</text></g><g stroke-linecap="round" transform="translate(280.3658200015225 103.42737850413022) rotate(0 18.63417999847718 34.78380266382396)"><path d="M9.32 0 C16.36 0, 23.41 0, 27.95 0 M9.32 0 C13.88 0, 18.44 0, 27.95 0 M27.95 0 C34.16 0, 37.27 3.11, 37.27 9.32 M27.95 0 C34.16 0, 37.27 3.11, 37.27 9.32 M37.27 9.32 C37.27 27.35, 37.27 45.38, 37.27 60.25 M37.27 9.32 C37.27 23.12, 37.27 36.93, 37.27 60.25 M37.27 60.25 C37.27 66.46, 34.16 69.57, 27.95 69.57 M37.27 60.25 C37.27 66.46, 34.16 69.57, 27.95 69.57 M27.95 69.57 C23.79 69.57, 19.63 69.57, 9.32 69.57 M27.95 69.57 C22.22 69.57, 16.49 69.57, 9.32 69.57 M9.32 69.57 C3.11 69.57, 0 66.46, 0 60.25 M9.32 69.57 C3.11 69.57, 0 66.46, 0 60.25 M0 60.25 C0 43.23, 0 26.22, 0 9.32 M0 60.25 C0 46.41, 0 32.57, 0 9.32 M0 9.32 C0 3.11, 3.11 0, 9.32 0 M0 9.32 C0 3.11, 3.11 0, 9.32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(285.1375628665364 111.12332917008581) rotate(0 14.286204665499099 1.1368683772161603e-13)"><path d="M0 0 C4.76 0, 23.81 0, 28.57 0 M0 0 C4.76 0, 23.81 0, 28.57 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(284.22566016776454 117.52712694769417) rotate(0 14.286204665499099 1.1368683772161603e-13)"><path d="M0 0 C4.76 0, 23.81 0, 28.57 0 M0 0 C4.76 0, 23.81 0, 28.57 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(284.35189604399693 123.93092472530344) rotate(0 14.286204665499099 1.1368683772161603e-13)"><path d="M0 0 C4.76 0, 23.81 0, 28.57 0 M0 0 C4.76 0, 23.81 0, 28.57 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(284.2663606752267 130.33472250291226) rotate(0 14.286204665499099 1.1368683772161603e-13)"><path d="M0 0 C4.76 0, 23.81 0, 28.57 0 M0 0 C4.76 0, 23.81 0, 28.57 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(305.80706962141585 137.26294819896265) rotate(0 3.320581637643386 2.414968463740564)"><path d="M6.64 2.41 C6.64 2.55, 6.62 2.7, 6.59 2.83 C6.56 2.97, 6.51 3.11, 6.44 3.24 C6.38 3.37, 6.29 3.5, 6.2 3.62 C6.1 3.74, 5.99 3.86, 5.86 3.97 C5.74 4.07, 5.6 4.18, 5.46 4.26 C5.31 4.35, 5.15 4.44, 4.98 4.51 C4.81 4.58, 4.64 4.64, 4.46 4.68 C4.28 4.73, 4.09 4.77, 3.9 4.79 C3.71 4.82, 3.51 4.83, 3.32 4.83 C3.13 4.83, 2.93 4.82, 2.74 4.79 C2.55 4.77, 2.37 4.73, 2.18 4.68 C2 4.64, 1.83 4.58, 1.66 4.51 C1.49 4.44, 1.33 4.35, 1.19 4.26 C1.04 4.18, 0.9 4.07, 0.78 3.97 C0.65 3.86, 0.54 3.74, 0.44 3.62 C0.35 3.5, 0.27 3.37, 0.2 3.24 C0.13 3.11, 0.08 2.97, 0.05 2.83 C0.02 2.7, 0 2.55, 0 2.41 C0 2.28, 0.02 2.13, 0.05 2 C0.08 1.86, 0.13 1.72, 0.2 1.59 C0.27 1.46, 0.35 1.33, 0.44 1.21 C0.54 1.09, 0.65 0.97, 0.78 0.86 C0.9 0.76, 1.04 0.65, 1.19 0.56 C1.33 0.48, 1.49 0.39, 1.66 0.32 C1.83 0.25, 2 0.19, 2.18 0.15 C2.37 0.1, 2.55 0.06, 2.74 0.04 C2.93 0.01, 3.13 0, 3.32 0 C3.51 0, 3.71 0.01, 3.9 0.04 C4.09 0.06, 4.28 0.1, 4.46 0.15 C4.64 0.19, 4.81 0.25, 4.98 0.32 C5.15 0.39, 5.31 0.48, 5.46 0.56 C5.6 0.65, 5.74 0.76, 5.86 0.86 C5.99 0.97, 6.1 1.09, 6.2 1.21 C6.29 1.33, 6.38 1.46, 6.44 1.59 C6.51 1.72, 6.56 1.86, 6.59 2 C6.62 2.13, 6.63 2.35, 6.64 2.41 C6.65 2.48, 6.65 2.35, 6.64 2.41" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(10 29) rotate(0 97 72.5)"><path d="M32 0 C73.84 0, 115.69 0, 162 0 M32 0 C59.77 0, 87.53 0, 162 0 M162 0 C183.33 0, 194 10.67, 194 32 M162 0 C183.33 0, 194 10.67, 194 32 M194 32 C194 55.52, 194 79.05, 194 113 M194 32 C194 48.64, 194 65.27, 194 113 M194 113 C194 134.33, 183.33 145, 162 145 M194 113 C194 134.33, 183.33 145, 162 145 M162 145 C111.51 145, 61.03 145, 32 145 M162 145 C132.76 145, 103.53 145, 32 145 M32 145 C10.67 145, 0 134.33, 0 113 M32 145 C10.67 145, 0 134.33, 0 113 M0 113 C0 94.45, 0 75.91, 0 32 M0 113 C0 89.74, 0 66.48, 0 32 M0 32 C0 10.67, 10.67 0, 32 0 M0 32 C0 10.67, 10.67 0, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(19.933334350585938 64) rotate(0 87.06666564941406 37.5)"><text x="87.06666564941406" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Parse the header</text><text x="87.06666564941406" y="42.519999999999996" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">&amp; choose the </text><text x="87.06666564941406" y="67.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">endpoint handler</text></g><g stroke-linecap="round" transform="translate(15 215) rotate(0 85 67.5)"><path d="M32 0 C66.71 0, 101.42 0, 138 0 M32 0 C53.39 0, 74.78 0, 138 0 M138 0 C159.33 0, 170 10.67, 170 32 M138 0 C159.33 0, 170 10.67, 170 32 M170 32 C170 54.65, 170 77.3, 170 103 M170 32 C170 47.79, 170 63.58, 170 103 M170 103 C170 124.33, 159.33 135, 138 135 M170 103 C170 124.33, 159.33 135, 138 135 M138 135 C108.84 135, 79.69 135, 32 135 M138 135 C96.08 135, 54.15 135, 32 135 M32 135 C10.67 135, 0 124.33, 0 103 M32 135 C10.67 135, 0 124.33, 0 103 M0 103 C0 81.04, 0 59.08, 0 32 M0 103 C0 79.6, 0 56.19, 0 32 M0 32 C0 10.67, 10.67 0, 32 0 M0 32 C0 10.67, 10.67 0, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(21.85832977294922 245) rotate(0 78.14167022705078 37.5)"><text x="78.14167022705078" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Load the image</text><text x="78.14167022705078" y="42.519999999999996" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">to memory and </text><text x="78.14167022705078" y="67.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">raise semaphore</text></g><g stroke-linecap="round"><g transform="translate(483 147) rotate(0 -67.5 -1)"><path d="M0 0 C-22.5 -0.33, -112.5 -1.67, -135 -2 M0 0 C-22.5 -0.33, -112.5 -1.67, -135 -2" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(483 147) rotate(0 -67.5 -1)"><path d="M-111.38 -10.2 C-117.88 -7.94, -124.38 -5.69, -135 -2 M-111.38 -10.2 C-117.16 -8.2, -122.94 -6.19, -135 -2" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(483 147) rotate(0 -67.5 -1)"><path d="M-111.64 6.9 C-118.07 4.45, -124.5 2, -135 -2 M-111.64 6.9 C-117.35 4.72, -123.06 2.55, -135 -2" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(356 10) rotate(0 117.9000015258789 37.5)"><text x="0" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Open the website</text><text x="0" y="42.519999999999996" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Choose the image/data</text><text x="0" y="67.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Upload it to the server</text></g><g stroke-linecap="round"><g transform="translate(267 114.75374659571827) rotate(0 -29 -6.594843174112583)"><path d="M0 0 C-9.67 -2.2, -48.33 -10.99, -58 -13.19 M0 0 C-9.67 -2.2, -48.33 -10.99, -58 -13.19" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(267 114.75374659571827) rotate(0 -29 -6.594843174112583)"><path d="M-33.2 -16.32 C-40.26 -15.43, -47.32 -14.54, -58 -13.19 M-33.2 -16.32 C-40.55 -15.39, -47.9 -14.46, -58 -13.19" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(267 114.75374659571827) rotate(0 -29 -6.594843174112583)"><path d="M-36.99 0.36 C-42.97 -3.5, -48.95 -7.36, -58 -13.19 M-36.99 0.36 C-43.22 -3.66, -49.45 -7.68, -58 -13.19" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-opacity="0" fill-opacity="0" stroke-linecap="round" transform="translate(38.62133841816444 490.62133841816444) rotate(0 58.378661581835615 58.378661581835615)"><path d="M116.76 58.38 C116.76 60.72, 116.61 63.09, 116.33 65.42 C116.05 67.74, 115.62 70.07, 115.06 72.35 C114.5 74.63, 113.8 76.89, 112.96 79.08 C112.13 81.27, 111.16 83.43, 110.07 85.51 C108.98 87.59, 107.76 89.61, 106.42 91.54 C105.09 93.47, 103.63 95.34, 102.08 97.09 C100.52 98.85, 98.85 100.52, 97.09 102.08 C95.34 103.63, 93.47 105.09, 91.54 106.42 C89.61 107.76, 87.59 108.98, 85.51 110.07 C83.43 111.16, 81.27 112.13, 79.08 112.96 C76.89 113.8, 74.63 114.5, 72.35 115.06 C70.07 115.62, 67.74 116.05, 65.42 116.33 C63.09 116.61, 60.72 116.76, 58.38 116.76 C56.03 116.76, 53.67 116.61, 51.34 116.33 C49.01 116.05, 46.69 115.62, 44.41 115.06 C42.13 114.5, 39.87 113.8, 37.68 112.96 C35.48 112.13, 33.33 111.16, 31.25 110.07 C29.17 108.98, 27.15 107.76, 25.22 106.42 C23.29 105.09, 21.42 103.63, 19.67 102.08 C17.91 100.52, 16.24 98.85, 14.68 97.09 C13.13 95.34, 11.67 93.47, 10.33 91.54 C9 89.61, 7.78 87.59, 6.69 85.51 C5.6 83.43, 4.63 81.27, 3.79 79.08 C2.96 76.89, 2.26 74.63, 1.7 72.35 C1.14 70.07, 0.71 67.74, 0.43 65.42 C0.14 63.09, 0 60.72, 0 58.38 C0 56.03, 0.14 53.67, 0.43 51.34 C0.71 49.01, 1.14 46.69, 1.7 44.41 C2.26 42.13, 2.96 39.87, 3.79 37.68 C4.63 35.48, 5.6 33.33, 6.69 31.25 C7.78 29.17, 9 27.15, 10.33 25.22 C11.67 23.29, 13.13 21.42, 14.68 19.67 C16.24 17.91, 17.91 16.24, 19.67 14.68 C21.42 13.13, 23.29 11.67, 25.22 10.33 C27.15 9, 29.17 7.78, 31.25 6.69 C33.33 5.6, 35.48 4.63, 37.68 3.79 C39.87 2.96, 42.13 2.26, 44.41 1.7 C46.69 1.14, 49.01 0.71, 51.34 0.43 C53.67 0.14, 56.03 0, 58.38 0 C60.72 0, 63.09 0.14, 65.42 0.43 C67.74 0.71, 70.07 1.14, 72.35 1.7 C74.63 2.26, 76.89 2.96, 79.08 3.79 C81.27 4.63, 83.43 5.6, 85.51 6.69 C87.59 7.78, 89.61 9, 91.54 10.33 C93.47 11.67, 95.34 13.13, 97.09 14.68 C98.85 16.24, 100.52 17.91, 102.08 19.67 C103.63 21.42, 105.09 23.29, 106.42 25.22 C107.76 27.15, 108.98 29.17, 110.07 31.25 C111.16 33.33, 112.13 35.48, 112.96 37.68 C113.8 39.87, 114.5 42.13, 115.06 44.41 C115.62 46.69, 116.05 49.01, 116.33 51.34 C116.61 53.67, 116.76 56.03, 116.76 58.38" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(72.37692161307677 518.7742513488911) rotate(0 25.262497136909758 15.22026225018783)"><path d="M0 0 C-0.05 5.36, -1.44 25.97, -0.31 32.17 C0.81 38.36, -0.63 36.35, 6.75 37.19 C14.12 38.02, 36.59 38.08, 43.93 37.19 C51.28 36.3, 49.71 37.95, 50.84 31.85 C51.96 25.76, 51.94 7.06, 50.68 0.63 C49.43 -5.81, 50.34 -5.52, 43.31 -6.75 C36.27 -7.98, 15.69 -7.87, 8.47 -6.75 C1.26 -5.62, 1.41 -1.12, 0 0 M0 0 C-0.05 5.36, -1.44 25.97, -0.31 32.17 C0.81 38.36, -0.63 36.35, 6.75 37.19 C14.12 38.02, 36.59 38.08, 43.93 37.19 C51.28 36.3, 49.71 37.95, 50.84 31.85 C51.96 25.76, 51.94 7.06, 50.68 0.63 C49.43 -5.81, 50.34 -5.52, 43.31 -6.75 C36.27 -7.98, 15.69 -7.87, 8.47 -6.75 C1.26 -5.62, 1.41 -1.12, 0 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(71.9061918527616 547.8025865683214) rotate(0 25.576316977119802 -7.060946404726337)"><path d="M0 0 C3.74 -2.35, 17.1 -13.29, 22.44 -14.12 C27.77 -14.96, 29.37 -5.44, 32.01 -5.02 C34.65 -4.6, 35.1 -12.11, 38.29 -11.61 C41.48 -11.11, 49.01 -3.64, 51.15 -2.04 M0 0 C3.74 -2.35, 17.1 -13.29, 22.44 -14.12 C27.77 -14.96, 29.37 -5.44, 32.01 -5.02 C34.65 -4.6, 35.1 -12.11, 38.29 -11.61 C41.48 -11.11, 49.01 -3.64, 51.15 -2.04" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(103.75890563408257 519.8726207896264) rotate(0 3.4520182423106576 3.4520182423106576)"><path d="M6.9 3.45 C6.9 3.65, 6.89 3.85, 6.85 4.05 C6.82 4.25, 6.76 4.44, 6.7 4.63 C6.63 4.82, 6.54 5, 6.44 5.18 C6.34 5.35, 6.22 5.52, 6.1 5.67 C5.97 5.82, 5.82 5.97, 5.67 6.1 C5.52 6.22, 5.35 6.34, 5.18 6.44 C5 6.54, 4.82 6.63, 4.63 6.7 C4.44 6.76, 4.25 6.82, 4.05 6.85 C3.85 6.89, 3.65 6.9, 3.45 6.9 C3.25 6.9, 3.05 6.89, 2.85 6.85 C2.66 6.82, 2.46 6.76, 2.27 6.7 C2.08 6.63, 1.9 6.54, 1.73 6.44 C1.55 6.34, 1.39 6.22, 1.23 6.1 C1.08 5.97, 0.94 5.82, 0.81 5.67 C0.68 5.52, 0.56 5.35, 0.46 5.18 C0.36 5, 0.28 4.82, 0.21 4.63 C0.14 4.44, 0.09 4.25, 0.05 4.05 C0.02 3.85, 0 3.65, 0 3.45 C0 3.25, 0.02 3.05, 0.05 2.85 C0.09 2.66, 0.14 2.46, 0.21 2.27 C0.28 2.08, 0.36 1.9, 0.46 1.73 C0.56 1.55, 0.68 1.39, 0.81 1.23 C0.94 1.08, 1.08 0.94, 1.23 0.81 C1.39 0.68, 1.55 0.56, 1.73 0.46 C1.9 0.36, 2.08 0.28, 2.27 0.21 C2.46 0.14, 2.66 0.09, 2.85 0.05 C3.05 0.02, 3.25 0, 3.45 0 C3.65 0, 3.85 0.02, 4.05 0.05 C4.25 0.09, 4.44 0.14, 4.63 0.21 C4.82 0.28, 5 0.36, 5.18 0.46 C5.35 0.56, 5.52 0.68, 5.67 0.81 C5.82 0.94, 5.97 1.08, 6.1 1.23 C6.22 1.39, 6.34 1.55, 6.44 1.73 C6.54 1.9, 6.63 2.08, 6.7 2.27 C6.76 2.46, 6.82 2.66, 6.85 2.85 C6.89 3.05, 6.9 3.35, 6.9 3.45 C6.91 3.55, 6.91 3.35, 6.9 3.45" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(68.07003021240234 562.4662098563756) rotate(0 28.924999237060547 12.5)"><text x="28.924999237060547" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Image</text></g><g stroke-linecap="round"><g transform="translate(356 115) rotate(0 67 0.5)"><path d="M0 0 C22.33 0.17, 111.67 0.83, 134 1 M0 0 C22.33 0.17, 111.67 0.83, 134 1" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(356 115) rotate(0 67 0.5)"><path d="M110.44 9.37 C116.23 7.32, 122.02 5.26, 134 1 M110.44 9.37 C115.25 7.67, 120.06 5.96, 134 1" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(356 115) rotate(0 67 0.5)"><path d="M110.57 -7.73 C116.33 -5.58, 122.08 -3.44, 134 1 M110.57 -7.73 C115.35 -5.94, 120.14 -4.16, 134 1" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(110.27703472336657 175) rotate(0 -0.15626712238702112 18.5)"><path d="M0 0 C-0.05 6.17, -0.26 30.83, -0.31 37 M0 0 C-0.05 6.17, -0.26 30.83, -0.31 37" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(110.27703472336657 175) rotate(0 -0.15626712238702112 18.5)"><path d="M-6.49 19.56 C-4.7 24.63, -2.9 29.69, -0.31 37 M-6.49 19.56 C-5.22 23.14, -3.95 26.73, -0.31 37" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(110.27703472336657 175) rotate(0 -0.15626712238702112 18.5)"><path d="M6.16 19.67 C4.28 24.7, 2.4 29.74, -0.31 37 M6.16 19.67 C4.83 23.23, 3.5 26.79, -0.31 37" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(32.5 387.5) rotate(0 68.5 53.5)"><path d="M26.75 0 C53.39 0, 80.02 0, 110.25 0 M26.75 0 C45.32 0, 63.89 0, 110.25 0 M110.25 0 C128.08 0, 137 8.92, 137 26.75 M110.25 0 C128.08 0, 137 8.92, 137 26.75 M137 26.75 C137 41.47, 137 56.18, 137 80.25 M137 26.75 C137 47.91, 137 69.07, 137 80.25 M137 80.25 C137 98.08, 128.08 107, 110.25 107 M137 80.25 C137 98.08, 128.08 107, 110.25 107 M110.25 107 C84.42 107, 58.6 107, 26.75 107 M110.25 107 C82.73 107, 55.2 107, 26.75 107 M26.75 107 C8.92 107, 0 98.08, 0 80.25 M26.75 107 C8.92 107, 0 98.08, 0 80.25 M0 80.25 C0 68.77, 0 57.28, 0 26.75 M0 80.25 C0 59.65, 0 39.05, 0 26.75 M0 26.75 C0 8.92, 8.92 0, 26.75 0 M0 26.75 C0 8.92, 8.92 0, 26.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(40.59166717529297 403.5) rotate(0 60.40833282470703 37.5)"><text x="60.40833282470703" y="17.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Display the </text><text x="60.40833282470703" y="42.519999999999996" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">image on </text><text x="60.40833282470703" y="67.52" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">LED strip</text></g><g stroke-linecap="round"><g transform="translate(107.99514599999998 350) rotate(0 0 17)"><path d="M0 0 C0 5.67, 0 28.33, 0 34 M0 0 C0 5.67, 0 28.33, 0 34" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(107.99514599999998 350) rotate(0 0 17)"><path d="M-5.81 18.03 C-3.6 24.11, -1.38 30.2, 0 34 M-5.81 18.03 C-4.03 22.94, -2.24 27.85, 0 34" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(107.99514599999998 350) rotate(0 0 17)"><path d="M5.81 18.03 C3.6 24.11, 1.38 30.2, 0 34 M5.81 18.03 C4.03 22.94, 2.24 27.85, 0 34" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask></svg>
</span>

</p>
<h3 id="server-side">Server Side</h3>
<p>We talked high-level so let&rsquo;s now get more concrete and see how it is implemented in code. Everything starts by spawning a thread for TCP IPv4 processing (<em>somehow I got weird crashes when not enabling IPv6</em>) - this thread creates a <strong><a href="https://docs.zephyrproject.org/latest/connectivity/networking/api/sockets.html">BSD socket</a></strong> that will be used as a high-level abstraction for communication with the client.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">process_tcp4</span>(<span style="color:#66d9ef">void</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">struct</span> sockaddr_in addr4;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> ret;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	(<span style="color:#66d9ef">void</span>)<span style="color:#a6e22e">memset</span>(<span style="color:#f92672">&amp;</span>addr4, <span style="color:#ae81ff">0</span>, <span style="color:#66d9ef">sizeof</span>(addr4));
</span></span><span style="display:flex;"><span>	addr4.sin_family <span style="color:#f92672">=</span> AF_INET;
</span></span><span style="display:flex;"><span>	addr4.sin_port <span style="color:#f92672">=</span> <span style="color:#a6e22e">htons</span>(MY_PORT);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	ret <span style="color:#f92672">=</span> <span style="color:#a6e22e">setup</span>(<span style="color:#f92672">&amp;</span>tcp4_listen_sock, (<span style="color:#66d9ef">struct</span> sockaddr <span style="color:#f92672">*</span>)<span style="color:#f92672">&amp;</span>addr4,
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">sizeof</span>(addr4));
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> (ret <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">LOG_DBG</span>(<span style="color:#e6db74">&#34;Waiting for IPv4 HTTP connections on port %d, sock %d&#34;</span>,
</span></span><span style="display:flex;"><span>			MY_PORT, tcp4_listen_sock);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">while</span> (ret <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">||</span> <span style="color:#f92672">!</span>want_to_quit)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		ret <span style="color:#f92672">=</span> <span style="color:#a6e22e">process_tcp</span>(<span style="color:#f92672">&amp;</span>tcp4_listen_sock, tcp4_accepted);
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> (ret <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span>;
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Then we <code>accept</code> and create a thread for receiving the data:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">int</span> <span style="color:#a6e22e">process_tcp</span>(<span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>sock, <span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>accepted)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">static</span> <span style="color:#66d9ef">int</span> counter;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> client;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> slot;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">struct</span> sockaddr_in6 client_addr;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">socklen_t</span> client_addr_len <span style="color:#f92672">=</span> <span style="color:#66d9ef">sizeof</span>(client_addr);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	client <span style="color:#f92672">=</span> <span style="color:#a6e22e">accept</span>(<span style="color:#f92672">*</span>sock, (<span style="color:#66d9ef">struct</span> sockaddr <span style="color:#f92672">*</span>)<span style="color:#f92672">&amp;</span>client_addr,
</span></span><span style="display:flex;"><span>					<span style="color:#f92672">&amp;</span>client_addr_len);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">/* ommited */</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#if defined(CONFIG_NET_IPV4)
</span></span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> (client_addr.sin6_family <span style="color:#f92672">==</span> AF_INET)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		tcp4_handler_tid[slot] <span style="color:#f92672">=</span> <span style="color:#a6e22e">k_thread_create</span>(
</span></span><span style="display:flex;"><span>			<span style="color:#f92672">&amp;</span>tcp4_handler_thread[slot],
</span></span><span style="display:flex;"><span>			tcp4_handler_stack[slot],
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">K_THREAD_STACK_SIZEOF</span>(tcp4_handler_stack[slot]),
</span></span><span style="display:flex;"><span>			client_conn_handler,
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">INT_TO_POINTER</span>(slot),
</span></span><span style="display:flex;"><span>			<span style="color:#f92672">&amp;</span>accepted[slot],
</span></span><span style="display:flex;"><span>			<span style="color:#f92672">&amp;</span>tcp4_handler_tid[slot],
</span></span><span style="display:flex;"><span>			THREAD_PRIORITY,
</span></span><span style="display:flex;"><span>			<span style="color:#ae81ff">0</span>, K_NO_WAIT);
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span><span style="color:#75715e">#endif
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> (LOG_LEVEL <span style="color:#f92672">&gt;=</span> LOG_LEVEL_DBG)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">char</span> addr_str[INET6_ADDRSTRLEN];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">net_addr_ntop</span>(client_addr.sin6_family,
</span></span><span style="display:flex;"><span>					  <span style="color:#f92672">&amp;</span>client_addr.sin6_addr,
</span></span><span style="display:flex;"><span>					  addr_str, <span style="color:#66d9ef">sizeof</span>(addr_str));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">LOG_DBG</span>(<span style="color:#e6db74">&#34;[%d] Connection #%d from %s&#34;</span>,
</span></span><span style="display:flex;"><span>				client, <span style="color:#f92672">++</span>counter,
</span></span><span style="display:flex;"><span>				addr_str);
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Then whenever a request is made we read the data from the socket using the <code>recv</code> API and then match the received endpoint against the list of allowed endpoints (that we specify) - note the <code>parse_header</code> trick I added as the <code>recv</code> reads data in batches and we might have already read the header of the request. It is probably not the most robust way of doing things but for my limited application it works just fine.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">client_conn_handler</span>(<span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>ptr1, <span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>ptr2, <span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>ptr3)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">ARG_UNUSED</span>(ptr1);
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> <span style="color:#f92672">*</span>sock <span style="color:#f92672">=</span> ptr2;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">k_tid_t</span> <span style="color:#f92672">*</span>in_use <span style="color:#f92672">=</span> ptr3;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> client;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> received;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> ret;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">char</span> buf[RECEIVE_BUF_LEN];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">char</span> endpoint_buf[<span style="color:#ae81ff">20</span>];
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">bool</span> parsed_header <span style="color:#f92672">=</span> false;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">method_t</span> method;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	client <span style="color:#f92672">=</span> <span style="color:#f92672">*</span>sock;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		received <span style="color:#f92672">=</span> <span style="color:#a6e22e">recv</span>(client, buf, <span style="color:#66d9ef">sizeof</span>(buf), <span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> (received <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			<span style="color:#75715e">/* Connection closed */</span>
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">LOG_DBG</span>(<span style="color:#e6db74">&#34;[%d] Connection closed by peer&#34;</span>, client);
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">break</span>;
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> (received <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			<span style="color:#75715e">/* Socket error */</span>
</span></span><span style="display:flex;"><span>			ret <span style="color:#f92672">=</span> <span style="color:#f92672">-</span>errno;
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;[%d] Connection error %d&#34;</span>, client, ret);
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">break</span>;
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">LOG_DBG</span>(<span style="color:#e6db74">&#34;[%d] Received data: %.*s&#34;</span>, client, received, buf);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span>parsed_header)
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">parse_header</span>(buf, <span style="color:#66d9ef">sizeof</span>(buf), endpoint_buf, <span style="color:#66d9ef">sizeof</span>(endpoint_buf), <span style="color:#f92672">&amp;</span>method) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>			{
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;[%d] Could not parse header&#34;</span>, client);
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">break</span>;
</span></span><span style="display:flex;"><span>			}
</span></span><span style="display:flex;"><span>			parsed_header <span style="color:#f92672">=</span> true;
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">handle_endpoint</span>(client, endpoint_buf, method, buf, RECEIVE_BUF_LEN) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Handled the endpoint - exiting.&#34;</span>);
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">break</span>;
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	} <span style="color:#66d9ef">while</span> (true);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	(<span style="color:#66d9ef">void</span>)<span style="color:#a6e22e">close</span>(client);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">*</span>sock <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">*</span>in_use <span style="color:#f92672">=</span> NULL;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We first <code>parse_header</code> and allow only ones that we desire - note that this is a <strong>VERY</strong> incomplete HTTP server &#x1f601;</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">int</span> <span style="color:#a6e22e">parse_header</span>(<span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>buf, <span style="color:#66d9ef">int</span> buf_size, <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>endpoint, <span style="color:#66d9ef">int</span> endpoint_size, <span style="color:#66d9ef">method_t</span> <span style="color:#f92672">*</span>method)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>ptr <span style="color:#f92672">=</span> buf, <span style="color:#f92672">*</span>delim_pos <span style="color:#f92672">=</span> NULL;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> len <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">strstr</span>(ptr, <span style="color:#e6db74">&#34;GET&#34;</span>))
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#f92672">*</span>method <span style="color:#f92672">=</span> GET;
</span></span><span style="display:flex;"><span>		ptr <span style="color:#f92672">+=</span> <span style="color:#ae81ff">4</span>; <span style="color:#75715e">// +1 for whitespace
</span></span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">strstr</span>(ptr, <span style="color:#e6db74">&#34;POST&#34;</span>))
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#f92672">*</span>method <span style="color:#f92672">=</span> POST;
</span></span><span style="display:flex;"><span>		ptr <span style="color:#f92672">+=</span> <span style="color:#ae81ff">5</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Unknown method found!&#34;</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	delim_pos <span style="color:#f92672">=</span> <span style="color:#a6e22e">strchr</span>(ptr, <span style="color:#e6db74">&#39; &#39;</span>);
</span></span><span style="display:flex;"><span>	len <span style="color:#f92672">=</span> delim_pos <span style="color:#f92672">-</span> ptr;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> (len <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span> <span style="color:#f92672">&gt;</span> endpoint_size)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Too long endpoint name! Max allowed: %d&#34;</span>, endpoint_size);
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">strncpy</span>(endpoint, ptr, len);
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">*</span>(endpoint <span style="color:#f92672">+</span> len) <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;\0&#39;</span>; <span style="color:#75715e">// null-terminate it
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">LOG_DBG</span>(<span style="color:#e6db74">&#34;Found method of type: %d with endpoint name: %s&#34;</span>, <span style="color:#f92672">*</span>method, endpoint);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Then we handle the endpoint using <code>handle_endpoint</code> the function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">endpoint_t</span> valid_endpoints[NUMBER_OF_ENDPOINTS] <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>	{<span style="color:#e6db74">&#34;/&#34;</span>, GET}, <span style="color:#75715e">// TODO :add handling for favicon :)
</span></span></span><span style="display:flex;"><span>	{<span style="color:#e6db74">&#34;/api/image&#34;</span>, POST},
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">int</span> <span style="color:#a6e22e">handle_endpoint</span>(<span style="color:#66d9ef">int</span> client, <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>endpoint_buf, <span style="color:#66d9ef">method_t</span> method, <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>buf, <span style="color:#66d9ef">int</span> buf_len)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">//  GET /
</span></span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">strncmp</span>(valid_endpoints[<span style="color:#ae81ff">0</span>].name, endpoint_buf, <span style="color:#a6e22e">strlen</span>(endpoint_buf)) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// here we don&#39;t need to check any return values and can directly return the page to render
</span></span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Sending the data to the client!&#34;</span>);
</span></span><span style="display:flex;"><span>		(<span style="color:#66d9ef">void</span>)<span style="color:#a6e22e">sendall</span>(client, content, <span style="color:#66d9ef">sizeof</span>(content));
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">strncmp</span>(valid_endpoints[<span style="color:#ae81ff">1</span>].name, endpoint_buf, <span style="color:#a6e22e">strlen</span>(endpoint_buf)) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>	{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Handling POST /api/image&#34;</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> read_header <span style="color:#f92672">=</span> false;
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">uint8_t</span> length <span style="color:#f92672">=</span> <span style="color:#ae81ff">0u</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> (read_header)
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;rcv_img_offset + buf_len: %d MAX_IMAGE_SIZE: %d&#34;</span>, rcv_img_offset <span style="color:#f92672">+</span> buf_len, MAX_IMAGE_SIZE);
</span></span><span style="display:flex;"><span>			<span style="color:#75715e">// for now this will inform that we handled all
</span></span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">if</span> (rcv_img_offset <span style="color:#f92672">+</span> buf_len <span style="color:#f92672">&gt;=</span> MAX_IMAGE_SIZE)
</span></span><span style="display:flex;"><span>			{
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Stop accepting - Trying to send more data than Image can accept.&#34;</span>);
</span></span><span style="display:flex;"><span>				length <span style="color:#f92672">=</span> MAX_IMAGE_SIZE <span style="color:#f92672">-</span> rcv_img_offset;
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">if</span> (length <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>				{
</span></span><span style="display:flex;"><span>					<span style="color:#75715e">// this contains raw binary data - 0 is null terminator there :)
</span></span></span><span style="display:flex;"><span>					<span style="color:#a6e22e">memcpy</span>(received_image <span style="color:#f92672">+</span> rcv_img_offset, buf, length);
</span></span><span style="display:flex;"><span>				}
</span></span><span style="display:flex;"><span>				rcv_img_offset <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>				read_header <span style="color:#f92672">=</span> false;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// Give the semaphore to notify that a new image is ready
</span></span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">k_sem_give</span>(<span style="color:#f92672">&amp;</span>image_semaphore);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// sleep a short amount so that the waiting thread can read the data
</span></span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">k_sleep</span>(<span style="color:#a6e22e">K_MSEC</span>(<span style="color:#ae81ff">20</span>));
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// Wait for the image to be processed
</span></span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">k_sem_take</span>(<span style="color:#f92672">&amp;</span>image_semaphore, K_FOREVER);
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>			}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">memcpy</span>(received_image <span style="color:#f92672">+</span> rcv_img_offset, buf, buf_len);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>			rcv_img_offset <span style="color:#f92672">+=</span> buf_len;
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">// until get the magic number, keep reading the header 0xBADAD00B
</span></span></span><span style="display:flex;"><span>		<span style="color:#75715e">// there is a slight chance that the magic number will be split between two packets - but for now we don&#39;t handle it
</span></span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>pos <span style="color:#f92672">=</span> <span style="color:#a6e22e">strstr</span>(buf, magic_number);
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> (pos)
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Found the magic number!&#34;</span>);
</span></span><span style="display:flex;"><span>			read_header <span style="color:#f92672">=</span> true;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>			<span style="color:#75715e">// read the remainder as the image data
</span></span></span><span style="display:flex;"><span>			rcv_img_offset <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>			length <span style="color:#f92672">=</span> buf_len <span style="color:#f92672">-</span> (pos <span style="color:#f92672">-</span> buf) <span style="color:#f92672">-</span> <span style="color:#a6e22e">strlen</span>(magic_number);
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">memcpy</span>(received_image, pos <span style="color:#f92672">+</span> <span style="color:#a6e22e">strlen</span>(magic_number), length);
</span></span><span style="display:flex;"><span>			rcv_img_offset <span style="color:#f92672">+=</span> length;
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Still parsing the header&#34;</span>);
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">LOG_ERR</span>(<span style="color:#e6db74">&#34;Unknown endpoint and header!&#34;</span>);
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>You can see that this function is fairly long while not doing that much. The main issue here is that we need to handle each distinct API endpoint differently and also parse/ignore the header fields, I added a magic value of <code>0xBADAB00B</code> to know when my desired payload begins. This magic value is added on the client side as well. Astute readers might note that the magic value might be split between two consecutive buffers - this will be fixed <em>soon</em> but for now we don&rsquo;t really need to care as the header length is fixed - but it should be fixed nonetheless.</p>
<p>When the entirety of the image payload is read the semaphore is kicked and the image is displayed on the LED strip - you might say our job here is done &#x1f601;</p>
<h3 id="client-side">Client Side</h3>
<p>Client-wise we have a very basic HTML + CS + Javascript code. For now it is really basic, but we will put our frontend magic skills to use in a moment so let&rsquo;s go over the full code in a future post. For now just a small snippet that downsamples the uploaded image and calls the <code>/api/image</code> endpoint:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">processImage</span>() {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">fileInput</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;fileInput&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Check if a file is selected
</span></span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">fileInput</span>.<span style="color:#a6e22e">files</span>.<span style="color:#a6e22e">length</span> <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">file</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">fileInput</span>.<span style="color:#a6e22e">files</span>[<span style="color:#ae81ff">0</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Read the file as a data URL
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">reader</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">FileReader</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">reader</span>.<span style="color:#a6e22e">onload</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>(<span style="color:#a6e22e">event</span>) {
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">dataURL</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">target</span>.<span style="color:#a6e22e">result</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// Display the original image preview
</span></span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">originalPreview</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;originalPreview&#39;</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">originalPreview</span>.<span style="color:#a6e22e">innerHTML</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&lt;img src=&#34;&#39;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">dataURL</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#39;&#34; width=&#34;200&#34; alt=&#34;Original Image&#34;/&gt;&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// Create an image element
</span></span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">image</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Image</span>();
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">image</span>.<span style="color:#a6e22e">onload</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>() {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Create a canvas element
</span></span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">canvas</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">createElement</span>(<span style="color:#e6db74">&#39;canvas&#39;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">canvas</span>.<span style="color:#a6e22e">width</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">16</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">canvas</span>.<span style="color:#a6e22e">height</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">16</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">ctx</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">canvas</span>.<span style="color:#a6e22e">getContext</span>(<span style="color:#e6db74">&#39;2d&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Draw the image onto the canvas (resizing it to 16x16)
</span></span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">ctx</span>.<span style="color:#a6e22e">drawImage</span>(<span style="color:#a6e22e">image</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">16</span>, <span style="color:#ae81ff">16</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Get the pixel data from the canvas
</span></span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">imageData</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">ctx</span>.<span style="color:#a6e22e">getImageData</span>(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">16</span>, <span style="color:#ae81ff">16</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">pixelData</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">imageData</span>.<span style="color:#a6e22e">data</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#a6e22e">pixelData</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Create a Uint8Array to store the raw binary data
</span></span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">binaryData</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Uint8Array</span>(<span style="color:#ae81ff">16</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">16</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">3</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">newIdx</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> <span style="color:#f92672">&lt;</span> <span style="color:#a6e22e">pixelData</span>.<span style="color:#a6e22e">length</span>; <span style="color:#a6e22e">i</span> <span style="color:#f92672">+=</span> <span style="color:#ae81ff">4</span>, <span style="color:#a6e22e">newIdx</span> <span style="color:#f92672">+=</span> <span style="color:#ae81ff">3</span>) {
</span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">binaryData</span>[<span style="color:#a6e22e">newIdx</span>] <span style="color:#f92672">=</span> <span style="color:#a6e22e">pixelData</span>[<span style="color:#a6e22e">i</span>];           <span style="color:#75715e">// Red
</span></span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">binaryData</span>[<span style="color:#a6e22e">newIdx</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>] <span style="color:#f92672">=</span> <span style="color:#a6e22e">pixelData</span>[<span style="color:#a6e22e">i</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>];   <span style="color:#75715e">// Green
</span></span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">binaryData</span>[<span style="color:#a6e22e">newIdx</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>] <span style="color:#f92672">=</span> <span style="color:#a6e22e">pixelData</span>[<span style="color:#a6e22e">i</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>];   <span style="color:#75715e">// Blue
</span></span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">processedImage</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">binaryData</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Display the converted image preview
</span></span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">convertedPreview</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;convertedPreview&#39;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">convertedPreview</span>.<span style="color:#a6e22e">innerHTML</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&lt;img src=&#34;&#39;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">canvas</span>.<span style="color:#a6e22e">toDataURL</span>() <span style="color:#f92672">+</span> <span style="color:#e6db74">&#39;&#34; width=&#34;200&#34; alt=&#34;Converted Image&#34;/&gt;&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// Log the binary data to the console
</span></span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#39;Binary Data:&#39;</span>, <span style="color:#a6e22e">binaryData</span>);
</span></span><span style="display:flex;"><span>      };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// Set the image source to the data URL
</span></span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">image</span>.<span style="color:#a6e22e">src</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">dataURL</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Read the file as a data URL
</span></span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">reader</span>.<span style="color:#a6e22e">readAsDataURL</span>(<span style="color:#a6e22e">file</span>);
</span></span><span style="display:flex;"><span>  } <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">alert</span>(<span style="color:#e6db74">&#34;Please select a file before processing.&#34;</span>);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">uploadProcessedData</span>() {
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Create a new Uint8Array to hold the combined data
</span></span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">combinedArray</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Uint8Array</span>(<span style="color:#a6e22e">processedImage</span>.<span style="color:#a6e22e">length</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">8</span>); <span style="color:#75715e">// 8 bytes for the &#34;BADAB00D&#34; string
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Set the first 8 bytes to the &#34;BADAB00D&#34; string
</span></span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">magicHeader</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">TextEncoder</span>().<span style="color:#a6e22e">encode</span>(<span style="color:#e6db74">&#34;BADAB00D&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">combinedArray</span>.<span style="color:#a6e22e">set</span>(<span style="color:#a6e22e">magicHeader</span>, <span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Set the remaining bytes to the processed image data
</span></span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">combinedArray</span>.<span style="color:#a6e22e">set</span>(<span style="color:#a6e22e">processedImage</span>, <span style="color:#ae81ff">8</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Create a binary blob from the combined data
</span></span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">blob</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Blob</span>([<span style="color:#a6e22e">combinedArray</span>]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#39;Sending image + magic:&#39;</span>, <span style="color:#a6e22e">combinedArray</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Add your server endpoint URL here
</span></span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">endpointUrl</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;/api/image&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Upload data to server
</span></span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">fetch</span>(<span style="color:#a6e22e">endpointUrl</span>, {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">method</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;POST&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">body</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">blob</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">headers</span><span style="color:#f92672">:</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#39;Content-Type&#39;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;application/octet-stream&#39;</span> <span style="color:#75715e">// Specify the content type as binary
</span></span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  })
</span></span><span style="display:flex;"><span>  .<span style="color:#a6e22e">then</span>(<span style="color:#a6e22e">response</span> =&gt; <span style="color:#a6e22e">response</span>.<span style="color:#a6e22e">json</span>())
</span></span><span style="display:flex;"><span>  .<span style="color:#a6e22e">then</span>(<span style="color:#a6e22e">data</span> =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Handle server response if needed
</span></span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#39;Server response:&#39;</span>, <span style="color:#a6e22e">data</span>);
</span></span><span style="display:flex;"><span>  })
</span></span><span style="display:flex;"><span>  .<span style="color:#66d9ef">catch</span>(<span style="color:#a6e22e">error</span> =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">error</span>(<span style="color:#e6db74">&#39;Error:&#39;</span>, <span style="color:#a6e22e">error</span>);
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Please note that we convert the RGBA input array to RGB values (this was confusing me because I assumed the input was RGB not RGBA so imagine the rubbish I got on the output - <strong>and even displayed!</strong>). Also, you can see that we are prepending the magic value of <code>BADAB00D</code> so that we may know when we receive the payload.</p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>We have covered most important code that powers this project, still, in a future post I will go over several other additions to this project, such as animations and prettifying the UI. The aim of this blogpost series is for you to understand the most important concepts and be able to follow through by yourself - all <a href="https://github.com/JDuchniewicz/zled-frame">code</a> and <a href="https://github.com/JDuchniewicz/zled-frame-hw">design files</a> are on GitHub so all you really need is to follow my tracks and maybe build something even better &#x1f604;</p>
<p>Next up, me learning <strong>FreeCAD</strong>, discovering yet again that I hate when programmers think cryptic error messages help anyone, 3D printing, re-calibrating my 3D printer, fighting with first-layer adhesion issues and then 3D printing again so stay tuned &#x1f601;</p>
<p>I am leaving you with a picture of my happy face with something working after I assembled and resoldered it:</p>

    <img src="/zledframe/2/preview.jpeg"  alt="Preview of how the project looks so far."  class="center"  style="border-radius: 8px;"  />


<p>Until later! <em>(Yes I know that 2 weeks between blogposts is not feasible - probably one per month is the most often I can)</em></p>
]]></content>
        </item>
        
        <item>
            <title>FOSDEM 2024 - first trip to Brussels</title>
            <link>https://jduchniewicz.com/posts/2024/02/fosdem-2024-first-trip-to-brussels/</link>
            <pubDate>Sat, 10 Feb 2024 12:12:06 +0100</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2024/02/fosdem-2024-first-trip-to-brussels/</guid>
            <description>&lt;p&gt;Rarely do I have a &amp;ldquo;lazy&amp;rdquo; time in the recent months. This month already started with a blast with me going to &lt;strong&gt;&lt;a href=&#34;https://fosdem.org/2024/&#34;&gt;FOSDEM 2024&lt;/a&gt;&lt;/strong&gt; where I delivered &lt;a href=&#34;https://fosdem.org/2024/schedule/event/fosdem-2024-3128-openran-open-source-the-cool-kids-of-telecom-shaking-up-5g-lte-networks/&#34;&gt;a talk&lt;/a&gt; and had an opportunity to meet a ton of like-minded folks! Later this month I might tease some news about upcoming &lt;strong&gt;&lt;a href=&#34;https://www.linuxfoundation.org/research/the-evolution-of-the-open-source-program-office-ospo&#34;&gt;OSPO&lt;/a&gt;&lt;/strong&gt; projects in my company but that is still WiP and wishful thinking on my side&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;brussels-daytrip&#34;&gt;Brussels daytrip&lt;/h2&gt;
&lt;p&gt;I arrived in Brussels early on Friday morning and was forced to travel all the way from Charelroi airport (&lt;em&gt;including standing in 1,5 hour queue just to get on a bus&lt;/em&gt;) where said bus would drive me around Brussels&amp;rsquo; suburbs for yet another 1,5 hour until we arrived in the Brussels Midi station. Thankfully, these were the only inconveniences of the upcoming day.&lt;/p&gt;</description>
            <content type="html"><![CDATA[<p>Rarely do I have a &ldquo;lazy&rdquo; time in the recent months. This month already started with a blast with me going to <strong><a href="https://fosdem.org/2024/">FOSDEM 2024</a></strong> where I delivered <a href="https://fosdem.org/2024/schedule/event/fosdem-2024-3128-openran-open-source-the-cool-kids-of-telecom-shaking-up-5g-lte-networks/">a talk</a> and had an opportunity to meet a ton of like-minded folks! Later this month I might tease some news about upcoming <strong><a href="https://www.linuxfoundation.org/research/the-evolution-of-the-open-source-program-office-ospo">OSPO</a></strong> projects in my company but that is still WiP and wishful thinking on my side&hellip;</p>
<h2 id="brussels-daytrip">Brussels daytrip</h2>
<p>I arrived in Brussels early on Friday morning and was forced to travel all the way from Charelroi airport (<em>including standing in 1,5 hour queue just to get on a bus</em>) where said bus would drive me around Brussels&rsquo; suburbs for yet another 1,5 hour until we arrived in the Brussels Midi station. Thankfully, these were the only inconveniences of the upcoming day.</p>
<p>I won&rsquo;t bore you about all the usual tourist crap, instead let me just leave you with several pictures and the recommendation to eat <strong>Belgian fries</strong>, <strong>drink a Belgian Dubbel or Trippel (or a Blonde)</strong> and <strong>visit the <a href="https://musee-magritte-museum.be/en">Magritte</a> museum</strong> to get a dessert in form of abstract art.</p>
<div class="image-container">
  
      <img src="/fosdem24/brussels_1.jpeg"  alt="Rainy Brussels."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/fosdem24/brussels_3.jpeg"  alt="Brussels European Council."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/fosdem24/brussels_2.jpeg"  alt="Brussels station."  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>Also some works of <em>Magritte</em> that caught my eye (pissed pig or pre-Minecraft voxels):</p>
<div class="image-container">
  
      <img src="/fosdem24/magritte_2.jpeg"  alt="Pissed off pig."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/fosdem24/magritte_1.jpeg"  alt="Matches ad."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/fosdem24/magritte_3.jpeg"  alt="Voxelmania."  class="center"  style="border-radius: 8px;"  />
  

</div>
<h2 id="fosdem-in-general">FOSDEM in general</h2>
<p>I have been encouraged to come to <strong>FOSDEM</strong> for several years already and heard only superlatives about this conference - mainly because it is <em>Free</em> as the <strong>F</strong> in <strong><a href="https://en.wikipedia.org/wiki/Free_and_open-source_software">FOSS</a></strong> and because it has <strong>Beer</strong> as .* in <strong>FOSS</strong> &#x1f601;. I must say I was not disenchanted by a single bit (<em>or byte</em>) as during my entire stay at the premises of the <strong>ULB</strong> where it took place, people have been more than helpful and everyone was in the networking and learning mood that I all so enjoy.</p>
<p><strong><a href="https://www.linkedin.com/in/szymon-duch/">Szymon</a></strong> was supposed to join me but was forced to cancel his talk due to blockers that he faced in the course of his thesis development (the talk was based on his thesis progress) - but worry not, <strong>he will come next year</strong> (even if he does not know that yet :D). Also <strong><a href="https://www.linkedin.com/in/michal-duchniewicz/">Michał</a></strong>, who is not really a developer of <strong>FOSS</strong> software but rather its user, considered coming, since travelling to Brussels from London is fairly quick and still not very expensive (by train).</p>
<p>I must say I am quite envious of my Western European friends who happen to travel from Germany or France to Brussels by train instead of an airplane, but then we have other benefits by being slightly more remote &#x1f604; Let&rsquo;s not get sidetracked though and let&rsquo;s get to the main course of this blogpost - my talk on the role of <strong>Open Source</strong> in the development of <strong>5G</strong> and <strong>LTE</strong> networks.</p>
<div class="image-container">
  
      <img src="/fosdem24/fosdem_4.jpeg"  alt="Me"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/fosdem24/fosdem_3.jpeg"  alt="Campus"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/fosdem24/fosdem_1.jpeg"  alt="Network track packed."  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>There were hallmarks of FOSS everywhere!</p>
<div class="image-container">
  
      <img src="/fosdem24/fosdem_2.jpeg"  alt="Don&#39;t drink Belgian beer or you will end up like the VLC cone!"  class="center"  style="border-radius: 8px;"  />
  

</div>
<h2 id="my-talk">My talk</h2>
<p>Even though it was quite short (<em>around 20 minutes as the Network track was <strong>very</strong> packed this year</em>), <a href="https://fosdem.org/2024/schedule/event/fosdem-2024-3128-openran-open-source-the-cool-kids-of-telecom-shaking-up-5g-lte-networks/">my talk</a> garnered the audience of <strong>around 300 people</strong> that is the biggest so far. This has also been a talk that was more day-job related than my previous ones so I could finally boast of my experience in <strong><a href="https://www.intel.com/content/www/us/en/developer/topic-technology/edge-5g/tools/flexran.html">FlexRAN</a>&rsquo;s development</strong> for <strong>Intel</strong> or other work around <strong>5G</strong> and <strong><a href="https://www.o-ran.org/">ORAN</a></strong> networks. If you were to remember one thing from the talk here it is: <strong>&ldquo;It&rsquo;s great that we have some established projects in the Core Network like <a href="https://www.onap.org/architecture">ONAP</a> or <a href="https://sylvaproject.org/">Sylva</a>, but we <em>really</em> need a solid open source foundation in the lowest layer of the processing chain!&rdquo;</strong></p>
<p>After this call to action you know the gist of my talk, though re-watching it could give you more insight about the current state of the telecom industry and the problems and opportunities that it is currently facing. Apart from the said call-to-action, I explain how <strong>5G</strong> (and especially <strong><a href="https://www.sharetechnote.com/html/5G/5G_RadioProtocolStackArchitecture.html">L1</a></strong>) works and why we care about opening of the ecosystem. I also go over several foundational projects like <strong><a href="https://www.dpdk.org/">DPDK</a></strong>, <strong><a href="https://community.arm.com/arm-community-blogs/b/infrastructure-solutions-blog/posts/arm-ral-is-now-open-source">ARM RAL</a></strong> or <strong>CESNET</strong>&rsquo;s <strong>ORAN MPlane</strong> libraries that all start to form the open source core of <strong>L1</strong> in <strong>5G</strong> and soon <strong>6G</strong>.</p>
<p>I am leaving you here with 2 pictures related to the 5G protocol stack and network topology so that you may at least have a glimpse into the complex world of 5G. The picture below depicts the overall structure of the network with the main components depicted:</p>
<ul>
<li><strong>Radio Unit</strong> - the most <em>physical</em> part of the network, think <strong>very</strong> complex physical calculations being done in <strong>real-time</strong>, so quick that it is implemented on ASICs/FPGAs most of the time.</li>
<li><strong>Distributed Unit</strong> - depending on the network split, more or less calculations are performed here - this is the interface to the <strong>UPF</strong>. Usually up to L2/L3 layers are implemented here.</li>
<li><strong>User Plane Function</strong> - tasked with higher-level functions of the network, such as <em>packet filtering</em> or <em>quality of service</em>.</li>
<li><strong>Core Network</strong> - here be dragons - so many distinct things happening here, from security, to network management, updates and other things that are deemed important by the network operators. Also makes sure your packets are routed to the outside world and that you receive your data &#x1f601;</li>
</ul>











    



    


<span style="display: flex; justify-content: center; align-items: center;">
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155.1359851636707 701.810670167569" width="100%" height="100%">
  <!-- svg-source:excalidraw -->
  
  <defs>
    <style class="style-fonts">
      @font-face {
        font-family: "Virgil";
        src: url("https://excalidraw.com/Virgil.woff2");
      }
      @font-face {
        font-family: "Cascadia";
        src: url("https://excalidraw.com/Cascadia.woff2");
      }
      @font-face {
        font-family: "Assistant";
        src: url("https://excalidraw.com/Assistant-Regular.woff2");
      }
    </style>
    
  </defs>
  <g stroke-linecap="round" transform="translate(212.03188258183536 367.50240393775795) rotate(0 53 57.5)"><path d="M26.5 0 C45.39 -0.72, 64.8 -0.46, 79.5 0 C97.39 -1.56, 108.91 8.86, 106 26.5 C108.68 51.23, 104.51 72.6, 106 88.5 C105.8 108.37, 95.56 117.98, 79.5 115 C68.32 112.21, 54.69 113.82, 26.5 115 C9.53 112.75, 1.14 104.44, 0 88.5 C2.52 75.81, -1.38 58.87, 0 26.5 C2.13 6.25, 5.32 0.87, 26.5 0" stroke="none" stroke-width="0" fill="#ffc9c9"></path><path d="M26.5 0 C44.55 2.03, 59.77 -0.34, 79.5 0 M26.5 0 C37.17 0.37, 48.49 -0.55, 79.5 0 M79.5 0 C98 -1.38, 104.3 7.29, 106 26.5 M79.5 0 C96.15 0.34, 104.48 9.79, 106 26.5 M106 26.5 C107.03 46.79, 106.74 66.3, 106 88.5 M106 26.5 C105 46.6, 105.02 68.47, 106 88.5 M106 88.5 C104.03 107.17, 96.98 113.41, 79.5 115 M106 88.5 C107.17 105.55, 99.2 117.12, 79.5 115 M79.5 115 C65.17 113.08, 54.73 113.94, 26.5 115 M79.5 115 C68.73 114.63, 55.69 114.8, 26.5 115 M26.5 115 C9.6 115.73, -1.47 105.13, 0 88.5 M26.5 115 C8.11 112.84, 1.88 105.51, 0 88.5 M0 88.5 C0.05 66.86, 0.08 43.69, 0 26.5 M0 88.5 C-1.2 68.66, -0.85 46.77, 0 26.5 M0 26.5 C1.69 8.64, 9.81 -0.04, 26.5 0 M0 26.5 C-1.09 10.59, 6.56 -0.32, 26.5 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(224.01625758183536 401.00240393775795) rotate(0 41.015625 24)"><text x="41.015625" y="0" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">RU</text><text x="41.015625" y="24" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">(radio)</text></g><g stroke-linecap="round" transform="translate(372.0672255818354 367.50240393775795) rotate(0 61 57.5)"><path d="M28.75 0 C40.4 -2.07, 54.89 3.8, 93.25 0 C115.47 -3.41, 120.86 8.23, 122 28.75 C119.34 45.6, 122.09 56.15, 122 86.25 C125.03 106.12, 113.1 115.26, 93.25 115 C75.45 116.98, 50.63 113.41, 28.75 115 C12.01 118.32, -0.05 103.2, 0 86.25 C-1.71 77.21, 0.89 60.31, 0 28.75 C2.28 11.23, 6.97 -0.68, 28.75 0" stroke="none" stroke-width="0" fill="#b2f2bb"></path><path d="M28.75 0 C44.56 0.85, 60.6 0.3, 93.25 0 M28.75 0 C49.22 -0.86, 69.86 0.11, 93.25 0 M93.25 0 C113.75 -1.17, 120.02 8.39, 122 28.75 M93.25 0 C114.35 0.27, 123.49 10.93, 122 28.75 M122 28.75 C120.98 51.9, 120.31 70.86, 122 86.25 M122 28.75 C121.86 48.14, 121.73 68.01, 122 86.25 M122 86.25 C121.94 105.09, 114.01 115.21, 93.25 115 M122 86.25 C122.71 105.98, 110.68 115.34, 93.25 115 M93.25 115 C76.31 115.5, 55.36 114.24, 28.75 115 M93.25 115 C75.01 115.63, 55.85 114.99, 28.75 115 M28.75 115 C10.31 114.75, -0.5 105.34, 0 86.25 M28.75 115 C9.81 115.81, -0.77 106.7, 0 86.25 M0 86.25 C-0.66 70.8, -1.67 52.11, 0 28.75 M0 86.25 C-0.95 74.11, 0.81 62.35, 0 28.75 M0 28.75 C1.3 7.79, 8.31 -0.06, 28.75 0 M0 28.75 C0.37 7.56, 9.7 0.97, 28.75 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(380.3328505818354 401.00240393775795) rotate(0 52.734375 24)"><text x="52.734375" y="0" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">DU</text><text x="52.734375" y="24" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">(process)</text></g><g stroke-opacity="0" fill-opacity="0" stroke-linecap="round" transform="translate(9.999999999999886 365.7450803559223) rotate(0 58.378661581835615 58.378661581835615)"><path d="M63.58 -0.71 C72.41 -0.79, 82.66 3.53, 90.08 8.54 C97.5 13.55, 103.51 21.26, 108.09 29.35 C112.68 37.44, 117.19 48.16, 117.61 57.09 C118.03 66.01, 114.84 75.02, 110.63 82.88 C106.41 90.74, 99.51 98.77, 92.32 104.27 C85.13 109.77, 76.14 114.29, 67.47 115.89 C58.8 117.48, 48.9 116.57, 40.29 113.85 C31.69 111.12, 22.34 106.06, 15.84 99.56 C9.33 93.07, 3.67 83.72, 1.27 74.87 C-1.14 66.03, -0.51 55.31, 1.38 46.51 C3.28 37.7, 6.9 29.18, 12.65 22.05 C18.39 14.93, 25.38 6.98, 35.86 3.76 C46.34 0.53, 67.15 1.85, 75.53 2.71 C83.9 3.57, 86.43 7.95, 86.13 8.91 M71.32 2.86 C80.05 3.93, 90.33 9.08, 97.45 15.01 C104.57 20.94, 110.79 29.75, 114.04 38.43 C117.29 47.11, 118.33 58.13, 116.95 67.07 C115.57 76.01, 110.96 84.86, 105.74 92.08 C100.52 99.3, 93.77 106.54, 85.63 110.4 C77.49 114.27, 66.07 115.29, 56.91 115.26 C47.76 115.24, 38.29 114.5, 30.69 110.27 C23.09 106.03, 16.45 97.55, 11.32 89.85 C6.19 82.15, 1.11 72.76, -0.11 64.07 C-1.34 55.38, 0.45 46.22, 3.97 37.73 C7.5 29.23, 14.46 19.12, 21.04 13.12 C27.61 7.11, 34.75 3.38, 43.45 1.71 C52.15 0.04, 68.26 2.98, 73.23 3.09 C78.21 3.19, 73.56 1.73, 73.29 2.34" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(45.933180123023135 375.80757014242516) rotate(0 22.445481458812083 34.327365930073)"><path d="M0 0 C14.68 -1.91, 33.38 -1.91, 44.89 0 M0 0 C14.85 1.32, 30.6 0.03, 44.89 0 M44.89 0 C44.13 15.32, 45.46 31.56, 44.89 68.65 M44.89 0 C45.98 18.79, 45.53 36.61, 44.89 68.65 M44.89 68.65 C28.54 68.73, 11.52 69.66, 0 68.65 M44.89 68.65 C30.07 69.75, 15.73 69.59, 0 68.65 M0 68.65 C0.49 48.61, 1.67 26.17, 0 0 M0 68.65 C-0.93 46.04, -0.36 25.67, 0 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(51.07270188465793 381.0418464268785) rotate(0 17.68634444021592 26.254098365838104)"><path d="M0 0 C11.77 -1.51, 23.05 -0.91, 35.37 0 M0 0 C8.08 -0.71, 13.77 -1.27, 35.37 0 M35.37 0 C36.57 11.28, 34.77 23.72, 35.37 52.51 M35.37 0 C35.64 9.96, 36.39 21.4, 35.37 52.51 M35.37 52.51 C28.16 53.96, 20.3 53.3, 0 52.51 M35.37 52.51 C22.07 53.53, 10.69 52.86, 0 52.51 M0 52.51 C1.56 32.85, 0.16 15.06, 0 0 M0 52.51 C0.23 36.47, 1.18 19.01, 0 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(65.13696358008008 435.79717261973803) rotate(0 3.622082744793545 3.6220827447935733)"><path d="M3.55 0.3 C4.31 0.14, 4.98 0.04, 5.52 0.38 C6.06 0.72, 6.56 1.55, 6.79 2.33 C7.02 3.11, 7.14 4.28, 6.91 5.05 C6.68 5.82, 6.12 6.54, 5.41 6.94 C4.7 7.33, 3.48 7.61, 2.64 7.44 C1.8 7.26, 0.79 6.58, 0.36 5.9 C-0.07 5.22, -0.01 4.13, 0.06 3.37 C0.14 2.61, 0.25 1.96, 0.8 1.36 C1.35 0.75, 2.92 -0.06, 3.36 -0.26 C3.8 -0.46, 3.45 0.01, 3.46 0.16 M3.35 0.44 C3.98 0.43, 4.9 0.82, 5.55 1.26 C6.19 1.7, 6.98 2.37, 7.23 3.1 C7.47 3.83, 7.4 4.91, 7.03 5.64 C6.66 6.37, 5.82 7.24, 5 7.48 C4.19 7.72, 2.88 7.41, 2.15 7.07 C1.41 6.72, 1 6.19, 0.6 5.41 C0.19 4.63, -0.4 3.16, -0.29 2.41 C-0.17 1.66, 0.56 1.4, 1.29 0.92 C2.02 0.44, 3.73 -0.26, 4.11 -0.46 C4.49 -0.65, 3.61 -0.41, 3.54 -0.25" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(56.32124678928142 387.7258499490766) rotate(0 12.437799535592092 6.304023542482355)"><path d="M0 0 C4.23 0.04, 11.26 0.91, 24.88 0 M0 0 C6.02 0.09, 12.87 0.42, 24.88 0 M24.88 0 C24.24 4.28, 24.96 7.99, 24.88 12.61 M24.88 0 C24.66 3.05, 24.99 5.99, 24.88 12.61 M24.88 12.61 C16.2 11.94, 7.4 11.72, 0 12.61 M24.88 12.61 C15.95 12.74, 6.63 13.04, 0 12.61 M0 12.61 C0.06 8.77, -0.64 5.74, 0 0 M0 12.61 C-0.15 8.31, -0.04 4.5, 0 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(56.32124678928142 410.26612516328584) rotate(0 12.437799535592092 6.304023542482355)"><path d="M0 0 C6.82 0.84, 11.47 -0.72, 24.88 0 M0 0 C5.02 0.31, 10.27 -0.14, 24.88 0 M24.88 0 C24.91 4.93, 24.4 10.33, 24.88 12.61 M24.88 0 C24.89 4.06, 25.04 8.02, 24.88 12.61 M24.88 12.61 C17.41 11.58, 8.9 12.57, 0 12.61 M24.88 12.61 C17.52 13.07, 9.57 12.71, 0 12.61 M0 12.61 C-0.63 8.34, 0.15 4.77, 0 0 M0 12.61 C0.03 10.06, 0.25 7.07, 0 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(54.498664328417476 447.43991373309075) rotate(0 13.879997253417969 12.500000000000028)"><text x="13.879997253417969" y="0" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">UE</text></g><g stroke-opacity="0" fill-opacity="0" stroke-linecap="round" transform="translate(299.37866199999985 272.3664183559223) rotate(0 58.37866158183567 58.378661581835615)"><path d="M82.69 5.8 C90.88 8.71, 99.96 16.42, 105.66 23.55 C111.37 30.68, 115.55 39.81, 116.92 48.6 C118.29 57.39, 116.79 67.67, 113.89 76.3 C111 84.92, 106.28 93.89, 99.55 100.34 C92.83 106.8, 82.37 112.56, 73.56 115.05 C64.75 117.54, 55.48 117.12, 46.7 115.28 C37.91 113.43, 27.83 109.69, 20.86 103.96 C13.88 98.22, 8.27 89.4, 4.84 80.86 C1.4 72.32, -0.59 61.72, 0.25 52.72 C1.1 43.71, 5.14 34.22, 9.91 26.81 C14.67 19.4, 21.15 12.82, 28.84 8.24 C36.53 3.67, 45.44 -1.16, 56.03 -0.66 C66.61 -0.17, 84.93 7.88, 92.36 11.2 C99.79 14.53, 100.92 18.54, 100.61 19.27 M54.18 -1.02 C62.39 -2.48, 71.99 2.06, 80.4 5.71 C88.81 9.35, 98.81 13.89, 104.64 20.83 C110.47 27.77, 113.67 38.18, 115.37 47.35 C117.07 56.53, 117.44 67.13, 114.85 75.88 C112.26 84.62, 106.03 93.68, 99.85 99.82 C93.67 105.97, 86.24 110.3, 77.75 112.75 C69.26 115.21, 57.77 115.83, 48.9 114.53 C40.03 113.22, 31.78 110.24, 24.52 104.93 C17.27 99.63, 9.54 90.9, 5.36 82.71 C1.18 74.52, -0.88 64.57, -0.54 55.81 C-0.21 47.05, 2.95 37.78, 7.37 30.16 C11.79 22.54, 18.36 15.32, 25.98 10.09 C33.59 4.86, 48.57 0.18, 53.07 -1.21 C57.56 -2.61, 52.96 0.6, 52.95 1.73" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(339.1231435833579 281.1724584418881) rotate(0 18.63417999847718 34.78380266382396)"><path d="M0 0 C12.53 -0.04, 29.9 -0.12, 37.27 0 M0 0 C13.56 0.87, 28.5 -0.85, 37.27 0 M37.27 0 C36.77 25.51, 38.06 48.57, 37.27 69.57 M37.27 0 C36.71 20.49, 37.4 41.91, 37.27 69.57 M37.27 69.57 C28.22 67.86, 21.4 67.9, 0 69.57 M37.27 69.57 C26.86 68.9, 15.36 70.34, 0 69.57 M0 69.57 C0.97 45.05, 1.79 18.67, 0 0 M0 69.57 C-0.44 43.73, 0.42 19.82, 0 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(343.89488644837184 288.8684091078437) rotate(0 14.286204665499099 1.1368683772161603e-13)"><path d="M0.02 0.23 C4.75 0.41, 23.87 0.5, 28.57 0.48 M-0.64 -0.12 C4.01 -0.05, 23.15 -0.39, 28.13 -0.24" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(342.98298374959995 295.2722068854521) rotate(0 14.286204665499099 1.1368683772161603e-13)"><path d="M-0.01 0.48 C4.69 0.46, 23.49 0.12, 28.18 0.13 M-0.67 0.25 C4.19 0.04, 24.23 -0.68, 29.21 -0.77" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(343.10921962583234 301.67600466306135) rotate(0 14.286204665499099 1.1368683772161603e-13)"><path d="M-0.4 0.13 C4.29 0.14, 23.3 0.62, 28.1 0.53 M0.4 -0.28 C5.25 -0.17, 24.5 -0.2, 29.08 -0.16" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(343.0236842570621 308.07980244067016) rotate(0 14.286204665499099 1.1368683772161603e-13)"><path d="M-0.48 0.53 C4.32 0.44, 23.49 -0.36, 28.38 -0.42 M0.28 0.33 C5.02 0.28, 23.12 0.26, 27.85 0.07" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(364.56439320325126 315.00802813672055) rotate(0 3.320581637643386 2.414968463740564)"><path d="M3.48 0.19 C4.16 0.21, 5.23 0.37, 5.76 0.66 C6.28 0.96, 6.55 1.47, 6.64 1.98 C6.73 2.5, 6.72 3.27, 6.28 3.76 C5.84 4.25, 4.72 4.84, 3.98 4.94 C3.24 5.04, 2.49 4.65, 1.82 4.37 C1.15 4.1, 0.28 3.77, -0.02 3.3 C-0.31 2.82, -0.24 2.06, 0.03 1.54 C0.31 1.02, 1.03 0.42, 1.62 0.19 C2.22 -0.04, 3.23 0.17, 3.59 0.16 C3.96 0.15, 3.84 0.15, 3.8 0.13 M3.59 0.17 C4.24 0.29, 5.38 0.7, 5.86 1.1 C6.34 1.49, 6.39 2.14, 6.47 2.54 C6.55 2.94, 6.75 3.19, 6.36 3.48 C5.97 3.77, 4.82 4.09, 4.14 4.28 C3.47 4.46, 2.97 4.76, 2.32 4.58 C1.66 4.41, 0.62 3.69, 0.22 3.22 C-0.18 2.75, -0.25 2.14, -0.07 1.74 C0.11 1.33, 0.74 1.01, 1.28 0.79 C1.83 0.57, 2.87 0.6, 3.22 0.4 C3.57 0.2, 3.38 -0.4, 3.4 -0.4" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(149.44742258183555 26.745079937757964) rotate(0 -5.684341886080802e-14 327.90063399999997)"><path d="M-0.95 1.01 C-1.15 110.63, -0.46 547.86, -0.45 656.85" stroke="#1e1e1e" stroke-width="2.5" fill="none" stroke-dasharray="1.5 8"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(189.7573235818354 263.7450799377579) rotate(0 164 155)"><path d="M32 0 C101.61 -3.43, 173.53 -3.47, 296 0 M296 0 C318.04 0.78, 329.57 11.21, 328 32 M328 32 C324.74 124.93, 327.56 216.7, 328 278 M328 278 C326.04 300.69, 318.07 308.69, 296 310 M296 310 C238.58 309.07, 183.17 311.35, 32 310 M32 310 C12.01 310.12, 0.52 299.96, 0 278 M0 278 C0.97 215.77, -0.66 154.74, 0 32 M0 32 C1.13 12.59, 10.59 -1.87, 32 0" stroke="#1e1e1e" stroke-width="2.5" fill="none" stroke-dasharray="1.5 8"></path></g><g transform="translate(224.8510735818354 510.7450799377579) rotate(0 128.90625 12)"><text x="0" y="0" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">gNB - the base station</text></g><g stroke-linecap="round"><g transform="translate(109.75732358183541 422.7450799377579) rotate(0 50 0.5)"><path d="M0.11 1.04 C16.76 1.31, 83.37 2.09, 100.07 1.95 M-1.29 0.54 C15.2 0.46, 82.32 0.23, 99.15 0.32" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(109.75732358183541 422.7450799377579) rotate(0 50 0.5)"><path d="M75.66 8.86 C84.7 6.29, 91.88 4.01, 99.15 0.32 M75.66 8.86 C81.51 7.17, 87.32 5.01, 99.15 0.32" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(109.75732358183541 422.7450799377579) rotate(0 50 0.5)"><path d="M75.66 -8.24 C84.75 -5.48, 91.93 -2.41, 99.15 0.32 M75.66 -8.24 C81.63 -5.94, 87.45 -4.11, 99.15 0.32" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(314.7573235818354 427.61209487981876) rotate(0 26 0)"><path d="M0.61 0.03 C9.13 0.05, 43.63 0.2, 52.31 0.07 M-0.53 -1 C7.76 -0.76, 42.71 1.45, 51.52 1.65" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(314.7573235818354 427.61209487981876) rotate(0 26 0)"><path d="M27.67 9.13 C37.25 6.54, 46.84 4.23, 51.52 1.65 M27.67 9.13 C32.77 6.69, 38.98 5.82, 51.52 1.65" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(314.7573235818354 427.61209487981876) rotate(0 26 0)"><path d="M28.44 -7.95 C37.7 -3.72, 46.99 0.8, 51.52 1.65 M28.44 -7.95 C33.49 -6.38, 39.51 -3.21, 51.52 1.65" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(579.7573235818354 322.75819593775793) rotate(0 112.5 107.50000000000003)"><path d="M32 0 C76.88 -3.31, 127.42 1.78, 193 0 C214.66 -1.57, 226.67 7.29, 225 32 C221.7 65.12, 224.28 107.22, 225 183 C226.65 200.88, 217.28 211.5, 193 215 C163.3 216.44, 125.74 216.92, 32 215 C8.93 214.05, -3.23 202.99, 0 183 C-0.78 141.58, 5.51 99.44, 0 32 C-3.11 14, 12.89 -0.15, 32 0" stroke="none" stroke-width="0" fill="#fff9db"></path><path d="M32 0 C75.67 1.26, 122.22 -0.39, 193 0 M32 0 C90.13 -1.26, 149.2 -1.3, 193 0 M193 0 C214.91 0.5, 225.96 11.59, 225 32 M193 0 C213.11 -0.31, 225.47 10.18, 225 32 M225 32 C227.64 64.52, 227.51 100.16, 225 183 M225 32 C225.08 65.98, 226.17 101.1, 225 183 M225 183 C225.39 205.24, 214.22 215.33, 193 215 M225 183 C227.15 204.82, 212.05 214.82, 193 215 M193 215 C148.87 215.17, 100.54 213.17, 32 215 M193 215 C153.39 216.63, 112.22 215.88, 32 215 M32 215 C10.47 216.35, -1.66 203.56, 0 183 M32 215 C9.37 215.83, 0.33 203.2, 0 183 M0 183 C-1.76 123.82, 1.05 66.27, 0 32 M0 183 C-0.09 128.66, -0.65 74.83, 0 32 M0 32 C-0.46 11.89, 10.62 1.88, 32 0 M0 32 C1.05 12.15, 8.44 1.88, 32 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(586.7885735818354 370.25819593775793) rotate(0 105.46875 60.00000000000003)"><text x="105.46875" y="0" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">UPF</text><text x="105.46875" y="24" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">(user plane </text><text x="105.46875" y="48" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">function, packets </text><text x="105.46875" y="72" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">inspection, QoS </text><text x="105.46875" y="96" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">etc.)</text></g><g stroke-linecap="round"><g transform="translate(494.0672255513946 429.25819546354245) rotate(0 39.84504901522041 0.20104459966177046)"><path d="M-0.21 0.7 C13.17 0.48, 67.22 -0.76, 80.59 -0.72 M-1.78 0.03 C11.49 -0.14, 66.58 0.42, 80.12 0.23" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(494.0672255513946 429.25819546354245) rotate(0 39.84504901522041 0.20104459966177046)"><path d="M56.63 8.79 C65.42 7.55, 70.04 3.87, 80.12 0.23 M56.63 8.79 C64.77 5.26, 72.85 2.26, 80.12 0.23" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(494.0672255513946 429.25819546354245) rotate(0 39.84504901522041 0.20104459966177046)"><path d="M56.63 -8.31 C65.5 -3.98, 70.13 -2.08, 80.12 0.23 M56.63 -8.31 C64.6 -5.93, 72.68 -3.02, 80.12 0.23" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-opacity="0" fill-opacity="0" stroke-linecap="round" transform="translate(657.3786620000001 42.86641835592249) rotate(0 90.37866158183556 90.37866158183552)"><path d="M93.68 0.49 C104.98 -0.6, 118.93 3.36, 129.57 8.15 C140.21 12.95, 150.05 20.66, 157.53 29.23 C165.01 37.81, 170.64 48.69, 174.45 59.62 C178.26 70.55, 180.84 83.44, 180.38 94.83 C179.91 106.21, 176.42 117.46, 171.66 127.91 C166.91 138.37, 160.43 149.53, 151.87 157.57 C143.31 165.61, 131.23 172.14, 120.29 176.14 C109.36 180.13, 97.78 182.07, 86.26 181.54 C74.73 181, 61.46 177.84, 51.14 172.93 C40.82 168.02, 31.99 160.83, 24.33 152.08 C16.67 143.33, 9.39 131.48, 5.18 120.45 C0.98 109.42, -1.35 97.43, -0.9 85.91 C-0.45 74.39, 2.68 61.81, 7.88 51.33 C13.09 40.84, 21.78 30.71, 30.32 23.01 C38.87 15.31, 46.63 8.71, 59.18 5.13 C71.72 1.56, 96.12 1.47, 105.57 1.57 C115.03 1.67, 116.27 4.48, 115.9 5.75 M51.47 9.24 C60.74 3.18, 73.99 0.39, 85.45 -0.12 C96.91 -0.64, 109.63 2.48, 120.22 6.14 C130.82 9.8, 140.44 14.56, 149.04 21.84 C157.65 29.12, 166.71 39.21, 171.86 49.82 C177.01 60.44, 179.22 74.04, 179.94 85.53 C180.67 97.02, 179.65 107.92, 176.21 118.75 C172.78 129.59, 166.79 141.81, 159.33 150.55 C151.88 159.29, 141.91 166.28, 131.51 171.18 C121.1 176.09, 108.84 179.35, 96.9 179.96 C84.97 180.58, 71.19 178.71, 59.9 174.85 C48.61 170.99, 37.52 164.15, 29.16 156.8 C20.8 149.46, 14.4 140.67, 9.73 130.78 C5.06 120.89, 1.96 109.31, 1.15 97.48 C0.34 85.64, 1.25 70.67, 4.88 59.77 C8.51 48.87, 15.27 40.27, 22.95 32.09 C30.63 23.92, 46.44 14.09, 50.94 10.71 C55.44 7.33, 49.52 10.89, 49.98 11.83" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(707.2391368872923 152.1171489580715) rotate(0 41.04112875131068 -40.39855243069418)"><path d="M0.11 -1.05 C14.03 -1.4, 67.84 0.88, 84.41 -1.73 C100.98 -4.35, 100.54 -10.37, 99.52 -16.73 C98.49 -23.09, 81.53 -32.13, 78.25 -39.89 C74.96 -47.65, 82.34 -56.42, 79.82 -63.3 C77.3 -70.17, 69.79 -78.65, 63.12 -81.14 C56.45 -83.64, 45.49 -81.1, 39.79 -78.25 C34.09 -75.39, 32.73 -65.42, 28.91 -64 C25.08 -62.58, 20.48 -70.41, 16.84 -69.72 C13.19 -69.03, 8.66 -63.6, 7.05 -59.84 C5.43 -56.08, 9.66 -50.13, 7.15 -47.16 C4.65 -44.19, -4.12 -45.11, -7.99 -42.01 C-11.86 -38.91, -14.77 -33.87, -16.07 -28.55 C-17.37 -23.22, -18.38 -14.7, -15.78 -10.07 C-13.18 -5.44, -2.96 -2.63, -0.48 -0.77 M-1.29 1.02 C12.48 0.76, 67.26 2.57, 83.97 -0.68 C100.69 -3.94, 99.95 -11.6, 99 -18.52 C98.05 -25.44, 81.72 -34.69, 78.26 -42.18 C74.8 -49.67, 80.52 -56.78, 78.24 -63.47 C75.95 -70.17, 70.81 -80.23, 64.55 -82.37 C58.29 -84.5, 46.25 -79.35, 40.67 -76.29 C35.08 -73.23, 35.25 -65.39, 31.05 -64.01 C26.85 -62.62, 19.86 -68.6, 15.46 -67.99 C11.06 -67.38, 6.5 -63.86, 4.65 -60.32 C2.8 -56.78, 6.63 -49.81, 4.36 -46.76 C2.09 -43.7, -5.67 -44.88, -8.96 -42.01 C-12.25 -39.13, -14.65 -35.31, -15.37 -29.51 C-16.09 -23.71, -15.77 -11.86, -13.28 -7.23 C-10.78 -2.6, -2.56 -2.81, -0.4 -1.73" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(472.7573235818354 366.7450799377579) rotate(0 85 -103.5)"><path d="M0.16 0.64 C28.3 -33.73, 140.83 -172, 169.23 -206.46 M-1.22 -0.06 C27.27 -34.78, 142.98 -173.65, 171.54 -208.29" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(472.7573235818354 366.7450799377579) rotate(0 85 -103.5)"><path d="M163.13 -184.75 C167.03 -193.84, 169.65 -199.38, 171.54 -208.29 M163.13 -184.75 C165.52 -194.25, 168.72 -202.56, 171.54 -208.29" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(472.7573235818354 366.7450799377579) rotate(0 85 -103.5)"><path d="M149.96 -195.67 C158.21 -201.16, 165.19 -203.08, 171.54 -208.29 M149.96 -195.67 C157.4 -201.12, 165.55 -205.32, 171.54 -208.29" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(694.2573235818354 319.7450799377579) rotate(0 0.25 -51.5)"><path d="M0.13 0.7 C-0.04 -16.29, -0.6 -85.2, -0.51 -102.36 M-1.26 0.02 C-1.12 -17.28, 1.46 -86.77, 1.67 -104.15" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(694.2573235818354 319.7450799377579) rotate(0 0.25 -51.5)"><path d="M9.61 -80.45 C8.14 -90.25, 5.31 -96.4, 1.67 -104.15 M9.61 -80.45 C6.01 -89.63, 4.82 -96.99, 1.67 -104.15" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(694.2573235818354 319.7450799377579) rotate(0 0.25 -51.5)"><path d="M-7.49 -80.89 C-3.1 -90.56, -0.07 -96.56, 1.67 -104.15 M-7.49 -80.89 C-4.97 -89.86, -0.05 -97.06, 1.67 -104.15" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(645.5945331864866 119.06130793775793) rotate(0 48.66279069767438 46.5)"><path d="M23.25 0 C40.81 -3.11, 52.69 2.86, 74.08 0 C90.24 -2.75, 94.96 9.97, 97.33 23.25 C96.95 39.59, 99.44 60.08, 97.33 69.75 C98.09 84.36, 90.02 93.04, 74.08 93 C56.71 92.36, 42.28 93.71, 23.25 93 C6.65 89.94, 2.2 82.15, 0 69.75 C-0.88 57.05, 1.22 46.45, 0 23.25 C1.33 10.26, 9.19 2.85, 23.25 0" stroke="none" stroke-width="0" fill="#e7f5ff"></path><path d="M23.25 0 C42.54 1.19, 61.91 1.49, 74.08 0 M23.25 0 C34 0.08, 44.5 0.36, 74.08 0 M74.08 0 C87.91 -1.35, 97.19 9.5, 97.33 23.25 M74.08 0 C88.12 1.78, 96.56 9.37, 97.33 23.25 M97.33 23.25 C97.59 38.78, 96.51 51.05, 97.33 69.75 M97.33 23.25 C97.24 41.16, 96.76 58.03, 97.33 69.75 M97.33 69.75 C99.03 83.43, 88.46 91.03, 74.08 93 M97.33 69.75 C96.1 87.51, 87.57 92.55, 74.08 93 M74.08 93 C59.79 91.02, 47.5 92.12, 23.25 93 M74.08 93 C55.99 92.85, 37.1 93.35, 23.25 93 M23.25 93 C6.75 91.5, -0.97 87.12, 0 69.75 M23.25 93 C7.89 93.92, 1.41 86, 0 69.75 M0 69.75 C-1.57 60.33, 1.69 51.22, 0 23.25 M0 69.75 C-0.13 56.35, 0.99 43.85, 0 23.25 M0 23.25 C-1.15 9.71, 9.56 -1.01, 23.25 0 M0 23.25 C0.25 7.33, 5.47 -1.73, 23.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(675.545409821661 152.78195456282882) rotate(0 18.7119140625 12.779353374929102)"><text x="18.7119140625" y="0" font-family="Cascadia, Segoe UI Emoji" font-size="21.29892229154851px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">5GC</text></g><g stroke-linecap="round"><g transform="translate(548.0666685350036 24.745079937757964) rotate(0 0 331.85840558129735)"><path d="M0.59 1.03 C0.89 111.59, 0.79 553.04, 0.7 663.66" stroke="#1e1e1e" stroke-width="2.5" fill="none" stroke-dasharray="1.5 8"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(838.0666685157214 10.403841945528995) rotate(0 -1 340.85840558129735)"><path d="M0.67 -0.4 C0.18 113.03, -2.75 567.57, -3.05 681.41" stroke="#1e1e1e" stroke-width="2.5" fill="none" stroke-dasharray="1.5 8"></path></g></g><mask></mask><g stroke-opacity="0" fill-opacity="0" stroke-linecap="round" transform="translate(967.3786619999996 305.36641835592224) rotate(0 88.87866158183567 88.87866158183562)"><path d="M59.45 6.21 C69.2 1.28, 81.61 -0.26, 92.82 0.23 C104.02 0.72, 116.29 4.45, 126.66 9.14 C137.04 13.83, 147.51 19.92, 155.07 28.36 C162.64 36.8, 168.32 49.01, 172.03 59.79 C175.74 70.57, 177.63 81.86, 177.32 93.04 C177.01 104.23, 174.95 116.61, 170.17 126.91 C165.4 137.21, 157.24 147.24, 148.67 154.85 C140.1 162.46, 129.37 168.81, 118.77 172.58 C108.18 176.34, 96.31 177.93, 85.1 177.42 C73.88 176.91, 61.76 174.31, 51.48 169.51 C41.2 164.71, 31.24 157.08, 23.44 148.63 C15.63 140.17, 8.62 129.46, 4.62 118.76 C0.62 108.05, -1.1 95.76, -0.56 84.4 C-0.01 73.03, 3.02 60.83, 7.89 50.57 C12.76 40.3, 18.22 30.94, 28.67 22.81 C39.11 14.68, 61.58 5.24, 70.57 1.76 C79.55 -1.71, 82.21 0.37, 82.59 1.96 M80.75 0.27 C91.37 -2.28, 105.37 0.5, 116.29 3.78 C127.21 7.05, 137.92 12.55, 146.28 19.9 C154.63 27.25, 161 37.65, 166.42 47.89 C171.84 58.13, 177.79 69.87, 178.79 81.33 C179.79 92.79, 175.93 105.74, 172.41 116.64 C168.89 127.53, 164.52 138.38, 157.66 146.71 C150.8 155.04, 141.19 161.71, 131.26 166.61 C121.33 171.51, 109.53 175.03, 98.07 176.12 C86.61 177.21, 73.52 176.53, 62.51 173.14 C51.5 169.75, 40.55 162.95, 32 155.78 C23.45 148.62, 16.62 139.98, 11.21 130.17 C5.8 120.35, 0.79 108.37, -0.47 96.89 C-1.72 85.42, 0.17 72.19, 3.67 61.3 C7.18 50.41, 13.24 39.98, 20.56 31.56 C27.88 23.13, 37.5 15.84, 47.58 10.76 C57.66 5.68, 75.53 2.35, 81.05 1.09 C86.56 -0.18, 80.53 1.65, 80.67 3.16" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(1016.4116106657045 412.803932286846) rotate(0 40.359975788327006 -39.72806420277141)"><path d="M-0.83 -0.9 C12.79 -1.05, 65.63 2.76, 82.2 -0.07 C98.77 -2.9, 99.35 -11.24, 98.58 -17.88 C97.8 -24.51, 80.72 -32.75, 77.54 -39.89 C74.36 -47.02, 82.23 -54, 79.5 -60.7 C76.76 -67.39, 67.74 -77.39, 61.13 -80.05 C54.51 -82.72, 45.13 -79.61, 39.82 -76.68 C34.5 -73.75, 33.18 -64.01, 29.23 -62.47 C25.28 -60.94, 19.98 -68.08, 16.14 -67.49 C12.31 -66.91, 7.9 -62.76, 6.22 -58.96 C4.54 -55.16, 8.59 -47.62, 6.06 -44.71 C3.53 -41.8, -5.21 -44.38, -8.95 -41.49 C-12.69 -38.61, -15.42 -32.73, -16.38 -27.39 C-17.34 -22.05, -17.39 -13.9, -14.69 -9.47 C-11.99 -5.04, -2.59 -2.25, -0.18 -0.79 M0.94 1.24 C14.37 0.67, 65.08 1.19, 81.33 -1.81 C97.58 -4.81, 99.01 -10.59, 98.43 -16.77 C97.85 -22.94, 81.2 -31.65, 77.86 -38.87 C74.53 -46.08, 81.07 -53.57, 78.43 -60.05 C75.8 -66.53, 68.9 -75.33, 62.06 -77.75 C55.22 -80.17, 43.05 -77.16, 37.39 -74.58 C31.74 -72, 31.95 -63.2, 28.14 -62.24 C24.33 -61.29, 18.05 -69.31, 14.54 -68.86 C11.04 -68.4, 8.45 -63.13, 7.1 -59.5 C5.74 -55.87, 8.73 -50.06, 6.41 -47.08 C4.08 -44.09, -3.11 -44.77, -6.85 -41.59 C-10.58 -38.41, -14.57 -33.25, -15.99 -28 C-17.42 -22.74, -18.07 -14.41, -15.4 -10.04 C-12.72 -5.67, -2.62 -3.47, 0.05 -1.77" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(917.9500608841611 373.4618909377579) rotate(0 67.16279069767438 56.5)"><path d="M28.25 0 C54.48 0.7, 81.23 4.44, 106.08 0 C123.94 -2.12, 135.74 10.36, 134.33 28.25 C137.4 49.51, 137.26 68.4, 134.33 84.75 C131.48 103.07, 126.51 112.57, 106.08 113 C77.66 117.18, 47.99 117.04, 28.25 113 C7.61 114.67, -0.32 101.79, 0 84.75 C-2.05 64.37, 1.3 44.98, 0 28.25 C0.77 12.57, 6.19 -2.88, 28.25 0" stroke="none" stroke-width="0" fill="#d2bab0"></path><path d="M28.25 0 C45.58 2.41, 62.66 0.71, 106.08 0 M28.25 0 C51.52 -0.95, 74.71 -0.66, 106.08 0 M106.08 0 C125.85 1.37, 134.97 8.43, 134.33 28.25 M106.08 0 C122.67 0.76, 135.89 8.49, 134.33 28.25 M134.33 28.25 C134.02 46.89, 135.4 66.26, 134.33 84.75 M134.33 28.25 C134.25 41.86, 134.59 55.18, 134.33 84.75 M134.33 84.75 C132.35 103.92, 123.49 114.82, 106.08 113 M134.33 84.75 C134.13 104.72, 125.76 115, 106.08 113 M106.08 113 C85.6 113.5, 69.15 115.04, 28.25 113 M106.08 113 C83.53 113.43, 58.78 112.25, 28.25 113 M28.25 113 C7.48 111.84, 1.45 101.65, 0 84.75 M28.25 113 C7.25 111.1, -0.85 104.83, 0 84.75 M0 84.75 C-0.22 68.26, -0.72 54.8, 0 28.25 M0 84.75 C-0.51 65.83, -0.72 45.69, 0 28.25 M0 28.25 C1.16 7.82, 10.63 1.18, 28.25 0 M0 28.25 C1.41 11.2, 7.24 1.06, 28.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(935.2144140818355 391.6238308129706) rotate(0 49.8984375 38.33806012478729)"><text x="49.8984375" y="0" font-family="Cascadia, Segoe UI Emoji" font-size="21.29892229154851px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">DN</text><text x="49.8984375" y="25.558706749858214" font-family="Cascadia, Segoe UI Emoji" font-size="21.29892229154851px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">(Data </text><text x="49.8984375" y="51.11741349971643" font-family="Cascadia, Segoe UI Emoji" font-size="21.29892229154851px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">Network)</text></g><g stroke-linecap="round"><g transform="translate(805.7573235818354 429.7980191740901) rotate(0 54 0.15811168817759835)"><path d="M-0.69 0.27 C17.47 0.41, 90.58 1.69, 108.73 1.52 M1.15 -0.63 C19.24 -0.86, 90.43 -0.08, 108.16 0.02" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(805.7573235818354 429.7980191740901) rotate(0 54 0.15811168817759835)"><path d="M84.6 8.38 C91.56 7.4, 99.66 4.18, 108.16 0.02 M84.6 8.38 C90.37 6.49, 94.94 5.64, 108.16 0.02" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(805.7573235818354 429.7980191740901) rotate(0 54 0.15811168817759835)"><path d="M84.74 -8.72 C91.76 -4.94, 99.82 -3.41, 108.16 0.02 M84.74 -8.72 C90.42 -7.05, 94.97 -4.33, 108.16 0.02" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask></svg>
</span>


<p>(If you cannot see some parts of the images, please toggle the <em>Dark/Light</em> theme settings in the context menu - they are .svg so have a transparent background)</p>
<p>Now please take a look at the protocol stack and where <em>exactly</em> is <strong>L1</strong> in all this mess:</p>











    



    


<span style="display: flex; justify-content: center; align-items: center;">
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 274.60597988671884 591" width="30%" height="30%">
  <!-- svg-source:excalidraw -->
  
  <defs>
    <style class="style-fonts">
      @font-face {
        font-family: "Virgil";
        src: url("https://excalidraw.com/Virgil.woff2");
      }
      @font-face {
        font-family: "Cascadia";
        src: url("https://excalidraw.com/Cascadia.woff2");
      }
      @font-face {
        font-family: "Assistant";
        src: url("https://excalidraw.com/Assistant-Regular.woff2");
      }
    </style>
    
  </defs>
  <g stroke-linecap="round" transform="translate(26 501) rotate(0 75.5 32.5)"><path d="M16.25 0 C58.87 -3.82, 93.59 -3.27, 134.75 0 C148.51 -0.93, 153.75 8.96, 151 16.25 C153.15 24.31, 151.5 32.88, 151 48.75 C149.05 61.2, 144.34 67.21, 134.75 65 C95.65 60.69, 51.93 66.73, 16.25 65 C8.61 63.83, -2.66 57.87, 0 48.75 C3.12 41.45, -0.48 29.02, 0 16.25 C-1.25 2.71, 5.88 -1.52, 16.25 0" stroke="none" stroke-width="0" fill="#b2f2bb"></path><path d="M16.25 0 C55.01 -0.78, 94.73 -0.22, 134.75 0 M16.25 0 C60.67 0.73, 107.25 0.99, 134.75 0 M134.75 0 C144.34 -1.7, 152.97 5.96, 151 16.25 M134.75 0 C147.15 -0.66, 151.92 3.85, 151 16.25 M151 16.25 C151.76 24.53, 150.69 31.73, 151 48.75 M151 16.25 C151.09 28.98, 151.61 40.41, 151 48.75 M151 48.75 C150.85 60.05, 146.5 66.83, 134.75 65 M151 48.75 C149.77 58.62, 146.47 62.92, 134.75 65 M134.75 65 C106.32 64.74, 76.12 65.71, 16.25 65 M134.75 65 C99.61 63.99, 65.25 63.58, 16.25 65 M16.25 65 C5.98 63.12, 1.13 58, 0 48.75 M16.25 65 C4.15 65.23, -0.65 61.4, 0 48.75 M0 48.75 C-0.82 36.07, -0.81 28.79, 0 16.25 M0 48.75 C-0.99 37.77, -1.17 24.41, 0 16.25 M0 16.25 C-1.86 6.19, 7.25 -1.63, 16.25 0 M0 16.25 C-1.85 4.58, 5.01 0.41, 16.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(84.22001647949219 521) rotate(0 17.279983520507812 12.5)"><text x="17.279983520507812" y="0" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">PHY</text></g><g stroke-linecap="round" transform="translate(26 421.5) rotate(0 75.5 32.5)"><path d="M16.25 0 C49.31 2.73, 84.24 -3.07, 134.75 0 C142.27 1.25, 153.02 6.74, 151 16.25 C154.54 22.69, 149.53 37.88, 151 48.75 C152.87 61.03, 146.44 63.12, 134.75 65 C104.02 64.75, 64.8 63.48, 16.25 65 C4.42 67.42, -0.95 57.05, 0 48.75 C-2.98 39.67, 2.16 27.3, 0 16.25 C-2.95 5.41, 8.6 -1.62, 16.25 0" stroke="none" stroke-width="0" fill="#ffec99"></path><path d="M16.25 0 C57.37 -1.22, 97.32 1.53, 134.75 0 M16.25 0 C46.83 -1.25, 79.93 -1.46, 134.75 0 M134.75 0 C146.09 1.69, 152.77 4.76, 151 16.25 M134.75 0 C143.89 -1.09, 150.91 3.57, 151 16.25 M151 16.25 C150.71 26.45, 150.55 35.68, 151 48.75 M151 16.25 C150.6 26.47, 150.27 37.06, 151 48.75 M151 48.75 C150.48 59.66, 145.69 64.88, 134.75 65 M151 48.75 C152.22 58.33, 147.6 65.48, 134.75 65 M134.75 65 C109.91 64.6, 86.94 64.36, 16.25 65 M134.75 65 C92.49 66.68, 49.75 66.1, 16.25 65 M16.25 65 C5.42 66.41, 1.98 61.56, 0 48.75 M16.25 65 C3.15 64.22, 0.27 61.87, 0 48.75 M0 48.75 C-0.51 37.16, -1.13 26.91, 0 16.25 M0 48.75 C0.24 42.25, 1.11 36.26, 0 16.25 M0 16.25 C-1.35 7.16, 6.18 1.3, 16.25 0 M0 16.25 C2.01 4.79, 6.25 1.93, 16.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(80.84001159667969 441.5) rotate(0 20.659988403320312 12.5)"><text x="20.659988403320312" y="0" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">MAC</text></g><g stroke-linecap="round" transform="translate(26 342) rotate(0 75.5 32.5)"><path d="M16.25 0 C47.9 -2.9, 84.36 2.2, 134.75 0 C147.56 -2.99, 149.16 5.8, 151 16.25 C153.87 26.35, 147.73 38.39, 151 48.75 C148.58 57.1, 146.72 63.65, 134.75 65 C108.18 62.11, 78.87 63.55, 16.25 65 C8.15 65.65, -2.41 58.3, 0 48.75 C3.37 38.58, -3.79 32.67, 0 16.25 C2.39 8.05, 3.69 0.39, 16.25 0" stroke="none" stroke-width="0" fill="#ffec99"></path><path d="M16.25 0 C59.48 0.68, 101.46 1.47, 134.75 0 M16.25 0 C49.84 -1.39, 83.45 -1.3, 134.75 0 M134.75 0 C146.78 0.32, 152.49 5.74, 151 16.25 M134.75 0 C143.81 -0.56, 149.73 6.66, 151 16.25 M151 16.25 C150.87 22.73, 150.11 31.8, 151 48.75 M151 16.25 C151.47 26.21, 150.81 34.89, 151 48.75 M151 48.75 C149.64 58.73, 143.78 63.45, 134.75 65 M151 48.75 C151.39 59.53, 143.58 64.42, 134.75 65 M134.75 65 C94.1 65.89, 53.5 64.3, 16.25 65 M134.75 65 C94.13 65.34, 52.78 66.97, 16.25 65 M16.25 65 C4.46 63.42, 1.72 61.15, 0 48.75 M16.25 65 C7.16 66.11, 1.9 58.99, 0 48.75 M0 48.75 C0.44 40.64, -0.58 27.91, 0 16.25 M0 48.75 C0.72 35.75, 0.74 23.99, 0 16.25 M0 16.25 C1.86 5.12, 7.3 -0.58, 16.25 0 M0 16.25 C-2.22 3.82, 4.63 1.8, 16.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(82.29000854492188 362) rotate(0 19.209991455078125 12.5)"><text x="19.209991455078125" y="0" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">RLC</text></g><g stroke-linecap="round" transform="translate(26 262.5) rotate(0 75.5 32.5)"><path d="M16.25 0 C42.85 1.62, 70.44 2.02, 134.75 0 C148.22 3.17, 151.38 7.09, 151 16.25 C147.12 25.32, 151.88 39.97, 151 48.75 C153.02 56.22, 144.41 65.64, 134.75 65 C111.77 66.99, 88.07 63.5, 16.25 65 C8.01 66.11, -1.71 61.84, 0 48.75 C2.3 40.17, -2.15 32.08, 0 16.25 C-2.57 6.5, 4.9 -1.15, 16.25 0" stroke="none" stroke-width="0" fill="#ffec99"></path><path d="M16.25 0 C61.88 0.17, 104.33 -1.29, 134.75 0 M16.25 0 C53.92 -1.16, 90.48 -1.13, 134.75 0 M134.75 0 C146.18 0.56, 152.17 4.31, 151 16.25 M134.75 0 C146.35 -2.22, 151.52 6.14, 151 16.25 M151 16.25 C149.25 26.84, 151.04 34.97, 151 48.75 M151 16.25 C150.09 25.76, 151.21 35.98, 151 48.75 M151 48.75 C151.57 59.14, 147.55 63.25, 134.75 65 M151 48.75 C151.01 60.85, 147.01 64.39, 134.75 65 M134.75 65 C90.04 65.81, 50.33 63.42, 16.25 65 M134.75 65 C101.29 65.15, 69.59 63.48, 16.25 65 M16.25 65 C3.88 64.78, -1.21 60.57, 0 48.75 M16.25 65 C3.18 65.51, -1.93 61.77, 0 48.75 M0 48.75 C-1.27 37.1, -0.08 22.01, 0 16.25 M0 48.75 C0.18 38.68, 0.04 27.67, 0 16.25 M0 16.25 C-0.29 4.37, 7.19 -1.42, 16.25 0 M0 16.25 C-0.31 6.78, 7.21 -1.65, 16.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(74.04002380371094 282.5) rotate(0 27.459976196289062 12.5)"><text x="27.459976196289062" y="0" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">PDCP</text></g><g stroke-linecap="round" transform="translate(25 103.5) rotate(0 75.5 32.5)"><path d="M16.25 0 C55.32 -0.11, 88.38 0.22, 134.75 0 C146.84 1.42, 148.49 4.02, 151 16.25 C149.22 24.67, 148.46 30.56, 151 48.75 C148.57 57.97, 142.55 65.73, 134.75 65 C97.57 64.52, 58.88 66.13, 16.25 65 C4.21 62.54, 0.68 62.03, 0 48.75 C1.94 40.05, 0.14 35.9, 0 16.25 C-0.26 4.88, 4.96 2.72, 16.25 0" stroke="none" stroke-width="0" fill="#a5d8ff"></path><path d="M16.25 0 C50.32 2.23, 81.26 0.91, 134.75 0 M16.25 0 C57.74 -0.92, 99.95 0.95, 134.75 0 M134.75 0 C146.28 0.58, 150.5 5.08, 151 16.25 M134.75 0 C144.4 -1.62, 149.41 5.19, 151 16.25 M151 16.25 C149.14 24.66, 151.22 32.05, 151 48.75 M151 16.25 C151.78 28.43, 151.77 38.11, 151 48.75 M151 48.75 C151.28 60.88, 144.93 66.57, 134.75 65 M151 48.75 C152.41 60.1, 145.41 66.16, 134.75 65 M134.75 65 C93.4 67.54, 56.06 66.07, 16.25 65 M134.75 65 C99.83 65.91, 64.26 66.32, 16.25 65 M16.25 65 C4.9 66.42, 1.41 60.26, 0 48.75 M16.25 65 C6.49 65.38, -2.26 57.86, 0 48.75 M0 48.75 C1.74 39.86, -1.93 33.62, 0 16.25 M0 48.75 C0.01 42.41, -0.7 35.39, 0 16.25 M0 16.25 C0.03 5.69, 7.21 0.47, 16.25 0 M0 16.25 C0.51 5.48, 7.3 -1.68, 16.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(80.50000762939453 123.5) rotate(0 19.99999237060547 12.5)"><text x="19.99999237060547" y="0" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">RRC</text></g><g stroke-linecap="round" transform="translate(25 24) rotate(0 75.5 32.5)"><path d="M16.25 0 C52.34 -2.87, 90.69 0.46, 134.75 0 C147.05 2.96, 151.86 1.88, 151 16.25 C152.97 28.22, 152.21 40.31, 151 48.75 C149.85 62, 145.97 64.57, 134.75 65 C87.83 63.87, 47.86 66.43, 16.25 65 C7.65 66.51, 2.93 56.42, 0 48.75 C-0.19 37.77, 2.31 21.96, 0 16.25 C-1.66 8.2, 3.46 -1.4, 16.25 0" stroke="none" stroke-width="0" fill="#a5d8ff"></path><path d="M16.25 0 C60.34 -0.34, 102.71 -0.44, 134.75 0 M16.25 0 C60.8 0.76, 104.37 0.06, 134.75 0 M134.75 0 C147.02 1.47, 150.2 7.39, 151 16.25 M134.75 0 C144.92 -0.22, 151.9 7.53, 151 16.25 M151 16.25 C151.13 27.04, 151.1 39.06, 151 48.75 M151 16.25 C151.92 24.01, 151.91 31.96, 151 48.75 M151 48.75 C152.73 58.87, 144.82 65.76, 134.75 65 M151 48.75 C150.32 59.73, 147.41 63.47, 134.75 65 M134.75 65 C102.27 66.9, 68.83 67.17, 16.25 65 M134.75 65 C95.84 64.55, 56.15 64.67, 16.25 65 M16.25 65 C5.62 63.86, -1.59 58.94, 0 48.75 M16.25 65 C6.41 65.71, -0.91 60.41, 0 48.75 M0 48.75 C-1.41 41.93, -1.93 35.22, 0 16.25 M0 48.75 C0.02 42.16, -1.17 35.02, 0 16.25 M0 16.25 C1.71 6.69, 5.6 -1.21, 16.25 0 M0 16.25 C2.03 5.84, 7.72 -0.88, 16.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(81.42001342773438 44) rotate(0 19.079986572265625 12.5)"><text x="19.079986572265625" y="0" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">NAS</text></g><g stroke-linecap="round" transform="translate(26 183) rotate(0 75.5 32.5)"><path d="M16.25 0 C64.76 -1.62, 103.92 -0.42, 134.75 0 C147.87 -0.45, 149.89 2.56, 151 16.25 C153.19 19.93, 153.72 28.59, 151 48.75 C147.86 58.77, 146.77 68.5, 134.75 65 C108.55 65.56, 80.72 66.02, 16.25 65 C4.73 62.78, -0.45 62.19, 0 48.75 C-1.58 43.01, -2.42 34.04, 0 16.25 C1.62 7.42, 5.32 2.64, 16.25 0" stroke="none" stroke-width="0" fill="#ffec99"></path><path d="M16.25 0 C50.96 -1.54, 84.51 -0.92, 134.75 0 M16.25 0 C43.71 0.76, 70.58 1.8, 134.75 0 M134.75 0 C146.73 -0.11, 151.61 4.1, 151 16.25 M134.75 0 C147.45 1.34, 151.05 3.52, 151 16.25 M151 16.25 C151.77 26.76, 151.45 40.43, 151 48.75 M151 16.25 C152.16 23.68, 151.84 29.64, 151 48.75 M151 48.75 C151.13 59.21, 147.52 64.02, 134.75 65 M151 48.75 C152.22 59.06, 145.75 63.29, 134.75 65 M134.75 65 C108.24 64.14, 78.66 65.64, 16.25 65 M134.75 65 C89.56 65.12, 42.28 65.24, 16.25 65 M16.25 65 C5.67 65.83, 1.37 61.26, 0 48.75 M16.25 65 C5.8 62.74, -2.08 59.42, 0 48.75 M0 48.75 C-1.07 41.3, -0.39 29.79, 0 16.25 M0 48.75 C-0.41 40.15, 0.43 32.12, 0 16.25 M0 16.25 C0.18 5.11, 6.75 -0.35, 16.25 0 M0 16.25 C1.71 6.05, 5.12 -0.72, 16.25 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(74.45001983642578 203) rotate(0 27.04998016357422 12.5)"><text x="27.04998016357422" y="0" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">SDAP</text></g><g stroke-linecap="round" transform="translate(10 491) rotate(0 90.5 45)"><path d="M22.5 0 C59.13 0.72, 97.32 -0.36, 158.5 0 M158.5 0 C174.76 0.6, 180.3 8.59, 181 22.5 M181 22.5 C182.49 36.45, 179.16 51.14, 181 67.5 M181 67.5 C179.65 84.01, 174.94 88.25, 158.5 90 M158.5 90 C116.47 88.8, 72.9 88.93, 22.5 90 M22.5 90 C7.48 89.38, 0.3 83.54, 0 67.5 M0 67.5 C1.76 56.19, 0.12 48.12, 0 22.5 M0 22.5 C0.89 7.01, 8.73 -0.52, 22.5 0" stroke="#1e1e1e" stroke-width="2.5" fill="none" stroke-dasharray="1.5 8"></path></g><g stroke-linecap="round" transform="translate(10 177.5) rotate(0 90.5 156.75)"><path d="M32 0 C72.22 -0.54, 114.16 0.61, 149 0 M149 0 C168.77 -0.63, 182.87 9.34, 181 32 M181 32 C180.36 115.25, 180.83 197.63, 181 281.5 M181 281.5 C179.35 303.02, 171.94 313.69, 149 313.5 M149 313.5 C115.81 312.05, 81.35 313.35, 32 313.5 M32 313.5 C11.84 311.55, 0.7 302.24, 0 281.5 M0 281.5 C0.2 184.94, -0.02 90.21, 0 32 M0 32 C-0.25 10.87, 9.95 -0.27, 32 0" stroke="#1e1e1e" stroke-width="2.5" fill="none" stroke-dasharray="1.5 8"></path></g><g stroke-linecap="round" transform="translate(10 10) rotate(0 90.5 83.75)"><path d="M32 0 C74.42 0.47, 116.57 0.77, 149 0 M149 0 C171.93 0.53, 179.67 9.94, 181 32 M181 32 C181.62 55.22, 179.95 80.37, 181 135.5 M181 135.5 C179.86 158.08, 168.97 165.9, 149 167.5 M149 167.5 C121.56 169.81, 93.33 169.69, 32 167.5 M32 167.5 C9.77 165.5, -1.22 155.69, 0 135.5 M0 135.5 C-0.55 101.35, 0.76 66.44, 0 32 M0 32 C0.33 10.43, 10.17 1.77, 32 0" stroke="#1e1e1e" stroke-width="2.5" fill="none" stroke-dasharray="1.5 8"></path></g><g transform="translate(218.52599299999997 71.25) rotate(0 23.039993286132812 22.5)"><text x="0" y="0" font-family="Virgil, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">L3</text></g><g transform="translate(217.4099960000001 311.75) rotate(0 23.597991943359375 22.5)"><text x="0" y="0" font-family="Virgil, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">L2</text></g><g transform="translate(225.3479920000002 513.5) rotate(0 15.659996032714844 22.5)"><text x="0" y="0" font-family="Virgil, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">L1</text></g></svg>
</span>


<p>In all honesty, if you are at least slightly interested in <strong>5G</strong> networks and about their current state, my talk will give you at least some knowledge and point you to proper resources to learn more. And if said topics are something that resonate with you, we will be more than happy than work with you (we meaning my current employer - <strong><a href="https://www.tietoevry.com/">Tietoevry</a></strong>).</p>
<h2 id="zephyr-emulators-and-retrocomputing">Zephyr, Emulators and Retrocomputing</h2>
<h3 id="zephyr">Zephyr</h3>
<p>Having talked more than 2 hours with folks after my talk I managed to catch up with people from the <strong><a href="https://www.zephyrproject.org/">Zephyr</a></strong> project and we even went for a dinner where we discussed our recent experiences with various chips (I could prattle about <a href="https://jduchniewicz.com/posts/2024/01/z-led-frame-or-how-to-illuminate-your-art-with-zephyr-part-1-intro-and-prototyping/">my struggles</a> with <strong>ESP32C6</strong> and lack of support for it - <em>yet</em>). If any of you is into embedded development and is currently searching for a great and friendly project - search no more - <strong>Zephyr</strong> got you covered. Meeting with them reminded me to push the PRs that enhance the documentation to the <strong>HTTP server samples</strong> which I have currently been porting to my <strong><a href="https://github.com/JDuchniewicz/zled-frame/tree/main">newest project</a></strong>.</p>
<p>I managed to catch several hours of sleep (<em>next to the European Council - the Schumann station</em>) and went for another busy day which I spent almost entirely on two tracks - <strong>Emulators</strong> and then <strong>Retrocomputing</strong>. Every time I meet folks that do these things I get a small impostor syndrome - how can you be an electronics, system, and game developer at the same time?! Well, it turns out that with dedication and commitment (and a ton of curiosity) such people are molded. Needless to say, <strong>mark my words</strong>, my next project will be in the emulation area (but more on that in future blogposts &#x1f601;)&hellip;</p>
<div class="image-container">
  
      <img src="/fosdem24/zephyr.jpg"  alt="Zephyr Dinner!"  class="center"  style="border-radius: 8px;"  />
  

</div>
<h3 id="emulators">Emulators</h3>
<p>I won&rsquo;t cover all talks from these tracks but rather focus on the most eyebrow raising ones:</p>
<p>The Emulator track opened with talks on my beloved <strong>GameBoy</strong> emulation and getting started with that. Firstly we had a talk on <strong>Nintendo 3DS</strong> emulator - <strong><a href="https://github.com/wheremyfoodat/Panda3DS">Panda3DS</a></strong> including a very in-depth discussion about various <strong>3DS</strong> internals and peripherals. Probably the most important useless fact is that <strong>Nintendo did software SHA calculation even though they had a hardware chip to EXACTLY DO THAT</strong> &#x1f601;</p>
<p>Next up, there was a talk on approaching emulation and reverse-engineering <strong>Android operating system</strong> including the oh-so-dreaded <strong>Primary Bootloader</strong>, which turns out to be a <em>very</em> complex code when disassembled. I really enjoyed the talk because we could have a glimpse how a national institution approaches such problems - and believe me they do it very professionally. Also, it included using <strong><a href="https://ghidra-sre.org/">Ghidra</a></strong> and live patching the binary with scripts, <strong><a href="https://www.unicorn-engine.org/showcase/">Unicorn</a></strong> and <strong><a href="https://github.com/qilingframework/qiling">Qiling</a></strong> to make the program behave as the researcher deemed it. I also learned a new word (or a neologism) <em>Concolic execution</em> - which is a conjunction of <em>concrete</em> and <em>symbolic</em>. Basically it means that we choose heuristics to progress with the program execution to cover all of our desired paths <em>(though I know it is still complex&hellip;)</em></p>
<p>There was also a talk on how <strong>Microsoft</strong> <a href="https://fosdem.org/2024/schedule/event/fosdem-2024-1762-arm64ec-microsoft-s-emulation-frankenstein/">recently started</a> supporting <strong>ARM64EC</strong> (which stands for emulated code), where I could learn about the pleasures (or lack of them) in marrying <strong>x86</strong> instruction set with <strong>ARM64</strong> one with both of them having different register/flag and caller/callee register preserving conventions. I highly recommend watching it if you like to listen how <strong>Microsoft</strong> chose <em>the proper way</em> to approach a problem that is solved by the rest of us in a <strong>totally</strong> different way &#x1f601;</p>
<h3 id="retrocomputing">Retrocomputing</h3>
<p>The next half of the day was dedicated to retrocomputing machines, such as <strong>Z80</strong>, <strong>GameBoy Advanced</strong> one more time and the mysterious <strong>Sanco 6003</strong> computer. The hero of the first talk was a <strong>Commodore CBM II</strong>. I don&rsquo;t stop to be amazed by the ingenuity of older computer designs - and I was not disappointed now - this machine had a possibility for connecting a secondary CPU to be working either as the main one or a co-processor!</p>
<p>If you are curious about other such examples, I highly recommend The <em>Bald Engineer</em> and <a href="https://hackaday.com/2022/12/23/an-almost-single-chip-apple-iie/">his talk</a> from last year&rsquo;s <a href="https://hackaday.io/superconference/">Hackaday Supercon</a> about bringing the Apple ][ machine to life. (It&rsquo;s a link to his video on that topic - could not find the actual recording&hellip;)</p>
<p>The talk on <strong>GBA</strong> mostly tackled tooling and resources for folks who want to hack around with this retro piece of console (<em>like me</em>) that I will shamelessly plug in here:</p>
<ul>
<li><a href="https://gbdev.io/">gbdev.io</a> - community page for GBA hackers</li>
<li><a href="https://github.com/Gekkio/gb-ctr">CTR</a> - a Complete Technical Reference for GBA</li>
<li><a href="https://www.romhacking.net/">romhacking</a> - a collection of hacked ROMs that are free to use and peruse (and to contribute of course &#x1f604;)</li>
<li><a href="https://github.com/ahrnbom/gbapfomgd">assembly</a> - GB Assembly for modern Game Developer</li>
<li><a href="https://gbdev.io/gb-asm-tutorial/">GB ASM tutorial</a> - how to make GB games from scratch</li>
</ul>
<p>Lastly, I <em>really</em> enjoyed and kept grinning when 2 guys were presenting their <a href="https://fosdem.org/2024/schedule/event/fosdem-2024-2008-a-journey-documenting-the-sanco-8003-computer/">thrash-prize</a> - <strong>Sanco computer</strong> that turned out to be Franco-Japanese machine that (<em>no surprise here</em>) had scarce documentation. They reverse engineered the schematic (**from the traces on the board!!!*) and continue to add support and documentation for it. When they were talking about solutions on printing the characters to the screen and how the characters are stretched vertically or horizontally using very simple combinatorial circuits, for a moment I wished I was back at Uni doing Boolean tables and digital circuit optimization. But worry not, this moment passed as quickly as it arrived &#x1f601;</p>
<h2 id="summary">Summary</h2>
<p>Although this was the first <strong>FOSDEM</strong> I ever attended, it surely won&rsquo;t be the last - Michal and Szymon, shame on you if you don&rsquo;t come next year! The sheer number of people attending this event made me feel a part of something greater even more so than during my last year&rsquo;s <strong>GDC</strong>. What&rsquo;s better, this event was all about <strong>FREE technologies that happen to power most of our modern world</strong> and are ever so important while, sadly, often overlooked. Being part of these conferences always makes me want more and gives me food for thought and new projects ideas &#x1f601; Speaking of, I need to get back to the <strong>ZLED project</strong> that already started gathering some dust as I didn&rsquo;t shine these LEDs while being sucked in by the Zephyr&rsquo;s networking stack. Worry not, we will have a shiny <strong>3D printed case</strong> for the frame soon . Until then!</p>
]]></content>
        </item>
        
        <item>
            <title>Z LED Frame, or how to illuminate your art with Zephyr - part 1: Intro and prototyping</title>
            <link>https://jduchniewicz.com/posts/2024/01/z-led-frame-or-how-to-illuminate-your-art-with-zephyr-part-1-intro-and-prototyping/</link>
            <pubDate>Sat, 20 Jan 2024 13:00:57 +0100</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2024/01/z-led-frame-or-how-to-illuminate-your-art-with-zephyr-part-1-intro-and-prototyping/</guid>
            <description>&lt;p&gt;Winter is the time for long, cozy evenings, catching up with your favorite games, TV series or books and maybe even some snow (&lt;strong&gt;looking at you Warsaw 2024&lt;/strong&gt; &amp;#x1f440;). For me it turned out to also be a stimuli to &lt;strong&gt;embrace my inner maker/hacker spirit&lt;/strong&gt; and do more of the stuff that requires soldering/prototyping and, in general, making stuff. Last year&amp;rsquo;s &lt;a href=&#34;https://hackaday.io/superconference/&#34;&gt;Hackaday Supercon&lt;/a&gt; inspired me not to wait for ages until my skillset is complete and only then attempt to build an &lt;em&gt;opus magnum&lt;/em&gt; but rather &lt;em&gt;start now, smaller, gradually building up&lt;/em&gt;. Also, I thought that maybe it is worth putting my skills to use in &lt;strong&gt;some down-to-earth projects&lt;/strong&gt; that can have &lt;strong&gt;real&lt;/strong&gt; impact on my everyday life and &lt;strong&gt;will stick around for years to come&lt;/strong&gt;. This is accompanied by mine and other members of &lt;a href=&#34;https://stickypistonstudios.com/&#34;&gt;Sticky Piston Studios&lt;/a&gt; mindset of embracing the technology no matter its branch - see our &lt;a href=&#34;https://github.com/Sticky-Piston-Studios/Sticky-Web-Platform&#34;&gt;Sticky Web Platform&lt;/a&gt; where we keep on lowering the entry bar of deploying your own websites and services. (&lt;strong&gt;shameless marketing&lt;/strong&gt; &amp;#x1f604;)&lt;/p&gt;</description>
            <content type="html"><![CDATA[<p>Winter is the time for long, cozy evenings, catching up with your favorite games, TV series or books and maybe even some snow (<strong>looking at you Warsaw 2024</strong> &#x1f440;). For me it turned out to also be a stimuli to <strong>embrace my inner maker/hacker spirit</strong> and do more of the stuff that requires soldering/prototyping and, in general, making stuff. Last year&rsquo;s <a href="https://hackaday.io/superconference/">Hackaday Supercon</a> inspired me not to wait for ages until my skillset is complete and only then attempt to build an <em>opus magnum</em> but rather <em>start now, smaller, gradually building up</em>. Also, I thought that maybe it is worth putting my skills to use in <strong>some down-to-earth projects</strong> that can have <strong>real</strong> impact on my everyday life and <strong>will stick around for years to come</strong>. This is accompanied by mine and other members of <a href="https://stickypistonstudios.com/">Sticky Piston Studios</a> mindset of embracing the technology no matter its branch - see our <a href="https://github.com/Sticky-Piston-Studios/Sticky-Web-Platform">Sticky Web Platform</a> where we keep on lowering the entry bar of deploying your own websites and services. (<strong>shameless marketing</strong> &#x1f604;)</p>

    <img src="/zledframe/1/sunset.jpg"  alt="Gorgeous sunset in Bad Gastein."  class="center"  style="border-radius: 8px;"  />


<p>Thus, after thinking what project would I really like to have around that would be a base for my further reverse-engineering/retro-gaming efforts, I came up with the <strong>LED-frame</strong> concept that has already had several previous renditions, like <a href="https://marian42.de/article/ledmatrix/">Raspberry-Pi Frame</a>, <a href="https://www.daftmike.com/2018/03/led-matrix-animation-frame.html">or another similar one</a>. Since in previous attempts some things were left out and, to my knowledge, none of previous efforts utilized <a href="https://github.com/zephyrproject-rtos/zephyr">Zephyr</a> and less powerful MCUs like <a href="https://www.espressif.com/en/products/socs/esp32">ESP32</a>, I decided to share my work on this project here, and maybe on some other social media platforms (not really an avid user of any of them). Of course, all of the project will be shared on my <a href="https://github.com/JDuchniewicz/zled-frame">GitHub</a> as I live by the rules of <strong>Free Open Source Software (and hardware)</strong>, in fact I am travelling to this year&rsquo;s <a href="https://fosdem.org/2024/">FOSDEM</a> so expect some updates from there too!</p>
<h2 id="goal-and-how-to-get-there">Goal and how to get there?</h2>
<p>The goal here is quite straightforward - I want to have a physical LED frame that I can hang in my living room that would display static/animated pictures of my choice on a 16x16 pixel grid. As with all ideas, it is too vague so let&rsquo;s flesh it out then:</p>
<ul>
<li><strong>Physical LED frame</strong> - meaning that I will have to design it and then either build from regular materials like wood or plastic, or 3D-print it. In my case it will be the latter, but I am not restricting anyone here &#x1f601;.</li>
<li><strong>16x16 pixel grid</strong> - sounds like I need to have either separate pixels or use a LED strip, or even have an entire programmable LED array - I chose the LED strip for its cost and malleability.</li>
<li><strong>display static/animated pictures of my choice</strong> - this means I need a way of communicating with the frame, so it definitely needs to be <em>smart</em> (the question is how smart).</li>
</ul>
<p>Now that it sounds less like a wish and more like engineering project, let&rsquo;s address the rest of the requirements that were not voiced anywhere:</p>
<ul>
<li><strong>Controller</strong> - implied in the design is of course the fact that something needs to drive the LEDs and decide what to display there, in my case it will be <a href="https://www.espressif.com/en/products/socs/esp32">ESP32</a> (tried the new one based on <a href="https://riscv.org/">RISC-V</a>, more on that later).</li>
<li><strong>Power management</strong> - since LEDs are powered from 5V voltage source and <a href="https://www.espressif.com/en/products/socs/esp32">ESP32</a> is capable of outputting only 3.3V we need either a logic-level shifter or separate voltage source.</li>
<li><strong>Data processing</strong> - displaying <em>stuff</em> on such a small resolution requires some image pre-processing and we are speaking about <strong>embedded</strong> devices that might not have the processing power.</li>
<li><strong>Communication</strong> - well, how to interface the <strong>Controller</strong>? We have mediums/protocols of choice, such as HTTP over Wi-Fi or using <a href="https://en.wikipedia.org/wiki/Bluetooth_Low_Energy">BLE</a> for simpler communication.</li>
</ul>
<h3 id="steps">Steps</h3>
<p>Okay, now it seems like we have something tangible. Let me present you the plan to get there - by taking small steps and documenting my progress so people can follow along:</p>
<ul>
<li>First, there is this blogpost that introduces the project and the prototype.</li>
<li>Then, we will have either one or two that dig into the details of setting up a HTTP server on <a href="https://github.com/zephyrproject-rtos/zephyr">Zephyr</a>, connecting the LEDs and displaying the picture of choice on them.</li>
<li>We also need to talk about assembly and some hardware stuff, like 3D design and printing (here I am a layman and I might request <a href="https://www.linkedin.com/in/szymon-duch/">Szymon</a>&rsquo;s help.</li>
<li>Lastly, we should talk about powering it up, having some Li-Po (or other) battery and a charging circuit.</li>
<li>(there might be changes to the schedule along the way, since we need to design the Frontend for the controlling website, dig around Zephyr, etc.) - <strong>but expect a blogpost roughly every 2 weeks!</strong></li>
</ul>
<p>After the last blogpost we should have a solid base for further experiments and extensions to this project, but I am will not jump ahead and first <strong>focus on actually assembling it</strong>!</p>
<h2 id="prototyping">Prototyping</h2>
<p>Here I won&rsquo;t go into very technical details (this will be done in the second blogpost), rather I will focus on why even do prototyping and why not do it <em>The Proper Way(TM)</em>. If any of you worked on a big software/hardware (and got forbid a mix of both) engineering project, you probably know that the path from A (conception) to B (the product doing something <em>useful</em>) is <em>loooooooooooong</em>. I think the complexity is logarithmic here (but don&rsquo;t quote me on that &#x1f601;), the more people and components are involved, the more things can go wrong and therefore <strong>will</strong> go wrong thanks to our old friend - statistics.</p>
<p>So, how to quickly ascertain that an idea is tangible and can be realized? By <strong>rushing</strong> to have something <strong>very basic ASAP</strong> - this means prototyping (there even is an earlier form of it called <a href="https://www.pretotyping.org/"><em>pretotyping</em></a>, that validates the idea even earlier!). Following this ideology, my way forward with this project was simple - <strong>have something displayed on a basic LED grid ASAP</strong>. This usually means doing nasty hackish things, such as copy-pasting code from samples, putting everything into <code>main.c</code> and using cardboard/paper scraps for assembly. And, that&rsquo;s exactly what I did and am totally not ashamed to showcase in the pictures below &#x1f601;.</p>
<p>The exact steps of connecting and powering the LED matrix are coming soon and for now please accept some teasers!</p>
<div class="image-container">
  
      <img src="/zledframe/1/proto1.jpg"  alt="Wiring up the ESP32"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/zledframe/1/proto2.jpg"  alt="First cuts."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/zledframe/1/proto3.jpg"  alt="Something assembled."  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>After some more assembly:</p>
<div class="image-container">
  
      <img src="/zledframe/1/proto4.jpg"  alt="All soldered."  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/zledframe/1/proto5.jpg"  alt="SHINY!"  class="center"  style="border-radius: 8px;"  />
  

</div>
<p>And finally the classic blinky!</p>

<div class="video-container">
    <iframe width="429" height="763" src="https://www.youtube.com/embed/TiEBmr2SlWo" title="ZLED matrix part 1: Blinking the prototype" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</div>


<h2 id="esp32c6">ESP32C6</h2>
<p>While I promised not to get very technical in this post, I should present my reasoning of choosing <a href="https://www.espressif.com/en/products/socs/esp32">ESP32</a> for this task. Previous year, I attended the <a href="https://jduchniewicz.com/posts/2023/11/hackaday-supercon-2023-/-risc-v-summit-na/">RISC-V Summit NA</a> where I obtained a cute <a href="https://www.espressif.com/en/products/socs/esp32-c6">ESP32C6</a> prototype board (thanks Tiffany!) and decided to use it for this project to further my <a href="https://riscv.org/">RISC-V</a> knowledge. However, as <a href="https://github.com/zephyrproject-rtos/zephyr/discussions/62138">it turns out</a>, the board is not yet supported in the Zephyr ecosystem, and basing on my <a href="https://jduchniewicz.com/posts/2023/07/embedded-open-source-summit-2023/">previous experience</a> with adding more support for a particular board to Zephyr, I decided to focus on the project first and then invest my time into that (if it were my daily job, then sure why not now). So rest assured, I will go back to this board and give you more updates on that &#x1f604;</p>
<h2 id="summary">Summary</h2>
<p>As usual, I hope you gained something from this post and maybe will be motivated to follow along or create something amazing of your own! Warm wintry hugs from me, and see you around!</p>
<p>Leaving you with beautiful Austrian Alp view &#x1f601;</p>

    <img src="/zledframe/1/alps_panorama.jpg"  alt="Alps panorama."  class="center"  style="border-radius: 8px;"  />


]]></content>
        </item>
        
        <item>
            <title>Hackaday Supercon 2023 / RISC-V Summit NA</title>
            <link>https://jduchniewicz.com/posts/2023/11/hackaday-supercon-2023-/-risc-v-summit-na/</link>
            <pubDate>Sat, 25 Nov 2023 12:11:29 +0100</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2023/11/hackaday-supercon-2023-/-risc-v-summit-na/</guid>
            <description>&lt;p&gt;Who would have thought that after the ACL injury that I suffered skiing in February I would be able to go (twice!) all the way to California to surf and attend/speak at several conferences there. As usual, my partner in crime is &lt;strong&gt;&lt;a href=&#34;https://www.linkedin.com/in/szymon-duch/&#34;&gt;Szymon&lt;/a&gt;&lt;/strong&gt; who, despite being in the final year of his master&amp;rsquo;s degree at UCL was able to keep me company. &lt;em&gt;(For anyone interested, I was at the &lt;a href=&#34;https://www.linkedin.com/posts/jduchnie_ai-opensource-future-activity-7046277876450508800-KYoX?utm_source=share&amp;amp;utm_medium=member_desktop&#34;&gt;Game Developers Conference&lt;/a&gt; in San Francisco in March)&lt;/em&gt;&lt;/p&gt;</description>
            <content type="html"><![CDATA[<p>Who would have thought that after the ACL injury that I suffered skiing in February I would be able to go (twice!) all the way to California to surf and attend/speak at several conferences there. As usual, my partner in crime is <strong><a href="https://www.linkedin.com/in/szymon-duch/">Szymon</a></strong> who, despite being in the final year of his master&rsquo;s degree at UCL was able to keep me company. <em>(For anyone interested, I was at the <a href="https://www.linkedin.com/posts/jduchnie_ai-opensource-future-activity-7046277876450508800-KYoX?utm_source=share&amp;utm_medium=member_desktop">Game Developers Conference</a> in San Francisco in March)</em></p>
<p>In this blog post you will get a glimpse of what all the conferences were about and what are latest market trends and concerns related to today&rsquo;s geopolitical and economic situation.</p>
<p>Also, I will talk a tiny bit about surfing &#x1f601;</p>

    <img src="/caliv2/encinitassunset.jpg"  alt="Sunset at Moonlight Beach"  class="center"  style="border-radius: 8px;"  />


<h2 id="monterey">Monterey</h2>
<p>The first step on our journey was Monterey, CA where we both attended the <strong><a href="https://events.linuxfoundation.org/lf-member-summit/">Linux Foundation Member Summit 2023</a></strong> which was a first for us. Summit was mostly community and business oriented where major topics such as <strong><a href="https://www.linuxfoundation.org/research/the-evolution-of-the-open-source-program-office-ospo">Open Source Project Office</a></strong> or Open Source community building and management or Open Source project lifecycles were discussed.</p>
<p>My interest was piqued by the talk about <em>Kernel Maintaining</em> by <strong>Johnatan Corbet</strong> from <strong><a href="https://lwn.net/">LWN.net</a></strong>. There, he presented the broad ecosystem that the Linux Kernel is and he pointed out some major challenges that its maintainers are currently facing. Namely there are some boxes in the dark cellar that have been mostly lying dormant and not receiving that much attention as, for example, device drivers or features that majority of users needs. These areas include documentation, build system being old <em>KConfig</em> and <em>Makefile</em> based (looking at you sweet and shiny <strong><a href="https://mesonbuild.com/">meson</a></strong>) and some core kernel areas and drivers that are in a <strong><a href="https://lwn.net/Articles/842415/">dire need of a maintainer</a></strong> (this article is slightly older, so you may refer to <strong><a href="https://www.youtube.com/watch?v=fu8ZNRDQsi8&amp;t=6771s">the actual talk</a></strong>).</p>
<p>There was a lot of discussion on open <strong>Artificial Intelligence</strong> models and how to properly and safely develop them so that they do not become evil rogues with intent of murdering all of humanity. Lastly, there was a talk about licensing and I finally understood how many flavors of <em>GPL</em> there exist(hint - 6) and about <strong>SPDX (Software Package Data Exchange)</strong> - a standard introduced to make licensing code less convolved. Check it out if you still don&rsquo;t know what <em>GPL</em> or <em>MIT</em> stand for (ok the latter was quite easy).</p>
<div class="image-container">
  
      <img src="/caliv2/usmonterey.jpg"  alt="Us at Pebble Beach"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/caliv2/szymonmonterey.jpg"  alt="Szymon at Linux Foundation Member Summit"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/caliv2/pubmonterey.jpg"  alt="Irish Pub in Monterey"  class="center"  style="border-radius: 8px;"  />
  

</div>
<h2 id="hackaday-supercon-2023">Hackaday Supercon 2023</h2>
<p>After our brief respite in Encinitas, CA, (Tony Hawk lives there &#x1f601;) where we surfed and rested a little-bit we hit the road and arrived in beautiful Pasadena, CA. Apart from being greeted by a gigantic traffic, we were also greeted by the most diverse and welcoming crowd of people <strong>I ever met in my life</strong>. I cannot speak any bad word about this conference and community because the passion for hacking and tinkering was literally seeping from these people.</p>
<p>It was also my first conference with a non-conventional badge, which instead of being a paper or plastic rectangle was a full-blown <strong><a href="https://hackaday.com/2023/10/18/2023-hackaday-supercon-badge-welcome-to-the-vectorscope/">Vectorscope</a></strong>! My amazement had no boundaries when I learned that during the 3-day conference we could hack and tinker with it and we finally presented it at the <strong><a href="https://www.youtube.com/watch?v=11Js0cOif4c">closing gala</a></strong> where we almost won in our category (losing only to Pluto which apparently regained its status of a planet &#x1f92a;</p>
<p>Even though the badge was initially slightly unstable (both the software and hardware had been made by the folks at <strong><a href="https://hackaday.com/">Hackaday</a></strong>!), people created <strong>AMAZING</strong> <strong><a href="https://hackaday.com/2023/11/15/a-look-at-all-the-badge-hacks-of-supercon-2023/">creations using it</a></strong>, think <strong>DOOM on Vectroscope</strong>, <strong><a href="https://github.com/unwiredben/vector-video">MPEG-1 video player</a></strong> and others!</p>
<p><strong><a href="https://youtu.be/11Js0cOif4c?t=2540">Our game</a></strong> was quite simple yet fun to hack around and tinker with in the corridors and workbenches of the conference. We added a parallax background (scrolling behind the main scene), some simple controls and game loop. Oh and we also managed to play some audio &#x1f604; In fact, this reminded me that I need to resurrect my GameBoy game porting and design side project!</p>
<div class="image-container">
  
      <img src="/caliv2/badges.jpg"  alt="Our Supercon Badges!"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/caliv2/jakubsoldering.jpeg"  alt="Me soldering"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/caliv2/superconszymek.jpg"  alt="Szymon at Supercon Hacking Emporeum"  class="center"  style="border-radius: 8px;"  />
  

</div>
<h2 id="risc-v-summit">RISC-V Summit</h2>
<p>Right after the closing gala we hit the road and travelled over 400 miles to Santa Clara, where the next conference would start the next morning. While writing this I just remembered that the time change occurred in the US so we lost an hour of sleeping which might explain why we were so tired after Supercon in the first place.</p>
<p>The <strong><a href="https://events.linuxfoundation.org/riscv-summit/">RISC-V Summit</a></strong> was much more business-oriented and was a stark contrast to the geeky and casual Supercon. In fact, I felt slightly underdressed without a tuxedo and in my Vans &#x1f601; Nonetheless, the conference was mostly focusing at current challenges that the chip industry is trying to solve and how RISC-V is a good answer to them. What bothers the industry the most is effective architecture for <strong>LLMs (Large Language Models, think GPT-3)</strong> or other <strong>Generative AI</strong> models like <strong>Stable Diffusion</strong>. RISC-V is a good answer to that, and <strong>Meta</strong> has used a fabric of 2 RISC-V cores comprising one processing-element (one core for processing and another for vector operations) in their <strong><a href="https://ai.meta.com/blog/meta-training-inference-accelerator-AI-MTIA/">MTIA</a></strong> accelerator.</p>
<p>Other topics included governing and growth of the <strong>RISC-V foundation</strong> that is in a stark contrast to chip architectures like <strong>Intel</strong> or <strong>ARM</strong>, where this architecture is created in an Open Source way instead of being proprietary and centrally governed. Imagine a world where it is <strong>YOU</strong> who can request a new feature to be added/improved in your everyday hardware, well, we might just as well be living it &#x1f604;</p>
<p>We also reunited with some of our friends at <strong><a href="https://www.beagleboard.org/">beagleboard.org</a></strong> who recently released <strong><a href="https://www.beagleboard.org/boards/beaglev-fire">yet another RISC-V based board - BeagleV-Fire</a></strong>!</p>
<div class="image-container">
  
      <img src="/caliv2/riscvus.jpg"  alt="Me and Szymon at RISC-V Summit"  class="center"  style="border-radius: 8px;"  />
  

  
      <img src="/caliv2/riscvboards.jpg"  class="center"  style="border-radius: 8px;"  />
  

</div>
<h2 id="surfing">Surfing</h2>
<p>Probably your inner geek has already been satiated by this point so now let&rsquo;s discuss how&rsquo;s the surfing in California. Answer? <strong>Can&rsquo;t get any better!</strong> &#x1f30a;</p>
<h3 id="socal-surfing">SoCal surfing</h3>
<p>Let&rsquo;s first clarify how big California really is. Sources do not agree, but its coast is of more-less 1200 miles long (that&rsquo;s around 2000 km) and we have 3 distinct regions: Southern California spanning from Mexican border to around Santa Maria. Then we have Central (wild) California where we now have more sharks and golfers than surfers but also breathtaking surfing vistas and waves. Lastly, we have Northern California starting at San Francisco up to Oregon. This last stretch of the Coastline is starkly different from its southern counterpart, but this time we had no pleasure surfing there.</p>
<p>The surf culture north of San Diego is pervasive, locals are more-less cultured and crowds are mostly only on weekends. <strong>My personal favorite is Encinitas</strong> but for concrete spot recommendations you would have to ask me personally &#x1f601;</p>

    <img src="/caliv2/mesurf.jpeg"  alt="Me at D Street"  class="center"  style="border-radius: 8px;"  />


<h3 id="santa-cruz">Santa Cruz</h3>
<p>Santa Cruz was a reality check for us, as we are not used to surfing in crowds and in such densely populated areas. Although the city itself is beautiful and the vistas are marvelous, you simply cannot surf near the weekends and after regular working hours. That&rsquo;s a shame because the legendary spot <strong>Steamer Lane</strong> provides great waves <strong>DAILY!</strong>. Here is a picture of it at its regular potential &#x1f606;</p>

    <img src="/caliv2/steamer.jpg"  alt="Steamer Lane"  class="center"  style="border-radius: 8px;"  />


<p>Overall, Santa Cruz is a great place to live, albeit quite expensive one. Locals are friendly and the surfing vibe is magnetic (<strong>wishing I did my studies at <a href="https://www.ucsc.edu/">UCSC</a></strong>).</p>
<h2 id="summary">Summary</h2>
<p>This is definitely not the last time we visited California, we still have some unfinished businesses both in the literal meaning of it and with the surfing spots!</p>
<p>Stay tuned for some goodies from <strong><a href="https://stickypistonstudios.com">Sticky Piston Studios</a></strong> and if you still have not followed us on <a href="https://www.linkedin.com/company/100697668/">LinkedIn</a>, then please do!</p>
]]></content>
        </item>
        
        <item>
            <title>Embedded Open Source Summit 2023</title>
            <link>https://jduchniewicz.com/posts/2023/07/embedded-open-source-summit-2023/</link>
            <pubDate>Thu, 13 Jul 2023 18:53:24 +0200</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2023/07/embedded-open-source-summit-2023/</guid>
            <description>&lt;h2 id=&#34;tldr&#34;&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;/h2&gt;
&lt;h2 id=&#34;link-to-our-talk&#34;&gt;&lt;strong&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=fBMeNOOghD4&amp;amp;feature=youtu.be&#34;&gt;Link to our talk&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;h2 id=&#34;link-to-szymon&#34;&gt;&lt;strong&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=nbDXio1qOUU&#34;&gt;Link to Szymon&amp;rsquo;s talk on Green Software for Embedded Devices&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;By the end of June, me and &lt;a href=&#34;https://github.com/Willmish&#34;&gt;Szymon&lt;/a&gt; travelled to &lt;strong&gt;Prague, Czech Republic&lt;/strong&gt; for the &lt;strong&gt;&lt;a href=&#34;https://sched.co/1LcM4&#34;&gt;Embedded Open Source Summit 2023&lt;/a&gt;&lt;/strong&gt; where we participated in the conference both as speakers and attendees. We also attended &lt;strong&gt;&lt;a href=&#34;https://events.linuxfoundation.org/xen-project-summit/&#34;&gt;Xen Developer Summit&lt;/a&gt;&lt;/strong&gt; and the &lt;strong&gt;&lt;a href=&#34;https://www.yoctoproject.org/&#34;&gt;Yocto Project Dev Day&lt;/a&gt;&lt;/strong&gt;!&lt;/p&gt;
&lt;h2 id=&#34;our-talk&#34;&gt;Our talk&lt;/h2&gt;
&lt;p&gt;Our talk titled &lt;strong&gt;&amp;ldquo;Porting an AI Powered Wearable Health Monitor to Zephyr on Open Hardware&lt;/strong&gt; boasted almost &lt;strong&gt;full room&lt;/strong&gt; by which we were very flattered. Warm thanks to everyone who engaged with us after the talk and hope you took away something useful from this presentation.&lt;/p&gt;</description>
            <content type="html"><![CDATA[<h2 id="tldr"><strong>TL;DR:</strong></h2>
<h2 id="link-to-our-talk"><strong><a href="https://www.youtube.com/watch?v=fBMeNOOghD4&amp;feature=youtu.be">Link to our talk</a></strong></h2>
<h2 id="link-to-szymon"><strong><a href="https://www.youtube.com/watch?v=nbDXio1qOUU">Link to Szymon&rsquo;s talk on Green Software for Embedded Devices</a></strong></h2>
<p>By the end of June, me and <a href="https://github.com/Willmish">Szymon</a> travelled to <strong>Prague, Czech Republic</strong> for the <strong><a href="https://sched.co/1LcM4">Embedded Open Source Summit 2023</a></strong> where we participated in the conference both as speakers and attendees. We also attended <strong><a href="https://events.linuxfoundation.org/xen-project-summit/">Xen Developer Summit</a></strong> and the <strong><a href="https://www.yoctoproject.org/">Yocto Project Dev Day</a></strong>!</p>
<h2 id="our-talk">Our talk</h2>
<p>Our talk titled <strong>&ldquo;Porting an AI Powered Wearable Health Monitor to Zephyr on Open Hardware</strong> boasted almost <strong>full room</strong> by which we were very flattered. Warm thanks to everyone who engaged with us after the talk and hope you took away something useful from this presentation.</p>

    <img src="/eoss23/wetalking.jpg"  alt="EOSS23 Presentation"  class="center"  style="border-radius: 8px;"  />


<p>In short, we presented a <em>war-story</em> where we worked on adding support for <strong><a href="https://www.quicklogic.com/">QuickLogic</a>&rsquo;s <a href="https://www.quicklogic.com/products/soc/eos-s3-microcontroller/">EOS S3</a> SoC</strong> running the <strong><a href="https://github.com/zephyrproject-rtos/zephyr">Zephyr</a> real-time operating system</strong>, while deploying a Blood Pressure prediction model that you may already know from <strong><a href="https://jduchniewicz.com/posts/2021/05/bibop-1-intro-and-machine-learning/">this post</a></strong>. The model was deployed using <strong><a href="https://www.tensorflow.org/lite/microcontrollers">TensorFlow Lite for Microcontrollers</a></strong> which proved to be very easy and accurate.</p>
<p>Here you may see the breadboard prototype as we didn&rsquo;t have time to remake the original case <a href="https://github.com/Willmish">Szymon</a> envisioned for the previous iteration of this project.</p>

    <img src="/eoss23/breadboard_90.jpg"  alt="Project on a breadboard"  class="center"  style="border-radius: 8px;"  />


<h2 id="beagleboardorg">Beagleboard.org</h2>
<p>The highlights from this conference include <strong>finally meeting <a href="https://github.com/jadonk">Jason Kridner</a> - the founder of <a href="https://beagleboard.org/">beagleboard.org</a></strong> for whom we had the pleasure to create projects during <strong><a href="https://summerofcode.withgoogle.com/">Google Summer of Code 2021</a> where I did <a href="https://github.com/JDuchniewicz/GPGPU-with-GLES">GPGPU computing with BBB</a> and Szymon started porting <a href="https://github.com/zephyrproject-rtos/zephyr">Zephyr</a> support for <a href="https://www.seeedstudio.com/Wio-Terminal-p-4509.html">Wio Terminal</a> to act as a <a href="https://docs.beagleboard.org/latest/boards/beagleconnect/freedom/demos-and-tutorials/using-greybus.html">Greybus</a> host for <a href="https://docs.beagleboard.org/latest/boards/beagleconnect/freedom/index.html">BeagleConnect Freedom</a></strong>. We also met other folks from the <em>beagleboard.org</em> organization including <strong><a href="https://microblocks.fun/">Kathy Giori</a></strong> and <strong><a href="https://mastodon.social/@pdp7">Drew Fustini</a></strong> who conducted a panel regarding future of <em>beagleboard.org</em> foundation.</p>
<p><strong>BTW - fresh RISC-V board dropped from beagleboard.org - <a href="https://beagleboard.org/beaglev-ahead">BeagleV Ahead</a> based on Alibaba T-Head chip!</strong></p>
<h2 id="zephyr">Zephyr</h2>
<p>We also met some <strong><a href="https://github.com/zephyrproject-rtos/zephyr">Zephyr</a></strong> people who helped us a lot during development of this project - <strong><a href="https://github.com/cfriedt">Chris Friedt</a></strong> or <strong><a href="https://github.com/henrikbrixandersen">Henrik Brix Andersen</a></strong> as well as <strong><a href="https://github.com/kartben">Benjamin Cabé</a></strong>. <strong>Actually, there are already three PR&rsquo;s</strong> that were the direct result of our participation in this conference and in this project <strong><a href="https://github.com/zephyrproject-rtos/zephyr/pull/59905">1</a>,<a href="https://github.com/zephyrproject-rtos/zephyr/pull/60185">2</a>, <a href="https://github.com/zephyrproject-rtos/hal_quicklogic/pull/4">3</a></strong>. Being an <strong>Open Source contributor</strong> to such an important project is surely satisfying &#x1f60e;.</p>
<p>We plan to continue extending our support for <strong><a href="https://github.com/zephyrproject-rtos/zephyr">Zephyr</a></strong> for this board by adding support for more peripherals and trying to decouple the Zephyr subsystem implementation from the <strong><a href="https://github.com/zephyrproject-rtos/hal_quicklogic">Hardware Abstraction Layer</a></strong> from Quicklogic. Also, since I have always been eager to <strong><a href="https://www.youtube.com/watch?v=BVhWh3AsXQs&amp;list=PLy2022BX6EspFAKBCgRuEuzapuz_4aJCn">learn PCB design</a></strong> we might create a single PCB for this solution (<strong>but that&rsquo;s a stretch and the day has only 24 hours, eh?</strong>).</p>
<p>I now have a beautiful <a href="https://github.com/zephyrproject-rtos/zephyr">Zephyr</a> kite &#x1fa81; (that I wish I could surf on &#x1f601;) in my living/<em>hacking</em> room.</p>

    <img src="/eoss23/kite.jpg"  alt="Splending Zephyr Kite"  class="center"  style="border-radius: 8px;"  />


<p><em>Oh we also had the opportunity to see <a href="https://www.prusa3d.com/">Josef&rsquo;s Prusa</a> HQ in Holešovice Praha.</em></p>

    <img src="/eoss23/prusa.jpg"  alt="Prusas printing Prusas"  class="center"  style="border-radius: 8px;"  />


<h2 id="whats-next">What&rsquo;s next?</h2>
<p>Since we are only getting started, expect us on <strong>further conferences around Autumn</strong> (<strong><a href="https://hackaday.com/2023/05/10/supercon-2023-is-on-we-want-you/">Hackaday Supercon</a></strong> and <strong><a href="https://riscv.org/event/risc-v-summit-2023/">RISC-V Summit</a></strong> &#x1f609; - <em>not yet confirmed</em>), and now we will enjoy some well deserved rest and vacation &#x1f604; (Windsurfing &#x1f3c4; time for Szymon and some gym &#x1f3cb;&#xfe0f; and cycling &#x1f6b4; for me). Enjoy the Summer folks!</p>
<p>Also, stay tuned for something from <strong><a href="https://github.com/Sticky-Piston-Studios">Sticky Piston Studios</a></strong> as even though we will be mostly resting, <strong>something nice is en-route</strong> &#x1f601;</p>

    <img src="/eoss23/we.jpg"  alt="Me and Szymon"  class="center"  style="border-radius: 8px;"  />


]]></content>
        </item>
        
        <item>
            <title>Digital Dragons</title>
            <link>https://jduchniewicz.com/posts/2023/05/digital-dragons/</link>
            <pubDate>Sat, 20 May 2023 16:28:30 +0200</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2023/05/digital-dragons/</guid>
            <description>&lt;p&gt;This post starts a new trend of more lifestyle-oriented posts rather than fully-technical. &lt;br&gt;
A little bit more about my current status - &lt;strong&gt;I am recovering from ACL reconstruction that I had mid-April so that&amp;rsquo;s why you might see me with crutches in some of pictures posted below &amp;#x1f604;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;why-go-there&#34;&gt;Why go there?&lt;/h2&gt;
&lt;p&gt;We received tickets to &lt;a href=&#34;https://digitaldragons.pl/&#34;&gt;Digital Dragons&lt;/a&gt; during &lt;a href=&#34;https://hackyeah.pl/#hackathon&#34;&gt;HackYeah&lt;/a&gt; 2022 on which we also won with our game &lt;a href=&#34;https://hist0r.itch.io/the-deluge&#34;&gt;The Deluge&lt;/a&gt; that you are encouraged to try and enjoy! Below you can see us in the moment of triumph:&lt;/p&gt;</description>
            <content type="html"><![CDATA[<p>This post starts a new trend of more lifestyle-oriented posts rather than fully-technical. <br>
A little bit more about my current status - <strong>I am recovering from ACL reconstruction that I had mid-April so that&rsquo;s why you might see me with crutches in some of pictures posted below &#x1f604;</strong>.</p>
<h2 id="why-go-there">Why go there?</h2>
<p>We received tickets to <a href="https://digitaldragons.pl/">Digital Dragons</a> during <a href="https://hackyeah.pl/#hackathon">HackYeah</a> 2022 on which we also won with our game <a href="https://hist0r.itch.io/the-deluge">The Deluge</a> that you are encouraged to try and enjoy! Below you can see us in the moment of triumph:</p>

    <img src="/digitaldragons/hackyeah22win.jpg"  alt="HackYeah 2022 Winners"  class="center"  style="border-radius: 8px;"  />


<h2 id="who-are-we">Who are we?</h2>
<p>We are <strong><a href="https://github.com/Sticky-Piston-Studios">Sticky Piston Studios</a></strong> and we are a team of 3 passionate young people who have been working in the industry for a while already. <strong>Having attended more than 15 gamejams in total we feel that it is time to transition to game publishing</strong> so stay tuned for some of our new productions &#x1f601;!</p>
<p>Below you may see the holy trinity: <strong>COO, CEO and CTO in that order. <a href="https://github.com/Willmish">Szymon Duchniewicz</a> (Willmish), Me (Celeborth) and <a href="https://mattszymonski.com/">Mateusz Szymoński</a> (Hist0r)</strong></p>

    <img src="/digitaldragons/beerdd.jpg"  alt="Holy Trinity of SPS"  class="center"  style="border-radius: 8px;"  />


<h2 id="quick-update-from-digital-dragons-2023">Quick update from Digital Dragons 2023</h2>
<p>Digital dragons were filled to the brim with good laughs, <em>people on crutches</em>, talks about building a healthy company and how to best capitalize on the market during tough times. We attended different tracks and while I focused mostly on the teambuilding and mobile tracks, our CTO attended more technical talks and some post-mortems, such as House Flipper or Castle Crumble. Szymon, on the other hand, participated in talks about market development and brand construction. During the <strong>Indie Expo</strong> we met with several publishers with whom we plan our future releases and we also had pleasure to play innovative Indie games that were nominated to Indie Awards.</p>
<p>Lastly, here is a picture of us with our badges and the shiny Digital Dragons logo &#x1f601;</p>

    <img src="/digitaldragons/logodd.jpg"  alt="The holy trio and DD logo"  class="center"  style="border-radius: 8px;"  />


<p>Next stop, <strong><a href="https://sched.co/1LcM4">Embedded Open Source Summit 2023</a> in Prague</strong> with my and Szymon&rsquo;s talk on <strong>embedded health blood-pressure measuring device based on Zephyr OS and open hardware</strong>. Until next time!</p>
]]></content>
        </item>
        
        <item>
            <title>BIBoP 1 - Intro and Machine Learning</title>
            <link>https://jduchniewicz.com/posts/2021/05/bibop-1-intro-and-machine-learning/</link>
            <pubDate>Mon, 31 May 2021 11:54:10 +0100</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2021/05/bibop-1-intro-and-machine-learning/</guid>
            <description>&lt;!-- markdownlint-disable MD013 --&gt;
&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Hi! My name is Jakub Duchniewicz and welcome to Brother Industry Band of Power.&lt;/p&gt;
&lt;p&gt;In this post series we plan to describe our progress with the BIBoP project and shed some light on various issues we had to tackle along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Be sure to check the [official repository] of this project!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here is a small sneak-peek of how the device will look like once assembled:&lt;/p&gt;</description>
            <content type="html"><![CDATA[<!-- markdownlint-disable MD013 -->
<h2 id="introduction">Introduction</h2>
<p>Hi! My name is Jakub Duchniewicz and welcome to Brother Industry Band of Power.</p>
<p>In this post series we plan to describe our progress with the BIBoP project and shed some light on various issues we had to tackle along the way.</p>
<p><strong>Be sure to check the [official repository] of this project!</strong></p>
<p>Here is a small sneak-peek of how the device will look like once assembled:</p>

    <img src="/bibop/case.png"  alt="BIBoP casing render."  class="center"  style="border-radius: 8px;"  />


<h3 id="why">Why?</h3>
<p>Since I haven&rsquo;t posted in a while, a small update on the reasons behind this blog post series and why ultimately my last project ([Envidrawer]) was not documented here.</p>
<p>The reason is quite obvious: <em>I am already documenting the project on the [official contest website] and I am bringing here the best nitbits from there.</em></p>
<p>Also, this project touches on so many domains and digs into several obscure areas (<strong>SAMD21</strong> MCU programming, BP estimation from <strong>PPG</strong>, <strong>AWS Lambda</strong> over <strong>TLS/SSL</strong>&hellip;), it would be a shame not to document them!</p>
<h3 id="envidrawer">Envidrawer</h3>
<p>As for the [Envidrawer] project, I finished it in quite busy time of my life (changing countries, being sick) so I did not move it to this website. Maybe one day&hellip;</p>
<p>Nevertheless, be sure to check [some] [cool] [concepts] we came up with during development of the Envidrawer project.</p>
<h2 id="project-overview">Project overview</h2>
<p>Similarly as with Envidrawer, I teamed up with Michał and Szymon to create a solution to an important problem which the humanity is currently facing or will be facing in near future. Unfortunately, the project is during their exam time on universities and it is mostly my responsibility &#x1f604; (<em>not that I am complaining!</em>).</p>
<p>Our project is a wearable band which that will measure oxygen saturation, pulse, and body temperature of the potential patient. It will automatically connect to Wi-Fi and on reaching certain thresholds call in the emergency team for hospitalization. Being a cheap and easy to manufacture device, it could be distributed to the patients from high-risk groups which upon falling sick could make use of it. The true beauty lies in the fact that it could stay after the pandemic, once again moving healthcare closer to its recipients.</p>
<p>In other words, we want to provide people with affordable, easy-to-use smart-bands which will measure their vital signals and report any abnormalities to medical staff and to the users themselves.</p>
<p><em>In the picture below you can see the high-level overview of the project (the real photos will come in as soon as the 3D printed case is ready!).</em></p>

    <img src="/bibop/medical.png"  alt="High-level overview of the system"  class="center"  style="border-radius: 8px;"  />


<p>Every project has to be powered by [Arduino Nano 33 IoT], thus I decided to make use of some ready made Arduino libraries, such as WiFiNINA or BearSSL which are necessary for secure wireless communication. At the moment of writing this post I am waist-deep in the SAMD21 datasheet and trying to enable external interrupts in low power modes, since Arduino development framework does not provide all conceivable solutions.</p>
<p>Because of shortages in the developer team, the project may not achieve all of its goals on-time, but it definitely is worth spending some time on after the contest ends. After all, having your own smart-band is quite exciting &#x1f601;.</p>
<h2 id="i---first-steps">I - First steps</h2>
<p>Setting up the development environment is one of the first steps every developer has to undertake, so that is what I also had to do. The SAMD boards require their own Board Support Package which is best downloaded using the official Arduino IDE.</p>
<p>First of all we need to setup our build and editing environment.</p>
<p><em>Enter Makefiles.</em></p>
<p><strong>DISCLAIMER - This is fairly technical paragraph so feel free to scroll down for the Machine Learning related content</strong></p>
<h3 id="why-use-makefiles-when-we-have-arduino-ide">Why use Makefiles, when we have Arduino IDE?</h3>
<p>We have Arduino IDE, right. But apart from providing users with handy building scripts and libraries + toolchains management, it failed to meet the IDE standards in term of code editing. Since I am heavy vim user, I wanted to write my code in familiar environment and with handy shortcuts and handy tools.</p>
<p>This is just one reason behind it, the other being code extensibility, compiler choice and language version freedom. Assuming you want to have your own libraries as a part of a bigger project, Arduino IDE does not present you with an easy way to do it - with a custom Makefile you can structure your project as desired. This unfortunately is by no means out of the box solution, but I was able to polish some rough edges and possibly make it easier to fall in step for whoever reads this post.</p>
<h3 id="cloning-and-setting-up">Cloning and setting up</h3>
<p>Assuming you have read this far and are willing to create your own Makefile-based Arduino project, you need to create the folder structure or simply fork/clone this project. You have a bunch of unnecessary files to delete, such as exemplary Makefiles and mock libraries. Instead what you need to do is follow the <em>INSTALL.md</em> which guides you by hand mostly.</p>
<p>Once you have the Makefile in the project directory (<code>src/ProjectName/Makefile</code>), you have to fill it with some necessary variables which are used during the process of building the binary and during the flashing and debugging the code. Exemplary Makefile can be found below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-makefile" data-lang="makefile"><span style="display:flex;"><span><span style="color:#75715e"># For now makefile will be in this file, we will change it later
</span></span></span><span style="display:flex;"><span>PROJECT_DIR       <span style="color:#f92672">=</span> <span style="color:#66d9ef">$(</span>shell dirname <span style="color:#66d9ef">$(</span>shell dirname <span style="color:#66d9ef">$(</span>shell pwd<span style="color:#66d9ef">)))</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ARDMK_DIR         <span style="color:#f92672">=</span> <span style="color:#66d9ef">$(</span>PROJECT_DIR<span style="color:#66d9ef">)</span>/Arduino-Makefile
</span></span><span style="display:flex;"><span>ARDUINO_PACKAGE_DIR <span style="color:#f92672">=</span> <span style="color:#66d9ef">$(</span>HOME<span style="color:#66d9ef">)</span>/.arduino15/packages
</span></span><span style="display:flex;"><span>ARDUINO_DIR       <span style="color:#f92672">=</span> /usr/share/arduino
</span></span><span style="display:flex;"><span>USER_LIB_PATH     <span style="color:#f92672">:=</span>  <span style="color:#66d9ef">$(</span>realpath <span style="color:#66d9ef">$(</span>PROJECT_DIR<span style="color:#66d9ef">)</span>/lib<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>BOARD_TAG         <span style="color:#f92672">=</span> nano_33_iot
</span></span><span style="display:flex;"><span>MONITOR_PORT      <span style="color:#f92672">=</span> /dev/ttyACM*
</span></span><span style="display:flex;"><span>MONITOR_BAUDRATE  <span style="color:#f92672">=</span> <span style="color:#ae81ff">115200</span>
</span></span><span style="display:flex;"><span>AVR_TOOLS_DIR     <span style="color:#f92672">=</span> /usr
</span></span><span style="display:flex;"><span>AVRDUDE           <span style="color:#f92672">=</span> /usr/bin/avrdude
</span></span><span style="display:flex;"><span>CFLAGS_STD        <span style="color:#f92672">=</span> -std<span style="color:#f92672">=</span>gnu11
</span></span><span style="display:flex;"><span>CXXFLAGS_STD      <span style="color:#f92672">=</span> -std<span style="color:#f92672">=</span>gnu++17
</span></span><span style="display:flex;"><span>CXXFLAGS         <span style="color:#f92672">+=</span> -pedantic -Wall -Wextra
</span></span><span style="display:flex;"><span>LDFLAGS          <span style="color:#f92672">+=</span> -fdiagnostics-color
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">### OBJDIR
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">### Don&#39;t touch this!
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">### This is were you put the binaries you just compile using &#39;make&#39;
</span></span></span><span style="display:flex;"><span>CURRENT_DIR       <span style="color:#f92672">=</span> <span style="color:#66d9ef">$(</span>shell basename <span style="color:#66d9ef">$(</span>CURDIR<span style="color:#66d9ef">))</span>
</span></span><span style="display:flex;"><span>OBJDIR            <span style="color:#f92672">=</span> <span style="color:#66d9ef">$(</span>PROJECT_DIR<span style="color:#66d9ef">)</span>/build/<span style="color:#66d9ef">$(</span>CURRENT_DIR<span style="color:#66d9ef">)</span>/<span style="color:#66d9ef">$(</span>BOARD_TAG<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">include</span> <span style="color:#66d9ef">$(</span>ARDMK_DIR<span style="color:#66d9ef">)</span><span style="color:#960050;background-color:#1e0010">/Sam.mk</span>
</span></span></code></pre></div><p>As you can see, not much is needed to make all of this work (most of the variables are pre-filled and just have to be tweaked by you - hopefully you won&rsquo;t need to know the Makefile content by heart like I did while repairing it ). Remember to point the <em>USER_LIB_PATH</em> to the <code>ProjectRoot/lib</code> path and to symlink/copy the libraries you plan to use to this directory.</p>
<p>The GitHub repository README mentions that you have to set the <em>BOARD_TAG</em> and <em>BOARD_SUB</em> if you have boards which have these two parameters, but for the Arduino Nano 33 IoT we just need to set the <em>BOARD_TAG</em> to <strong><em>nano_33_iot</em></strong></p>
<p>Lastly, because the original Makefiles are for the regular AVR Arduinos, you need to change the last line which includes the main Makefile from include <code>$(ARDMK_DIR)/Arduino.mk</code> to include <code>$(ARDMK_DIR)/Sam.mk</code></p>
<h3 id="polishing-the-rough-edges">Polishing the rough edges</h3>
<p>If you tried compiling right now, you would be met by some errors about missing LTO plugins during running the binary linking step. The reason for this was fixed upstream but is not ported to the Makefile you have in the project, so I suggest changing the git submodule to the upstream. You can do it with following commands:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git submodule deinit Arduino-Makefile
</span></span><span style="display:flex;"><span>git rm Arduino-Makefile
</span></span><span style="display:flex;"><span><span style="color:#75715e"># now add the gitmodule</span>
</span></span><span style="display:flex;"><span>git submodule add https://github.com/sudar/Arduino-Makefile Arduino-Makefile
</span></span><span style="display:flex;"><span>git submodule update --init --recursive
</span></span></code></pre></div><p>The <code>--recursive</code> flag was needed in case the submodule includes other submodules.</p>
<p>Having the upstream Makefile, we have some problems fixed. Unfortunately this does not fix the libraries you create by yourself so I just add the LTO plugin by myself by adding the following line to the Arduino.mk:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-makefile" data-lang="makefile"><span style="display:flex;"><span><span style="color:#75715e"># SPECIAL WORKAROUND FOR LIBRARIES
</span></span></span><span style="display:flex;"><span>LTO_PLUGIN_DIR <span style="color:#f92672">=</span> <span style="color:#66d9ef">$(</span>HOME<span style="color:#66d9ef">)</span>/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/lib/gcc/arm-none-eabi/7.2.1/liblto_plugin.so
</span></span></code></pre></div><p>Now we should be able to add our files to the lib directory and compile successfully.</p>
<h3 id="building-and-flashing">Building and flashing</h3>
<p>In order to compile the program you simply run <code>make</code> in the <code>ProjectName/src/AnotherName</code> directory and wait for the magic to happen. If everything went fine it should have built the binary and left the build artifacts in the build folder (check which one this is!).</p>
<p>In order to flash the binary on the target just run <code>make upload</code> and be sure to put the proper port in the <strong>MONITOR_PORT</strong> variable. It is quite picky about the port being used so be sure to close all other serial connections on this port even if they are already dead.</p>
<p>You can also monitor and debug the code using a serial connection and GDB. You know the magic spells by now!</p>
<ul>
<li>
<p>The <code>monitor</code> command will simply output your Serial messages (or other printing method you have set on the target) using the screen program so be sure to install it!</p>
</li>
<li>
<p>The <code>debug</code> command will run <strong>GDB</strong> (if you don&rsquo;t know how it works, be sure to learn some basics and refer to this [cheatsheet]).</p>
</li>
</ul>
<p>The Arduino Nano 33 IoT exposes <strong>SWD</strong> debug pads, but does not provide a built-in debugger - you need to provide it on your own ([like this one])</p>
<h2 id="ii---machine-learning">II - Machine Learning</h2>
<p>The second section focuses on going step-by-step over a <strong>[Jupyter notebook]</strong> where a <strong>ML</strong> model for <strong>Blood Pressure</strong> (both systolic and diastolic) estimation is created and trained. First, the data is obtained and cleaned, followed by features extraction and evaluation, to finally end with model construction, training and testing.</p>
<p>The resultant models are serialized and saved for deployment.</p>
<p><em>If you want more in depth information - the [original post] covers that.</em></p>
<h3 id="data-obtaining-and-cleaning">Data obtaining and cleaning</h3>
<p>The data which will be the basis of the model was obtained from a publicly available data from [UCI Machine Learning Repository] which contained <strong>PPG</strong>, <strong>ECG</strong> and invasive BP measurements. The ground truth for our estimation were extracted <strong>SBP</strong> and <strong>DBP</strong> (systolic and diastolic BP), that were extracted from the <strong>ABP</strong> (Arterial Blood Pressure). The sampling frequency used was 125 Hz and this is the frequency with which we will be collecting our data by the BIBoP. The signals were of course not ideal and they had to be cleaned beforehand (this was done by the creators of the dataset).</p>
<p>After downloading the dataset, extracting it and loading to memory, the process of cleaning and data reshaping can commence!</p>
<p>This is visible in this chunk of code:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># download and load the data</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>chunk_size <span style="color:#f92672">=</span> <span style="color:#ae81ff">4096</span>
</span></span><span style="display:flex;"><span>url <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;https://archive.ics.uci.edu/ml/machine-learning-databases/00340/data.zip&#34;</span>
</span></span><span style="display:flex;"><span>req <span style="color:#f92672">=</span> requests<span style="color:#f92672">.</span>get(url, stream <span style="color:#f92672">=</span> <span style="color:#66d9ef">True</span>)
</span></span><span style="display:flex;"><span>total_size <span style="color:#f92672">=</span> int(req<span style="color:#f92672">.</span>headers[<span style="color:#e6db74">&#39;content-length&#39;</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Faster downloads in chunks</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">with</span> open(<span style="color:#e6db74">&#34;data.zip&#34;</span>, <span style="color:#e6db74">&#34;wb&#34;</span>) <span style="color:#66d9ef">as</span> file:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> data <span style="color:#f92672">in</span> tqdm(iterable<span style="color:#f92672">=</span>req<span style="color:#f92672">.</span>iter_content(chunk_size<span style="color:#f92672">=</span>chunk_size), total <span style="color:#f92672">=</span> total_size<span style="color:#f92672">/</span>chunk_size, unit<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;KB&#39;</span>):
</span></span><span style="display:flex;"><span>        file<span style="color:#f92672">.</span>write(data)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># extract the data</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">not</span> os<span style="color:#f92672">.</span>path<span style="color:#f92672">.</span>exists(DATA_FOLDER):
</span></span><span style="display:flex;"><span>    os<span style="color:#f92672">.</span>mkdir(DATA_FOLDER)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> zipfile
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">with</span> zipfile<span style="color:#f92672">.</span>ZipFile(<span style="color:#e6db74">&#34;data.zip&#34;</span>, <span style="color:#e6db74">&#34;r&#34;</span>) <span style="color:#66d9ef">as</span> ref:
</span></span><span style="display:flex;"><span>    ref<span style="color:#f92672">.</span>extractall(DATA_FOLDER)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>test_samples <span style="color:#f92672">=</span> mat73<span style="color:#f92672">.</span>loadmat(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>DATA_FOLDER<span style="color:#e6db74">}</span><span style="color:#e6db74">/Part_1.mat&#34;</span>)[<span style="color:#e6db74">&#39;Part_1&#39;</span>]
</span></span></code></pre></div><p>We want to divide the data into 125 samples segments (or longer depending on the segment length - more on that later!):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># the sampling speed - 125 Hz</span>
</span></span><span style="display:flex;"><span>FS <span style="color:#f92672">=</span> <span style="color:#ae81ff">125</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># SAMPLE_SIZE = 125 # the frequency in Hz (1 second samples)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># segments of 10 seconds</span>
</span></span><span style="display:flex;"><span>SAMPLE_SIZE <span style="color:#f92672">=</span> <span style="color:#ae81ff">125</span> <span style="color:#75715e"># or longer!</span>
</span></span><span style="display:flex;"><span>NUM_PERIODS <span style="color:#f92672">=</span> SAMPLE_SIZE <span style="color:#f92672">//</span> FS
</span></span><span style="display:flex;"><span><span style="color:#75715e"># partition the data into equal length pgg segments</span>
</span></span><span style="display:flex;"><span>ppg <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(len(test_samples)):
</span></span><span style="display:flex;"><span>    l <span style="color:#f92672">=</span> test_samples[i][<span style="color:#ae81ff">0</span>]<span style="color:#f92672">.</span>size
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> j <span style="color:#f92672">in</span> range(l <span style="color:#f92672">//</span> SAMPLE_SIZE):
</span></span><span style="display:flex;"><span>        ppg<span style="color:#f92672">.</span>append(test_samples[i][<span style="color:#ae81ff">0</span>][j <span style="color:#f92672">*</span> SAMPLE_SIZE : (j <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>) <span style="color:#f92672">*</span> SAMPLE_SIZE])
</span></span></code></pre></div><p><strong>Since machine learning (regression) in a BIG approximation is &ldquo;Given x calculate y, for y = f(x)&rdquo;, we are preparing our x&rsquo;s (independent variables) - our y&rsquo;s (dependent variables) will be predicted and tested against ground truth -&gt; blood pressure already in the dataset.</strong></p>
<p><em>(regression is in smart words prediction)</em></p>
<p>We now have to extract both systolic and diastolic blood pressure, and we do it by obtaining minimums and maximums of consecutive periods:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>sbp <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>dbp <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>bp <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(len(test_samples)):
</span></span><span style="display:flex;"><span>    l <span style="color:#f92672">=</span> test_samples[i][<span style="color:#ae81ff">1</span>]<span style="color:#f92672">.</span>size
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> j <span style="color:#f92672">in</span> range(l <span style="color:#f92672">//</span> SAMPLE_SIZE):
</span></span><span style="display:flex;"><span>        temp_bp <span style="color:#f92672">=</span> test_samples[i][<span style="color:#ae81ff">1</span>][j <span style="color:#f92672">*</span> SAMPLE_SIZE : (j <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>) <span style="color:#f92672">*</span> SAMPLE_SIZE]
</span></span><span style="display:flex;"><span>        tmp_sbp <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>        tmp_dbp <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> k <span style="color:#f92672">in</span> range(NUM_PERIODS):
</span></span><span style="display:flex;"><span>          tmp_bp_small <span style="color:#f92672">=</span> temp_bp[k <span style="color:#f92672">*</span> FS : (k <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>) <span style="color:#f92672">*</span> FS]
</span></span><span style="display:flex;"><span>          tmp_sbp<span style="color:#f92672">.</span>append(np<span style="color:#f92672">.</span>max(tmp_bp_small))
</span></span><span style="display:flex;"><span>          tmp_dbp<span style="color:#f92672">.</span>append(np<span style="color:#f92672">.</span>min(tmp_bp_small))
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># SBP will be maximum and DBP will be minimum of 1 such sampling period (or averaged if more periods)</span>
</span></span><span style="display:flex;"><span>        bp<span style="color:#f92672">.</span>append(temp_bp)
</span></span><span style="display:flex;"><span>        sbp<span style="color:#f92672">.</span>append(np<span style="color:#f92672">.</span>mean(tmp_sbp))
</span></span><span style="display:flex;"><span>        dbp<span style="color:#f92672">.</span>append(np<span style="color:#f92672">.</span>mean(tmp_dbp))
</span></span></code></pre></div><p>A comparison of the <strong>ABP</strong> and <strong>PPG</strong> signal is visible below:

    <img src="/bibop/bp_sbp.png"  alt="SBP and ABP comparison."  class="center"  style="border-radius: 8px;"  />

</p>
<p>Inspecting the <strong>SBP</strong> and <strong>DBP</strong> shows they are good enough:

    <img src="/bibop/bp_sbp_2.png"  alt="SBP and DBP comparison."  class="center"  style="border-radius: 8px;"  />

</p>
<p>The <strong>PPG</strong> signal is surely non-ideal and that is why we will need to perform some further cleaning:

    <img src="/bibop/ppg_signal.png"  alt="PPG signal inspection."  class="center"  style="border-radius: 8px;"  />

</p>
<p><strong>For now we can create a baseline model and see how it fares. We did not extract any features yet so we do the prediction based only on the <strong>PPG</strong> signal:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># since we want to predict both SBP and DBP we will pack them for each sample</span>
</span></span><span style="display:flex;"><span>target_bp <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(len(ppg)):
</span></span><span style="display:flex;"><span>    target_bp<span style="color:#f92672">.</span>append((sbp[i], dbp[i]))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>x_train, x_test, y_train, y_test <span style="color:#f92672">=</span> train_test_split(ppg, target_bp, test_size<span style="color:#f92672">=</span><span style="color:#ae81ff">0.3</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>model <span style="color:#f92672">=</span> LinearRegression()
</span></span><span style="display:flex;"><span>model<span style="color:#f92672">.</span>fit(x_train, y_train)
</span></span><span style="display:flex;"><span>y_pred <span style="color:#f92672">=</span> model<span style="color:#f92672">.</span>predict(x_test)
</span></span><span style="display:flex;"><span>mean_absolute_error(y_test, y_pred)
</span></span></code></pre></div><p>The achieved <strong>Mean Absolute Error</strong> was 13.8 which gives us some room for improvement. We need to extract features from the signal which may help us identify potential important characteristics for models.</p>
<h3 id="temporal-and-spectral-features-extraction">Temporal and Spectral features extraction</h3>
<h4 id="temporal">Temporal</h4>
<p>Since classic Machine Learning usually benefits from hand-picking some features from the input data, some features are extracted from the signal periods and assessed for validity. Features were chosen based on most popular ones in the recent scientific papers.</p>
<p>These include:</p>
<ul>
<li>Cycle duration time</li>
<li>Time from cycle start to systolic peak</li>
<li>Time from systolic peak to cycle end</li>
<li>Time from systolic peak to dicrotic notch</li>
<li>Time from dicrotic notch to end</li>
<li>Ratio between systolic and diastolic amplitude</li>
</ul>
<p>These features are explained in more detail in the graph underneath:</p>

    <img src="/bibop/systolediastole.png"  alt="Temporal features description."  class="center"  style="border-radius: 8px;"  />


<p>The code for extraction of both features is available in the [Jupyter notebook].</p>
<h4 id="spectral">Spectral</h4>
<p>Additionally, we can extract spectral features, which could help the models:</p>
<ul>
<li>Three largest magnitudes (both values and frequencies)</li>
<li>Normalized energy</li>
<li>Entropy</li>
<li>Histogram - Binned distribution from 0 to 60 Hz (10 bins)</li>
<li>Skewness</li>
<li>Kurtosis</li>
</ul>
<p><strong>These features require some periodicity (remember our old friend Joseph Fourier?), so they have to be taken from ~10 periods of <strong>PPG</strong>.</strong></p>
<h3 id="exploratory-data-analysis">Exploratory Data Analysis</h3>
<p>After we obtained the features, we assemble the dataframes and clean them slightly.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>rows <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(len(ppg)):
</span></span><span style="display:flex;"><span>    cycle_len, t_start_sys, t_sys_end, t_sys_dicr, t_dicr_end, ratio <span style="color:#f92672">=</span> extract_features_long_seg(ppg[i], ppg_ii[i])
</span></span><span style="display:flex;"><span>    freq_1, mag_1, freq_2, mag_2, freq_3, mag_3, energy, entro, bins, skewness, kurt <span style="color:#f92672">=</span> extract_spectral_features(ppg[i])
</span></span><span style="display:flex;"><span>    rows<span style="color:#f92672">.</span>append((cycle_len, t_start_sys, t_sys_end, t_sys_dicr, t_dicr_end, ratio,
</span></span><span style="display:flex;"><span>                freq_1, mag_1, freq_2, mag_2, freq_3, mag_3, energy, entro, skewness, kurt, <span style="color:#f92672">*</span>bins))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>rows <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>array(rows)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># make a df from the data to clean it</span>
</span></span><span style="display:flex;"><span>bins <span style="color:#f92672">=</span> [<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;bin_</span><span style="color:#e6db74">{</span>i<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> <span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">10</span>)]
</span></span><span style="display:flex;"><span>col <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#34;cycle_len&#34;</span>, <span style="color:#e6db74">&#34;t_start_sys&#34;</span>, <span style="color:#e6db74">&#34;t_sys_end&#34;</span>, <span style="color:#e6db74">&#34;t_sys_dicr&#34;</span>, <span style="color:#e6db74">&#34;t_dicr_end&#34;</span>, <span style="color:#e6db74">&#34;ratio&#34;</span>,
</span></span><span style="display:flex;"><span>       <span style="color:#e6db74">&#34;freq_1&#34;</span>, <span style="color:#e6db74">&#34;mag_1&#34;</span>, <span style="color:#e6db74">&#34;freq_2&#34;</span>, <span style="color:#e6db74">&#34;mag_2&#34;</span>, <span style="color:#e6db74">&#34;freq_3&#34;</span>, <span style="color:#e6db74">&#34;mag_3&#34;</span>, <span style="color:#e6db74">&#34;energy&#34;</span>, <span style="color:#e6db74">&#34;entropy&#34;</span>, <span style="color:#e6db74">&#34;skewness&#34;</span>, <span style="color:#e6db74">&#34;kurtosis&#34;</span>, <span style="color:#f92672">*</span>bins]
</span></span><span style="display:flex;"><span>df <span style="color:#f92672">=</span> pd<span style="color:#f92672">.</span>DataFrame(rows, columns<span style="color:#f92672">=</span>col)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># drop rows with wrong values</span>
</span></span><span style="display:flex;"><span>idxs <span style="color:#f92672">=</span> df<span style="color:#f92672">.</span>loc[df[<span style="color:#e6db74">&#39;t_sys_end&#39;</span>] <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0.</span>]<span style="color:#f92672">.</span>index
</span></span><span style="display:flex;"><span>inf_idxs <span style="color:#f92672">=</span> df<span style="color:#f92672">.</span>loc[df<span style="color:#f92672">.</span>values <span style="color:#f92672">&gt;=</span> np<span style="color:#f92672">.</span>finfo(np<span style="color:#f92672">.</span>float64)<span style="color:#f92672">.</span>max]<span style="color:#f92672">.</span>index
</span></span><span style="display:flex;"><span>indices <span style="color:#f92672">=</span> idxs<span style="color:#f92672">.</span>append(inf_idxs)
</span></span><span style="display:flex;"><span>df <span style="color:#f92672">=</span> df<span style="color:#f92672">.</span>drop(indices)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># fill all NaN&#39;s</span>
</span></span><span style="display:flex;"><span>df<span style="color:#f92672">.</span>fillna(<span style="color:#ae81ff">0</span>, inplace<span style="color:#f92672">=</span><span style="color:#66d9ef">True</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># clean also the target variables</span>
</span></span><span style="display:flex;"><span>col <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#34;SBP&#34;</span> , <span style="color:#e6db74">&#34;DBP&#34;</span>]
</span></span><span style="display:flex;"><span>df_target <span style="color:#f92672">=</span> pd<span style="color:#f92672">.</span>DataFrame(target_bp, columns<span style="color:#f92672">=</span>col)
</span></span><span style="display:flex;"><span>df_target<span style="color:#f92672">=</span> df_target<span style="color:#f92672">.</span>drop(indices)
</span></span></code></pre></div><p>Let&rsquo;s take a quick look at the <code>df.describe()</code> which will tell us how the dataframe fares:</p>

    <img src="/bibop/df_describe.png"  alt="Dataframe information."  class="center"  style="border-radius: 8px;"  />


<p>Briefly exploring the data, it can be seen there are some outliers which should be eliminated in order to make the models&rsquo; predictions better. For this we will use <strong>IQR elimination</strong> - removing all the values which lie outside of the Q1 and Q3 percentile quarters in the normal distribution of the data:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># only some columns are striking, remove only rows where outliers are present in these columns</span>
</span></span><span style="display:flex;"><span>sus <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#34;ratio&#34;</span>, <span style="color:#e6db74">&#34;mag_1&#34;</span>, <span style="color:#e6db74">&#34;mag_2&#34;</span>, <span style="color:#e6db74">&#34;mag_3&#34;</span>, <span style="color:#e6db74">&#34;energy&#34;</span>, <span style="color:#e6db74">&#34;entropy&#34;</span>, <span style="color:#e6db74">&#34;skewness&#34;</span>, <span style="color:#e6db74">&#34;kurtosis&#34;</span>]
</span></span><span style="display:flex;"><span>to_remove <span style="color:#f92672">=</span> set()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>indices <span style="color:#f92672">=</span> set()
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> x <span style="color:#f92672">in</span> sus:
</span></span><span style="display:flex;"><span>  q25, q75 <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>percentile(df<span style="color:#f92672">.</span>loc[:,x], [<span style="color:#ae81ff">25</span>, <span style="color:#ae81ff">75</span>])
</span></span><span style="display:flex;"><span>  intra <span style="color:#f92672">=</span> q75 <span style="color:#f92672">-</span> q25
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  max <span style="color:#f92672">=</span> q75 <span style="color:#f92672">+</span> intra <span style="color:#f92672">*</span> <span style="color:#ae81ff">1.5</span>
</span></span><span style="display:flex;"><span>  min <span style="color:#f92672">=</span> q25 <span style="color:#f92672">-</span> intra <span style="color:#f92672">*</span> <span style="color:#ae81ff">1.5</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  idxs_1 <span style="color:#f92672">=</span> df<span style="color:#f92672">.</span>loc[df[x] <span style="color:#f92672">&lt;</span> min, x]<span style="color:#f92672">.</span>index
</span></span><span style="display:flex;"><span>  idxs_2 <span style="color:#f92672">=</span> df<span style="color:#f92672">.</span>loc[df[x] <span style="color:#f92672">&gt;</span> max, x]<span style="color:#f92672">.</span>index
</span></span><span style="display:flex;"><span>  to_remove <span style="color:#f92672">=</span> to_remove<span style="color:#f92672">.</span>union(idxs_1)<span style="color:#f92672">.</span>union(idxs_2)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>df<span style="color:#f92672">.</span>drop(to_remove, inplace<span style="color:#f92672">=</span><span style="color:#66d9ef">True</span>)
</span></span><span style="display:flex;"><span>df_target<span style="color:#f92672">.</span>drop(to_remove, inplace<span style="color:#f92672">=</span><span style="color:#66d9ef">True</span>)
</span></span></code></pre></div><p>Now we can finally plot our data and see if there are any striking relations we should be aware of:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># correlation plots</span>
</span></span><span style="display:flex;"><span>plt<span style="color:#f92672">.</span>rcParams[<span style="color:#e6db74">&#39;figure.dpi&#39;</span>] <span style="color:#f92672">=</span> <span style="color:#ae81ff">100</span>
</span></span><span style="display:flex;"><span>plt<span style="color:#f92672">.</span>rcParams[<span style="color:#e6db74">&#34;figure.figsize&#34;</span>] <span style="color:#f92672">=</span> (<span style="color:#ae81ff">20</span>,<span style="color:#ae81ff">15</span>)
</span></span><span style="display:flex;"><span>scatter_var <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#34;cycle_len&#34;</span>, <span style="color:#e6db74">&#34;t_start_sys&#34;</span>, <span style="color:#e6db74">&#34;t_sys_end&#34;</span>, <span style="color:#e6db74">&#34;t_sys_dicr&#34;</span>, <span style="color:#e6db74">&#34;t_dicr_end&#34;</span>, <span style="color:#e6db74">&#34;ratio&#34;</span>,
</span></span><span style="display:flex;"><span>               <span style="color:#e6db74">&#34;freq_1&#34;</span>, <span style="color:#e6db74">&#34;mag_1&#34;</span>, <span style="color:#e6db74">&#34;freq_2&#34;</span>, <span style="color:#e6db74">&#34;mag_2&#34;</span>, <span style="color:#e6db74">&#34;freq_3&#34;</span>, <span style="color:#e6db74">&#34;mag_3&#34;</span>, <span style="color:#e6db74">&#34;energy&#34;</span>, <span style="color:#e6db74">&#34;entropy&#34;</span>, <span style="color:#e6db74">&#34;skewness&#34;</span>, <span style="color:#e6db74">&#34;kurtosis&#34;</span>]
</span></span><span style="display:flex;"><span>correlation_matrix <span style="color:#f92672">=</span> df[scatter_var]<span style="color:#f92672">.</span>corr()
</span></span><span style="display:flex;"><span>sns<span style="color:#f92672">.</span>heatmap(correlation_matrix, annot<span style="color:#f92672">=</span><span style="color:#66d9ef">True</span>)
</span></span></code></pre></div>
    <img src="/bibop/correlation.png"  alt="Correlation plots of the features."  class="center"  style="border-radius: 8px;"  />


<p>It can be seen that time features are quite correlated, which is expected. Also the energy is somewhat correlated with the time features. There are strong anticorrelations in frequency domain features - frequency/magnitude associations.</p>
<p>Apart from confirmation, this plot did not give as much insight as it can in other cases, so let&rsquo;s move on!</p>
<h3 id="machine-learning-and-results">Machine Learning and Results</h3>
<p>Having the data prepared, we can now proceed with the training of various models to assess which one is the best. The most promising models in the literature are a <strong>Random Forest</strong> and <strong>Linear Regression</strong> so we are using them here as well. I won&rsquo;t describe these two models here, because there is plenty of good sources on [RF] and [LR].</p>
<p>The data is further split using <strong>[K-Fold cross-validation]</strong>, in order to train the model for a given number of epochs. Then it is finally used to predict on the intact test set.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>folds <span style="color:#f92672">=</span> KFold(n_splits<span style="color:#f92672">=</span><span style="color:#ae81ff">10</span>, shuffle<span style="color:#f92672">=</span><span style="color:#66d9ef">False</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e"># resplit the data after processing</span>
</span></span><span style="display:flex;"><span>x_train, x_test, y_train, y_test <span style="color:#f92672">=</span> train_test_split(df, df_target, test_size<span style="color:#f92672">=</span><span style="color:#ae81ff">0.3</span>)
</span></span></code></pre></div><p>Finally, the model training can commence:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>linear <span style="color:#f92672">=</span> LinearRegression()
</span></span><span style="display:flex;"><span>errors_sbp <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>errors_dbp <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i, (train_idx, val_idx) <span style="color:#f92672">in</span> enumerate(folds<span style="color:#f92672">.</span>split(x_train, y_train)):
</span></span><span style="display:flex;"><span>    train_data, train_target <span style="color:#f92672">=</span> x_train<span style="color:#f92672">.</span>iloc[train_idx], y_train<span style="color:#f92672">.</span>iloc[train_idx]
</span></span><span style="display:flex;"><span>    val_data, val_target <span style="color:#f92672">=</span> x_train<span style="color:#f92672">.</span>iloc[val_idx], y_train<span style="color:#f92672">.</span>iloc[val_idx]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    linear<span style="color:#f92672">.</span>fit(train_data, train_target)
</span></span><span style="display:flex;"><span>    predictions <span style="color:#f92672">=</span> linear<span style="color:#f92672">.</span>predict(val_data)
</span></span><span style="display:flex;"><span>    error_sbp <span style="color:#f92672">=</span> mean_absolute_error(predictions[:,<span style="color:#ae81ff">0</span>], val_target[<span style="color:#e6db74">&#34;SBP&#34;</span>]<span style="color:#f92672">.</span>values)
</span></span><span style="display:flex;"><span>    error_dbp <span style="color:#f92672">=</span> mean_absolute_error(predictions[:,<span style="color:#ae81ff">1</span>], val_target[<span style="color:#e6db74">&#34;DBP&#34;</span>]<span style="color:#f92672">.</span>values)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;Train fold </span><span style="color:#e6db74">{</span>i<span style="color:#e6db74">}</span><span style="color:#e6db74"> MAE SBP: </span><span style="color:#e6db74">{</span>error_sbp<span style="color:#e6db74">}</span><span style="color:#e6db74"> MAE DBP: </span><span style="color:#e6db74">{</span>error_dbp<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span><span style="display:flex;"><span>    errors_sbp<span style="color:#f92672">.</span>append(error_sbp)
</span></span><span style="display:flex;"><span>    errors_dbp<span style="color:#f92672">.</span>append(error_dbp)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;Average MAE SBP: </span><span style="color:#e6db74">{</span>np<span style="color:#f92672">.</span>mean(errors_sbp)<span style="color:#e6db74">}</span><span style="color:#e6db74"> MAE DBP: </span><span style="color:#e6db74">{</span>np<span style="color:#f92672">.</span>mean(errors_dbp)<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span></code></pre></div><p>The results are visible in the picture below:</p>

    <img src="/bibop/results.png"  alt="Training results."  class="center"  style="border-radius: 8px;"  />


<p>It is visible that the rightmost model is the most accurate - Random Forest with 10s segment lengths and 100 estimators. The results are far from ideal but they are not much worse than recent <strong>State of The Art</strong> (we have still much to improve in this area).</p>
<p>The most important problem we are now facing is making the data captured from the <strong>PPG</strong> with the Arduino fit our model (be normalized and rescaled). Also the <strong>PPG</strong> reading often wanders and has varying amplitude between readings, so we will have to rescale the data dynamically (averaging a period of 10 seconds or more).</p>
<h2 id="summary">Summary</h2>
<p>This was the first of posts describing my endeavours with BIBoP, with several more to come. The next one will be focusing on AWS and setting up a Lambda which will make use of our model. I hope this post was informative enough and you learned something valuable.</p>
<p>As always, if you found anything unclear or want to provide feedback, reach out to me, be it below this post or personally &#x1f604;.</p>
<p>Also, if you like what I&rsquo;m doing and you would like to see more of it - consider buying me a [coffee] &#x2615;
[coffee]: <a href="https://www.buymeacoffee.com/jduchniewicz">https://www.buymeacoffee.com/jduchniewicz</a>
[Envidrawer]: <a href="https://www.element14.com/community/community/design-challenges/1-meter-of-pi/blog/2021/01/06/envidrawer-final-post">https://www.element14.com/community/community/design-challenges/1-meter-of-pi/blog/2021/01/06/envidrawer-final-post</a>
[official repository]: <a href="https://github.com/JDuchniewicz/BIBoP">https://github.com/JDuchniewicz/BIBoP</a>
[official contest website]: <a href="https://www.element14.com/community/community/design-challenges/design-for-a-cause-2021">https://www.element14.com/community/community/design-challenges/design-for-a-cause-2021</a>
[some]: <a href="https://www.element14.com/community/community/design-challenges/1-meter-of-pi/blog/2021/01/02/envidrawer-blog-7-ride-the-lightning">https://www.element14.com/community/community/design-challenges/1-meter-of-pi/blog/2021/01/02/envidrawer-blog-7-ride-the-lightning</a>
[cool]: <a href="https://www.element14.com/community/community/design-challenges/1-meter-of-pi/blog/2021/01/03/envidrawer-4-3d-modelling-printing-and-further-assembly">https://www.element14.com/community/community/design-challenges/1-meter-of-pi/blog/2021/01/03/envidrawer-4-3d-modelling-printing-and-further-assembly</a>
[concepts]: <a href="https://www.element14.com/community/community/design-challenges/1-meter-of-pi/blog/2020/11/02/envidrawer-2-materials-and-casing-assembly">https://www.element14.com/community/community/design-challenges/1-meter-of-pi/blog/2020/11/02/envidrawer-2-materials-and-casing-assembly</a>
[Arduino Nano 33 IoT]: <a href="https://store.arduino.cc/arduino-nano-33-iot">https://store.arduino.cc/arduino-nano-33-iot</a>
[cheatsheet]: <a href="https://gabriellesc.github.io/teaching/resources/GDB-cheat-sheet.pdf">https://gabriellesc.github.io/teaching/resources/GDB-cheat-sheet.pdf</a>
[like this one]: <a href="https://1bitsquared.de/products/black-magic-probe">https://1bitsquared.de/products/black-magic-probe</a>
[Jupyter notebook]: <a href="https://github.com/JDuchniewicz/BloodPressurePPG">https://github.com/JDuchniewicz/BloodPressurePPG</a>
[original post]: <a href="https://www.element14.com/community/community/design-challenges/design-for-a-cause-2021/blog/2021/05/13/bibop-3-blood-pressure-inference-machine-learning">https://www.element14.com/community/community/design-challenges/design-for-a-cause-2021/blog/2021/05/13/bibop-3-blood-pressure-inference-machine-learning</a>
[UCI Machine Learning Repository]: <a href="https://archive.ics.uci.edu/ml/datasets/Cuff-Less&#43;Blood&#43;Pressure&#43;Estimation">https://archive.ics.uci.edu/ml/datasets/Cuff-Less+Blood+Pressure+Estimation</a>
[RF]: <a href="https://towardsai.net/p/machine-learning/why-choose-random-forest-and-not-decision-trees">https://towardsai.net/p/machine-learning/why-choose-random-forest-and-not-decision-trees</a>
[LR]: <a href="https://www.cs.toronto.edu/~frossard/post/linear_regression/">https://www.cs.toronto.edu/~frossard/post/linear_regression/</a>
[K-Fold cross-validation]: <a href="https://machinelearningmastery.com/k-fold-cross-validation/">https://machinelearningmastery.com/k-fold-cross-validation/</a></p>
]]></content>
        </item>
        
        <item>
            <title>C&#43;&#43; to Rust - or how to render your mindset</title>
            <link>https://jduchniewicz.com/posts/2021/02/c-to-rust-or-how-to-render-your-mindset/</link>
            <pubDate>Sun, 28 Feb 2021 16:37:00 +0200</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2021/02/c-to-rust-or-how-to-render-your-mindset/</guid>
            <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;h4 id=&#34;original-chapter-1&#34;&gt;&lt;a href=&#34;https://raytracing.github.io/books/RayTracingInOneWeekend.html#overview&#34;&gt;Original Chapter 1&lt;/a&gt;&lt;/h4&gt;
&lt;h4 id=&#34;update&#34;&gt;Update&lt;/h4&gt;
&lt;p&gt;Thank you wholeheartedly for the support and the comments on this post. Some mistakes were fixed and some things are now better clarified. Also thanks to soruh for the &lt;a href=&#34;https://github.com/JDuchniewicz/rustracing/pull/1&#34;&gt;optimization PR&lt;/a&gt; to the repository (already merged). The relevant benchmarks are mentioned there and the code is parallelized with &lt;a href=&#34;https://docs.rs/rayon/1.5.0/rayon/&#34;&gt;rayon&lt;/a&gt;. If you are interested in the discussion take a look &lt;a href=&#34;https://www.reddit.com/r/rust/comments/lukgyi/c_to_rust_introduction_with_practical_raytracing/&#34;&gt;here&lt;/a&gt;. The main branch contains some improvements over the original code in this post, so check it out for some cool things such as Rust macros or the aforementioned parallelization.&lt;/p&gt;</description>
            <content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<h4 id="original-chapter-1"><a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html#overview">Original Chapter 1</a></h4>
<h4 id="update">Update</h4>
<p>Thank you wholeheartedly for the support and the comments on this post. Some mistakes were fixed and some things are now better clarified. Also thanks to soruh for the <a href="https://github.com/JDuchniewicz/rustracing/pull/1">optimization PR</a> to the repository (already merged). The relevant benchmarks are mentioned there and the code is parallelized with <a href="https://docs.rs/rayon/1.5.0/rayon/">rayon</a>. If you are interested in the discussion take a look <a href="https://www.reddit.com/r/rust/comments/lukgyi/c_to_rust_introduction_with_practical_raytracing/">here</a>. The main branch contains some improvements over the original code in this post, so check it out for some cool things such as Rust macros or the aforementioned parallelization.</p>
<p>Every programmer wants to feel loved (yes I am looking at you!), be it by others or yourself. Usually you <em>really</em> love yourself when you accomplish something you are proud of. That is why from time to time programmers tend to learn languages (be it programming or spoken ones - unless you can talk to your fridge in assembly of course) or challenge themselves and write tough and unintelligible pieces of code which do something amazing. If you are like me and were always amazed by how the computer can render something resembling real life instead of just 2D graphics, you came to the right place!</p>
<p>Cutting the slack, I will reimplement the amazing tutorial on <a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html"><em>Ray Tracing in One Weekend</em></a> in the Rust programming language. This post is aimed at people who are interested in the subject of rendering and want to try Rust, or are simply curious about how things are done in this language. I will not go through all content, but only focus on parts which are starkly different from the original implementation. The code for this project is available on this GitHub <a href="https://github.com/JDuchniewicz/rustracing/tree/f290e44caaacb249c0fd6bd49a26ace4d8709370">repo</a>.</p>
<p>We aim to obtain such a render at the end of this tutorial.

    <img src="/raytracing/image.png"  alt="Rendered image."  class="center"  style="border-radius: 8px;"  />

</p>
<p>Although you can just read through the whole thing and see how things are done differently in Rust compared to C++ or C, I recommend reading through the original tutorial and implementing the code yourself! Nevertheless, be prepared to learn a great deal about why and how Rust does some things the other way (the modern one?). Of course, do read <a href="https://doc.rust-lang.org/stable/book/">The Rust Programming Language</a>, in which you can find a comprehensive intro to Rust, or if you prefer less reading and more code look no further than <a href="https://doc.rust-lang.org/stable/rust-by-example/">Rust by example</a>.</p>
 <div align="center"><strong>DISCLAIMER</strong></div>
<p>This is yet another blog post in the style of <a href="https://transitiontech.ca/random/RIIR">RIIR</a> but with educational aims (don&rsquo;t hang me for it, please). The target audience should have some knowledge of programming (especially in C or C++). Assuming you are the target audience, Rust knowledge is not required but as stated before, do read up the official tutorials - this one is for those who want to have a sense of accomplishment and a pretty solid infant renderer.</p>
<p>Views expressed here are my own only&hellip;  <em>you know the rest</em>.</p>
<p>I <em>promise</em>, this is the last paragraph that keeps you from writing actual code. I will link relevant paragraphs from the original tutorial so you can see where the code differs so much it was worth me rambling on it.</p>
<h2 id="outputting-an-image">Outputting an image</h2>
<h4 id="original-chapter-2"><a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html#outputanimage">Original Chapter 2</a></h4>
<p>Time to get our hands dirty and code something! Rendering something is most fun if we can actually see the result, so we need to create a function which will save our rendered image into a <a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html#outputanimage/theppmimageformat"> PPM </a> image format (probably due to its simplicity).</p>
<p>Each time there is code to compare, I will paste both the C++ code and its Rust counterpart so you can spot the differences. I will only attach some of the images from the original post and instead provide direct links to them.</p>
<p><strong>The C++ code:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;iostream&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Image
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> <span style="color:#66d9ef">int</span> image_width <span style="color:#f92672">=</span> <span style="color:#ae81ff">256</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> <span style="color:#66d9ef">int</span> image_height <span style="color:#f92672">=</span> <span style="color:#ae81ff">256</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Render
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    std<span style="color:#f92672">::</span>cout <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;P3</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">&lt;&lt;</span> image_width <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#39; &#39;</span> <span style="color:#f92672">&lt;&lt;</span> image_height <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">255</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">int</span> j <span style="color:#f92672">=</span> image_height<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>; j <span style="color:#f92672">&gt;=</span> <span style="color:#ae81ff">0</span>; <span style="color:#f92672">--</span>j) {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">int</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; i <span style="color:#f92672">&lt;</span> image_width; <span style="color:#f92672">++</span>i) {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">auto</span> r <span style="color:#f92672">=</span> <span style="color:#66d9ef">double</span>(i) <span style="color:#f92672">/</span> (image_width<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">auto</span> g <span style="color:#f92672">=</span> <span style="color:#66d9ef">double</span>(j) <span style="color:#f92672">/</span> (image_height<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">auto</span> b <span style="color:#f92672">=</span> <span style="color:#ae81ff">0.25</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">int</span> ir <span style="color:#f92672">=</span> <span style="color:#66d9ef">static_cast</span><span style="color:#f92672">&lt;</span><span style="color:#66d9ef">int</span><span style="color:#f92672">&gt;</span>(<span style="color:#ae81ff">255.999</span> <span style="color:#f92672">*</span> r);
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">int</span> ig <span style="color:#f92672">=</span> <span style="color:#66d9ef">static_cast</span><span style="color:#f92672">&lt;</span><span style="color:#66d9ef">int</span><span style="color:#f92672">&gt;</span>(<span style="color:#ae81ff">255.999</span> <span style="color:#f92672">*</span> g);
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">int</span> ib <span style="color:#f92672">=</span> <span style="color:#66d9ef">static_cast</span><span style="color:#f92672">&lt;</span><span style="color:#66d9ef">int</span><span style="color:#f92672">&gt;</span>(<span style="color:#ae81ff">255.999</span> <span style="color:#f92672">*</span> b);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            std<span style="color:#f92672">::</span>cout <span style="color:#f92672">&lt;&lt;</span> ir <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#39; &#39;</span> <span style="color:#f92672">&lt;&lt;</span> ig <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#39; &#39;</span> <span style="color:#f92672">&lt;&lt;</span> ib <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#39;\n&#39;</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>Rust:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">let</span> image_width <span style="color:#f92672">=</span> <span style="color:#ae81ff">256</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">let</span> image_height <span style="color:#f92672">=</span> <span style="color:#ae81ff">256</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">println!</span>(<span style="color:#e6db74">&#34;P3</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">255&#34;</span>, image_height, image_width);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> j <span style="color:#66d9ef">in</span> (<span style="color:#ae81ff">0</span><span style="color:#f92672">..</span>image_height).rev() {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> i <span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0</span><span style="color:#f92672">..</span>image_width {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">let</span> r <span style="color:#f92672">=</span> i <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">f64</span> <span style="color:#f92672">/</span> (image_width <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">f64</span>;
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">let</span> g <span style="color:#f92672">=</span> j <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">f64</span> <span style="color:#f92672">/</span> (image_height <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">f64</span>;
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">let</span> b <span style="color:#f92672">=</span> <span style="color:#ae81ff">0.25</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">let</span> ir <span style="color:#f92672">=</span> (<span style="color:#ae81ff">255.999</span> <span style="color:#f92672">*</span> r) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>;
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">let</span> ig <span style="color:#f92672">=</span> (<span style="color:#ae81ff">255.999</span> <span style="color:#f92672">*</span> g) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>;
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">let</span> ib <span style="color:#f92672">=</span> (<span style="color:#ae81ff">255.999</span> <span style="color:#f92672">*</span> b) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">println!</span>(<span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{}</span><span style="color:#e6db74">&#34;</span>, ir, ig, ib);
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This should result in an image looking like <a href="https://raytracing.github.io/images/img-1.01-first-ppm-image.png">this</a> - you can view these images with most viewers as this is quite common image format for ASCII encoded images.</p>
<p>The first stark difference is the <code>for</code> loop - Rust uses syntax similar to Python and supports looping though iterable objects thanks to the <code>Iterator</code> trait (we will get to traits soon enough, for now it is a kind of interface). Looping forwards is easy, as you just specify the range of iteration like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">10</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">println!</span>(<span style="color:#e6db74">&#34;looping: </span><span style="color:#e6db74">{}</span><span style="color:#e6db74">&#34;</span>, i);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>You can also loop in steps similar to the C++ <code>i += 2</code> by using this syntax: <code>for i in (1..10).step_by(2)</code>, but how do you loop backward? I probably spoiled the fun as the answer is visible above, a range already implements the <code>Iterator</code> trait, and for other types you create an iterator from them by yet another trait called <code>Into</code> which is a reciprocal of <code>From</code> - in short it allows the programmer to specify legal conversions between types in Rust. So, we take a range of values, call the <code>rev()</code> function on it (provided by the <code>Iterator</code> trait) and <em>voila</em>, we got our reverse loop: <code>for i in (1..10).rev()</code>.</p>
<p>Barring from some syntax differences, the program is quite similar to the original version, we use <code>as</code> instead of C-style (<em>unsafe</em>) casts and <code>static_cast&lt;T&gt;</code>s. This cast will of course detect any mismatch at compile time.</p>
<h3 id="building-the-code">Building the code</h3>
<p>You will of course need a way to build the code and run it, and this is a good opportunity to introduce you to the first key selling point of Rust: <a href="https://doc.rust-lang.org/book/ch01-03-hello-cargo.html">Cargo</a>. This is both a build system and a package manage (think like Python&rsquo;s <code>pip</code> but with <code>Makefile</code>s on top of it). Forget about annoying <code>CMake</code> or writing <code>Makefile</code>s by hand - finally we have something with an easy-to-read syntax: <a href="https://toml.io/en/">TOML</a>. Cargo, of course allows for creating <em>targets</em> and managing compiler and linker flags but removes all the nitty-gritty details of including files and setting up export options.</p>
<p>In order to create a new project you just need to run <code>cargo new coolprojectname</code> and if you want to build it and run you may run <code>cargo run</code> or <code>cargo build</code> if you want to build it only (and have a brief lesson in Rust compiler messages). For the release builds, just pass the flag <code>--release</code> to the compiler (and be sure to run this project with this command, otherwise be prepared for long trips to kitchen to kill the time while the scene renders).</p>
<h2 id="vec3-helper-class">Vec3 helper class</h2>
<h4 id="original-chapter-3"><a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html#thevec3class">Original Chapter 3</a></h4>
<p>Because we will be using some heavy 3D maths, we will need a helper class capable of performing some operations automatically instead of writing them by hand. This is where our code starts to diverge (rather strongly I would say). The original class relies on standard C++ features such as constructor and operator overloading with a sprinkle of friend functions on top, while Rust has no notion of overloading and instead achieves these things with the power of <em>traits</em> and <em>generics</em> which are also present in C++ albeit wear a cover of <em>templates</em>. I will not go into much detail on the topic of run-time vs compile-time polymorphism, but if you are eager for a read then I leave <a href="https://catonmat.net/cpp-polymorphism">one</a>.</p>
<p><strong>C++:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#ifndef VEC3_H
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#define VEC3_H
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;cmath&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;iostream&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">using</span> std<span style="color:#f92672">::</span>sqrt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">vec3</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span><span style="color:#f92672">:</span>
</span></span><span style="display:flex;"><span>        vec3() <span style="color:#f92672">:</span> e{<span style="color:#ae81ff">0</span>,<span style="color:#ae81ff">0</span>,<span style="color:#ae81ff">0</span>} {}
</span></span><span style="display:flex;"><span>        vec3(<span style="color:#66d9ef">double</span> e0, <span style="color:#66d9ef">double</span> e1, <span style="color:#66d9ef">double</span> e2) <span style="color:#f92672">:</span> e{e0, e1, e2} {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">double</span> <span style="color:#a6e22e">x</span>() <span style="color:#66d9ef">const</span> { <span style="color:#66d9ef">return</span> e[<span style="color:#ae81ff">0</span>]; }
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">double</span> <span style="color:#a6e22e">y</span>() <span style="color:#66d9ef">const</span> { <span style="color:#66d9ef">return</span> e[<span style="color:#ae81ff">1</span>]; }
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">double</span> <span style="color:#a6e22e">z</span>() <span style="color:#66d9ef">const</span> { <span style="color:#66d9ef">return</span> e[<span style="color:#ae81ff">2</span>]; }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        vec3 <span style="color:#66d9ef">operator</span><span style="color:#f92672">-</span>() <span style="color:#66d9ef">const</span> { <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">vec3</span>(<span style="color:#f92672">-</span>e[<span style="color:#ae81ff">0</span>], <span style="color:#f92672">-</span>e[<span style="color:#ae81ff">1</span>], <span style="color:#f92672">-</span>e[<span style="color:#ae81ff">2</span>]); }
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">double</span> <span style="color:#66d9ef">operator</span>[](<span style="color:#66d9ef">int</span> i) <span style="color:#66d9ef">const</span> { <span style="color:#66d9ef">return</span> e[i]; }
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">double</span><span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">operator</span>[](<span style="color:#66d9ef">int</span> i) { <span style="color:#66d9ef">return</span> e[i]; }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        vec3<span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">operator</span><span style="color:#f92672">+=</span>(<span style="color:#66d9ef">const</span> vec3 <span style="color:#f92672">&amp;</span>v) {
</span></span><span style="display:flex;"><span>            e[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">+=</span> v.e[<span style="color:#ae81ff">0</span>];
</span></span><span style="display:flex;"><span>            e[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">+=</span> v.e[<span style="color:#ae81ff">1</span>];
</span></span><span style="display:flex;"><span>            e[<span style="color:#ae81ff">2</span>] <span style="color:#f92672">+=</span> v.e[<span style="color:#ae81ff">2</span>];
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#f92672">*</span><span style="color:#66d9ef">this</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        vec3<span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">operator</span><span style="color:#f92672">*=</span>(<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">double</span> t) {
</span></span><span style="display:flex;"><span>            e[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">*=</span> t;
</span></span><span style="display:flex;"><span>            e[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">*=</span> t;
</span></span><span style="display:flex;"><span>            e[<span style="color:#ae81ff">2</span>] <span style="color:#f92672">*=</span> t;
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#f92672">*</span><span style="color:#66d9ef">this</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        vec3<span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">operator</span><span style="color:#f92672">/=</span>(<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">double</span> t) {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#f92672">*</span><span style="color:#66d9ef">this</span> <span style="color:#f92672">*=</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">/</span>t;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">double</span> <span style="color:#a6e22e">length</span>() <span style="color:#66d9ef">const</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> sqrt(length_squared());
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">double</span> <span style="color:#a6e22e">length_squared</span>() <span style="color:#66d9ef">const</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> e[<span style="color:#ae81ff">0</span>]<span style="color:#f92672">*</span>e[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">+</span> e[<span style="color:#ae81ff">1</span>]<span style="color:#f92672">*</span>e[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">+</span> e[<span style="color:#ae81ff">2</span>]<span style="color:#f92672">*</span>e[<span style="color:#ae81ff">2</span>];
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span><span style="color:#f92672">:</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">double</span> e[<span style="color:#ae81ff">3</span>];
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Type aliases for vec3
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">using</span> point3 <span style="color:#f92672">=</span> vec3;   <span style="color:#75715e">// 3D point
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">using</span> color <span style="color:#f92672">=</span> vec3;    <span style="color:#75715e">// RGB color
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#endif
</span></span></span></code></pre></div><p><strong>Rust</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">use</span> std::fmt;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">use</span> std::ops;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#[derive(Clone, Copy, Debug, Default)]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Vec3</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">pub</span> x: <span style="color:#66d9ef">f64</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">pub</span> y: <span style="color:#66d9ef">f64</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">pub</span> z: <span style="color:#66d9ef">f64</span>,
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">use</span> Vec3 <span style="color:#66d9ef">as</span> Point3;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">use</span> Vec3 <span style="color:#66d9ef">as</span> Color;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> Vec3 {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>(x: <span style="color:#66d9ef">f64</span>, y: <span style="color:#66d9ef">f64</span>, z: <span style="color:#66d9ef">f64</span>) -&gt; <span style="color:#a6e22e">Vec3</span> {
</span></span><span style="display:flex;"><span>        Vec3 { x, y, z }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">length</span>(<span style="color:#f92672">&amp;</span>self) -&gt; <span style="color:#66d9ef">f64</span> {
</span></span><span style="display:flex;"><span>        self.length_squared().sqrt()
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">length_squared</span>(<span style="color:#f92672">&amp;</span>self) -&gt; <span style="color:#66d9ef">f64</span> {
</span></span><span style="display:flex;"><span>        self.x <span style="color:#f92672">*</span> self.x <span style="color:#f92672">+</span> self.y <span style="color:#f92672">*</span> self.y <span style="color:#f92672">+</span> self.z <span style="color:#f92672">*</span> self.z
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> ops::AddAssign<span style="color:#f92672">&lt;&amp;</span>Vec3<span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">for</span> Vec3 {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">add_assign</span>(<span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> self, rhs: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">Vec3</span>) {
</span></span><span style="display:flex;"><span>        self.x <span style="color:#f92672">+=</span> rhs.x;
</span></span><span style="display:flex;"><span>        self.y <span style="color:#f92672">+=</span> rhs.y;
</span></span><span style="display:flex;"><span>        self.z <span style="color:#f92672">+=</span> rhs.z;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> ops::MulAssign<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">f64</span><span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">for</span> Vec3 {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">mul_assign</span>(<span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> self, rhs: <span style="color:#66d9ef">f64</span>) {
</span></span><span style="display:flex;"><span>        self.x <span style="color:#f92672">*=</span> rhs;
</span></span><span style="display:flex;"><span>        self.y <span style="color:#f92672">*=</span> rhs;
</span></span><span style="display:flex;"><span>        self.z <span style="color:#f92672">*=</span> rhs;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> ops::DivAssign<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">f64</span><span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">for</span> Vec3 {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">div_assign</span>(<span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> self, rhs: <span style="color:#66d9ef">f64</span>) {
</span></span><span style="display:flex;"><span>        self.x <span style="color:#f92672">/=</span> rhs;
</span></span><span style="display:flex;"><span>        self.y <span style="color:#f92672">/=</span> rhs;
</span></span><span style="display:flex;"><span>        self.z <span style="color:#f92672">/=</span> rhs;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>First important thing to note is that Rust provides no constructor overloading and achieves similar goals with the <em>Builder Pattern</em>. <a href="https://doc.rust-lang.org/1.0.0/style/ownership/builders.html">This pattern</a> is quite popular and has been with us for quite some time now and it neatly fits in the <em>assumed immutability</em> philosophy of Rust. So instead of providing an overloaded constructor for every type, you call the builder and chain functions like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> vector: <span style="color:#a6e22e">Vec3</span> <span style="color:#f92672">=</span> Vec3::new(<span style="color:#ae81ff">1.0</span>, <span style="color:#ae81ff">2.0</span>, <span style="color:#ae81ff">3.0</span>).frobnicate().build();
</span></span></code></pre></div><p>Quite simple, isn&rsquo;t it?</p>
<p>And it removes much of the noise related to the class (<a href="https://en.cppreference.com/w/cpp/language/rule_of_three">rule of the 5</a>? anyone?).</p>
<p>However, we will go even simpler route an simply provide various constructor functions. Using builder here would be a pretty big overkill. Rust goes even further so that we don&rsquo;t need to provide a default constructor when we derive a <code>Default</code> trait. It manages all the initialization for us and does this properly.</p>
<p>You may have noticed the <code>self</code> and <code>mut self</code> arguments to the functions of this class (yes I know, it is a <em>struct</em>) - these are the indicators that this is a <em>method</em> compared to ordinary <em>associated function</em> (you may know them as <em>static methods</em> from C++).</p>
<p>Probably quite important design decision worth mentioning now is that I am storing the <em>x, y, z</em> components separately instead of a static array of this form: <code>[1.0, 2.0, 3.0];</code>. You could do both and just benchmark it later, but remember that you cannot modify elements of this array without a <code>&amp;mut</code>, you also cannot resize this array (treat it as a statically allocated C array with normal Rust ownership rules). If you need resizable arrays on the spot then look no further than a <em>vector</em> or <a href="https://doc.rust-lang.org/std/vec/struct.Vec.html"><code>Vec</code></a> in Rust terms. There are some situation in which you need more than one mutable reference to an object. In these circumstances, wrap them in <a href="https://doc.rust-lang.org/std/cell/"><code>Cell</code></a> or bring upon thyself wrath of the Rust gods for using <a href="https://doc.rust-lang.org/std/keyword.unsafe.html"><code>unsafe</code></a> code where it can be avoided. It is often just a matter of preference, and what is more optimal for you!</p>
<p>This brings us to the most glaring difference - <code>operator</code>s or the lack thereof. Rust handles them via <em>traits</em> and requires to provide the <code>impl</code> block if one wishes to use them with custom types. Thus, we have types such as <a href="https://doc.rust-lang.org/std/ops/trait.Add.html"><code>Add</code></a>, <a href="https://doc.rust-lang.org/std/ops/trait.AddAssign.html"><code>AddAssign</code></a> and others, where all we as implementors have to do is provide the similarly named function implementation.</p>
<p>The next step is quite similar so I am not including the code for it here - we have to implement the <code>friend</code> functions for adding two <code>Vec3</code>s and some utility functions. Implementing the <code>std{io,err}</code> printing is worth looking at though, so here it is:
<strong>C++:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c++" data-lang="c++"><span style="display:flex;"><span><span style="color:#66d9ef">inline</span> std<span style="color:#f92672">::</span>ostream<span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">operator</span><span style="color:#f92672">&lt;&lt;</span>(std<span style="color:#f92672">::</span>ostream <span style="color:#f92672">&amp;</span>out, <span style="color:#66d9ef">const</span> vec3 <span style="color:#f92672">&amp;</span>v) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> out <span style="color:#f92672">&lt;&lt;</span> v.e[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#39; &#39;</span> <span style="color:#f92672">&lt;&lt;</span> v.e[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#39; &#39;</span> <span style="color:#f92672">&lt;&lt;</span> v.e[<span style="color:#ae81ff">2</span>];
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>Rust:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> fmt::Display <span style="color:#66d9ef">for</span> Vec3 {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">fmt</span>(<span style="color:#f92672">&amp;</span>self, f: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">mut</span> fmt::Formatter<span style="color:#f92672">&lt;</span>&#39;_<span style="color:#f92672">&gt;</span>) -&gt; <span style="color:#a6e22e">fmt</span>::Result {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">write!</span>(f, <span style="color:#e6db74">&#34;{} {} {}&#34;</span>, self.x, self.y, self.z)
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>While in C++ you define the <code>operator&lt;&lt;</code> for standard stream operations, in Rust you need to only <code>#[derive(Debug)]</code> in order to have a debug printing of your custom struct. You may be now wondering what is the difference between <a href="https://doc.rust-lang.org/std/fmt/trait.Debug.html"><code>Debug</code></a> and <a href="https://doc.rust-lang.org/std/fmt/trait.Display.html"><code>Display</code></a> and the question is quite simple. Debugging printing uses some heuristics to format our struct and print it in a predefined form with <code>{:?}</code> or <code>{:#?}</code> for a pretty-printed form, whereas using the <a href="https://doc.rust-lang.org/std/fmt/trait.Display.html"><code>Display</code></a> trait allows the struct implementor to specify a custom form of printing. Because we have a need for a custom printing format we go ahead and implement it. Profit?</p>
<h2 id="structuring-our-project">Structuring our project</h2>
<p>This is a slight detour from our project development, although an important one. In C and C++ the custom is to have one header and one source file per class (or functionality), this is encouraged by the notion of <em>Translation Unit</em> - compiler-friendly name for a single source file and all necessary stuff from headers for this file. In Rust, however, there is no customary split between headers and source files (in fact all crate is a single TU), so how on earth the compiler understands how to resolve the symbols and what are the dependencies between them?</p>
<p>The answer is: <em>namespaces</em>. In Rust, we write all code in source files only and can write either a binary application or a library (in our case it is a binary). Structuring the code properly is a challenge but boils down to either:</p>
<ul>
<li>creating a namespace inside the same source file</li>
<li>splitting the source file into modules</li>
<li>moving our code to a library crate</li>
</ul>
<p>These steps are illustrated somewhat accurately <a href="https://dev.to/ghost/rust-project-structure-example-step-by-step-3ee">in this blog post</a>, and serve as a complement to the official <a href="https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html">docs</a>.</p>
<p>Hence, in order to see our <code>Vec3</code> struct in our <code>main.rs</code> we need to first inform the compiler we are using another module - <code>mod vec3;</code> and then import the necessary types with <code>use vec3::Vec3;</code>. These types need to have a <code>pub</code> keyword next to them for the import to work. I will keep doing that for each new file that is created in the original tutorial, and if one is not necessary, it will be <strong>boldly</strong> stated here. In fact, renderer could be a library and the binary would only be using the functions from it to tell it what it wants to get rendered.</p>
<h2 id="who-owns-who">Who owns who?</h2>
<h4 id="original-chapter-5"><a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html#addingasphere">Original Chapter 5</a></h4>
<p>So far, so good. Assuming you went and read the original tutorial and implemented the code you were probably faced with an error similar to this:</p>
<pre tabindex="0"><code>error[E0382]: borrow of moved value: `ray`
    --&gt; src/main.rs:23:50
       |
    19 | fn ray_color(ray: Ray) -&gt; Color {
       |              --- move occurs because `ray` has type `Ray`, which does not implement the `Copy` trait
    20 |     if hit_sphere(&amp;Point3::with_values(0.0, 0.0, -1.0), 0.5, ray) {
       |                                                              --- value moved here
      ...
    23 |     let unit_direction: Vec3 = Vec3::unit_vector(ray.direction);
       |                                                  ^^^^^^^^^^^^^^ value used here after move
</code></pre><p>What on earth is going on here? Remember the time we added a <code>#[derive(Copy)]</code> statement to the <code>Vec3</code> class? Our <code>Ray</code> class requires such a statement to inform the compiler it is <code>Copy</code>able. But wait, this now has two <code>Vec3</code>s and they each have 3 doubles(<code>f64</code>) and this starts to amount to a significant overhead when passing on the stack - 2 * 3 * 8 = 48 <em>bytes!</em></p>
<p>Of course we may pretend such puny numbers do not bother us, but if we wanted to implement this renderer on anything slightly less powerful than our PC, we should strongly consider changing this approach. I guess I need not explain this further to a C++ dev *<em>shrugs</em>*.</p>
<p>What we do instead is pass the value by a reference or in Rust terms <em>borrow</em> it. Borrows come in two flavors: immutable (the default ones, also called shared) - <code>&amp;</code> and mutable - <code>mut&amp;</code>. There are two rules which cannot be broken</p>
<ul>
<li>You can have <em>either</em> one mutable reference <em>or</em> any number of immutable references</li>
<li>References must always be valid</li>
</ul>
<p>This is all, no more rules? Yes, this is the cornerstone of Rust&rsquo;s ownership model and it makes much easier to understand how it all fits together. Be sure to read up on <a href="https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html">this chapter</a> of the Rust Book in order to be on the same page here.</p>
<p>So, now we are <em>borrowing</em> things instead of copying them like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">// function
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">hit_sphere</span>(center: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">Point3</span>, radius: <span style="color:#66d9ef">f64</span>, ray: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">Ray</span>) -&gt; <span style="color:#66d9ef">bool</span> {<span style="color:#960050;background-color:#1e0010">…</span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// call site
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> hit_sphere(<span style="color:#f92672">&amp;</span>Point3::with_values(<span style="color:#ae81ff">0.0</span>, <span style="color:#ae81ff">0.0</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">1.0</span>), <span style="color:#ae81ff">0.5</span>, <span style="color:#f92672">&amp;</span>ray) {<span style="color:#960050;background-color:#1e0010">…</span>}
</span></span></code></pre></div><p>As you can see we are passing in an immutable reference <em>borrowing</em> the <code>Ray</code> for the time of the <code>hit_sphere</code> call. Keep in mind that it is in stark contrast to C++ where passing an object without a <code>&amp;</code> or <code>const&amp;</code> tag did a copy of the object and in Rust we have either a copy (if it satisfies the <code>Copy</code> trait) or a <em>move</em>, similar to C++ <code>std::move</code>.</p>
<h2 id="traits-box-and-rc">Traits, <code>Box</code> and <code>Rc</code></h2>
<h4 id="original-chapter-6"><a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html#surfacenormalsandmultipleobjects/alistofhittableobjects">Original Chapter 6</a></h4>
<p>So far, we were using only <code>struct</code>s and things associated with them to achieve our goals. Now, it is a good time to learn about <code>trait</code>s  and <em>trait objects</em>. <code>trait</code> is like an interface in C++ (okay, you got me, there is no such thing in C++, there are <em>pure virtual classes</em>), allowing for dynamic dispatch of the function call. They in fact allow for much more, but this time we are considering them only as <em>trait objects</em>. This means, that their size is evaluated at run-time rather than at compile-time. For this we need to store them on the <em>heap</em> rather than on the <em>stack</em>.</p>
<p>In order to be stored on the <em>heap</em> they have to be wrapped in a special Rust&rsquo;s built-in - <a href="https://doc.rust-lang.org/std/boxed/struct.Box.html"><code>Box</code></a>. I won&rsquo;t dig into details on this type, except mentioning it allocates the object it <em>boxes</em> on the <em>heap</em> (or whatever the custom allocator you provide for it <a href="https://github.com/rust-lang/rust/pull/77187">#77187</a>. Because of that we are conforming to Rust&rsquo;s rules on types with a known size and can happily store such <em>trait objects</em> like this: <code>Box&lt;dyn Hittable&gt;</code>. The <code>dyn</code> keyword the key here - it is the marker telling this is not a regular <code>trait</code>. [Polymorphism in Rust] elaborates on this topic and provides further references.</p>
<p>Thus, being familiar with this concept you try to implement the <code>HittableList</code> class in Rust and you encounter <code>std::vector</code> and <code>std::shared_ptr</code>. While you already know about <a href="https://doc.rust-lang.org/std/vec/struct.Vec.html"><code>Vec</code></a>, you need a replacement for <code>std::shared_ptr</code> - <a href="https://doc.rust-lang.org/std/rc/struct.Rc.html"><code>Rc</code></a>. This type is a Reference Counted pointer, so behaves similarly to its C++ sibling. It is not thread-safe however, so remember to use its cross-thread counterpart - <a href="https://doc.rust-lang.org/std/sync/struct.Arc.html"><code>Arc</code></a>. Both of them also, obviously store their contents on the stack - otherwise would be quite difficult to be shared between threads or different parts of the project.</p>
<p>Great, knowing all this, you finally translate the code (solve several problems with references and ownership on the way) and meet this brow-raising error:</p>
<pre tabindex="0"><code>error[E0382]: use of moved value: `temp_rec`
  --&gt; src/hittable_list.rs:42:34
   |
35 |         let mut temp_rec: HitRecord;
   |             ------------ move occurs because `temp_rec` has type `HitRecord`, which does not implement the `Copy` trait
...
42 |                 closest_so_far = temp_rec.t;
   |                                  ^^^^^^^^^^ value used here after move
43 |                 *rec = temp_rec;
   |                        -------- value moved here, in previous iteration of loop
</code></pre><p><strong>The code for this part looks like this in C++:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#66d9ef">bool</span> hittable_list<span style="color:#f92672">::</span>hit(<span style="color:#66d9ef">const</span> ray<span style="color:#f92672">&amp;</span> r, <span style="color:#66d9ef">double</span> t_min, <span style="color:#66d9ef">double</span> t_max, hit_record<span style="color:#f92672">&amp;</span> rec) <span style="color:#66d9ef">const</span> {
</span></span><span style="display:flex;"><span>    hit_record temp_rec;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">bool</span> hit_anything <span style="color:#f92672">=</span> false;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">auto</span> closest_so_far <span style="color:#f92672">=</span> t_max;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">auto</span><span style="color:#f92672">&amp;</span> object : objects) {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> (object<span style="color:#f92672">-&gt;</span>hit(r, t_min, closest_so_far, temp_rec)) {
</span></span><span style="display:flex;"><span>            hit_anything <span style="color:#f92672">=</span> true;
</span></span><span style="display:flex;"><span>            closest_so_far <span style="color:#f92672">=</span> temp_rec.t;
</span></span><span style="display:flex;"><span>            rec <span style="color:#f92672">=</span> temp_rec;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> hit_anything;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>Rust attempt:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> Hittable <span style="color:#66d9ef">for</span> HittableList {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">hit</span>(<span style="color:#f92672">&amp;</span>self, ray: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">Ray</span>, t_min: <span style="color:#66d9ef">f64</span>, t_max: <span style="color:#66d9ef">f64</span>, rec: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">mut</span> HitRecord) -&gt; <span style="color:#66d9ef">bool</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> temp_rec: <span style="color:#a6e22e">HitRecord</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> hit_anything: <span style="color:#66d9ef">bool</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> closest_so_far <span style="color:#f92672">=</span> t_max;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> object <span style="color:#66d9ef">in</span> <span style="color:#f92672">&amp;</span>self.objects {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">if</span> object.hit(ray, t_min, closest_so_far, <span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> temp_rec) {
</span></span><span style="display:flex;"><span>                hit_anything <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>                closest_so_far <span style="color:#f92672">=</span> temp_rec.t;
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">*</span>rec <span style="color:#f92672">=</span> temp_rec;
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        hit_anything
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>And now, before you start doubting your whole existence, let me explain why (and how) not to translate C++&rsquo;s return-by-reference code. Remember that Rust is fond of moving rather than coping (unless the type is marked <code>Copy</code>), and here the <code>temp_rec</code> variable gets set(otherwise Rust will nag you about the uninitialized variable) and then is read from in the loop to be finally assigned to the outbound reference. And this is where all the trouble happens&hellip; Here, the <code>temp_rec</code> is moved out and Rust cannot trust you that it will be initialized again in the successive iterations. After some clarifications on <a href="https://www.reddit.com/r/rust/comments/lukgyi/c_to_rust_introduction_with_practical_raytracing/gp7m45i?utm_source=share&amp;utm_medium=web2x&amp;context=3">reddit</a> the problem boils down to passing uninitialized memory to a Rust function. This can be done with the <em>unsafe</em> code or a special wrapper - <a href="https://doc.rust-lang.org/core/mem/union.MaybeUninit.html"><code>core::mem::MaybeUninit</code></a></p>
<p>Since this guide is meant to introduce you to Rust and how it achieves its goals, this is a perfect opportunity for some rustacean culture!</p>
<p>Enter <a href="https://doc.rust-lang.org/std/option/"><code>Option</code></a> - Rust&rsquo;s type for values that may or may not have a value (<code>std::optional</code>). <code>hit</code> function is a good candidate as this type&rsquo;s user as it both returns by reference and returns a success value. So let&rsquo;s see how this code would look like with this type instead:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> Hittable <span style="color:#66d9ef">for</span> HittableList {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">hit</span>(<span style="color:#f92672">&amp;</span>self, ray: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">Ray</span>, t_min: <span style="color:#66d9ef">f64</span>, t_max: <span style="color:#66d9ef">f64</span>) -&gt; Option<span style="color:#f92672">&lt;</span>HitRecord<span style="color:#f92672">&gt;</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> temp_rec: Option<span style="color:#f92672">&lt;</span>HitRecord<span style="color:#f92672">&gt;</span> <span style="color:#f92672">=</span> None;
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> closest_so_far <span style="color:#f92672">=</span> t_max;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> object <span style="color:#66d9ef">in</span> <span style="color:#f92672">&amp;</span>self.objects {
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">match</span> object.hit(ray, t_min, closest_so_far) {
</span></span><span style="display:flex;"><span>                Some(rec) <span style="color:#f92672">=&gt;</span> {
</span></span><span style="display:flex;"><span>                    closest_so_far <span style="color:#f92672">=</span> rec.t;
</span></span><span style="display:flex;"><span>                    temp_rec.replace(rec);
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>                None <span style="color:#f92672">=&gt;</span> {}
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        temp_rec
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Notice how the <code>bool</code> variable is gone and the code seems to be more understandable (at least for me). Gone is the misleading out-reference, and the function returns a <code>Option&lt;HitRecord&gt;</code> which is more idiomatic. What you may have noticed is that this type takes either a <code>None</code> or <code>Some(value)</code> for its contents. We initialize it with <code>None</code> and then if the <code>hit</code> function returned a <code>Some</code> we do our <code>true</code> branch. Otherwise we do nothing as indicated by <code>None =&gt; {}</code>. The <a href="https://doc.rust-lang.org/rust-by-example/flow_control/match.html"><code>match</code></a> clause is a powerful tool which was one of killer features when my colleague sold this language to me a while ago. If you forget about the <code>mut</code> modifier next to the variable&rsquo;s type, no worries - Rust will notify you about it &#x1f601;</p>
<p>There are small changes that need to be made in the <code>sphere.rs</code> file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> rec: Option<span style="color:#f92672">&lt;</span>HitRecord<span style="color:#f92672">&gt;</span> <span style="color:#f92672">=</span> Some(HitRecord::with_values(ray.at(root), root));
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> outward_normal: <span style="color:#a6e22e">Vec3</span> <span style="color:#f92672">=</span> (rec.as_ref().unwrap().p <span style="color:#f92672">-</span> self.center) <span style="color:#f92672">/</span> self.radius;
</span></span><span style="display:flex;"><span>rec.as_mut().unwrap().set_face_normal(ray, <span style="color:#f92672">&amp;</span>outward_normal);
</span></span></code></pre></div><p>The <code>HitRecord</code> variable is now initialized with <code>Some</code> and is modified later with <code>as_ref().unwrap()</code> combo. Be careful with using <code>unwrap()</code> though - it&rsquo;s like telling the compiler: <em>I know then value is not <code>None</code>, just give it to me!</em>, so when it is indeed <code>None</code>, the code will <a href="https://doc.rust-lang.org/stable/book/ch09-01-unrecoverable-errors-with-panic.html"><em>panic</em></a>. Similarly, if you wish to modify the object stored in the <code>Option</code>, call <code>as_mut()</code> before doing so. Finally we return the <code>Option&lt;HitRecord&gt;</code> as before.</p>
<h2 id="adding-external-crates-and-global-variables">Adding external crates and global variables</h2>
<h4 id="original-chapter-7"><a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html#antialiasing">Original Chapter 7</a></h4>
<p>In this chapter, we implement antialiasing using (not so) random capabilities of our hardware. For that we need a random number generator and while C++ has its <code>#include &lt;random&gt;</code>, Rust does not have a built-in for random numbers. Thus we will need to make use of our build and package manager - Cargo. As you already know, it handles most of the irritating details for us and lets us focus on the actual programming (while still allowing for plumbing the build machinery).</p>
<p>Adding a dependency to Cargo is as easy as including it in the <code>Cargo.toml</code> like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#a6e22e">dependencies</span>]
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">rand</span> = <span style="color:#e6db74">&#34;0.8.3&#34;</span>
</span></span></code></pre></div><p>This follows the <a href="https://semver.org/">semver</a> versioning system, which is quite easy to grasp. At this point I would also like to propose an alternative to manually adding the dependency with the command <code>cargo add</code>. It is not a built-in and requires you to install <a href="https://github.com/killercup/cargo-edit">cargo-edit</a>, which is a set of tools endorsed by the Rust language.</p>
<p>With the new <code>rand</code> package added, we may create our random-generating function. Honestly, I was not sure if it was worth creating a new function for this as the call is simply:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">use</span> rand::prelude::<span style="color:#f92672">*</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#[inline]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">random_f64</span>() -&gt; <span style="color:#66d9ef">f64</span> {
</span></span><span style="display:flex;"><span>    rand::thread_rng().gen()
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>While the original uses <code>static</code> function variables, meaning they are shared through all function calls. In Rust, however, there are no such things, and the global mutable shared state is strongly discouraged. There are some alternatives, like the <a href="https://rust-embedded.github.io/book/peripherals/singletons.html">singleton</a> pattern, but this would be too much for now. Thus, we remain steadfast in our initial implementation, knowing the <code>tread_rng</code> object is created each time we call <code>random_f64</code>.</p>
<h2 id="handling-errors">Handling <code>Error</code>s</h2>
<p>The rest of the original tutorial will guide you through the complex maths of rendering different materials and making the camera much more flexible. Notable differences include implementing a <code>trait</code> for Materials and <code>match</code>ing on <code>Option</code>s instead of usual branch conditions. Feel free to look up the <a href="https://github.com/JDuchniewicz/rustracing/tree/f290e44caaacb249c0fd6bd49a26ace4d8709370">repo</a> if you are stuck - but try to push it yourself and let the Rust compiler guide you &#x1f604;</p>
<p>Although this tutorial does not cover the language extensively (there is only so much one can do with a short project), it strives to show you some of most prominent features of the Rust programming language (<em>copyright</em>). Leaving out error handling would be a disgrace, so here they are: recoverable errors and unrecoverable errors. The latter were discussed briefly when introducing <code>unwrap</code>s on the <code>Option</code> type, while the former were not mentioned at all yet.</p>
<p>Recoverable errors are those, which signal an improper condition in the program, but do not abort it, simply try to mitigate (if possible) any consequences induced by such an error. For example, we had our function, which saved data to a <code>impl std::io::Write</code> buffer, and this write is not guaranteed to succeed. For instance, we are writing it to a file descriptor that is already closed by a different thread, or it is being written over the network and there was failure delivering the packet (this is of course quite stretched reason but you get the point). In such case we should handle this failure and probably reprocess this chunk of data, or at least signal this to the user.</p>
<p>So in our case we can change the signature of our function to be:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">pub</span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">write_color</span>(
</span></span><span style="display:flex;"><span>    stream: <span style="color:#66d9ef">&amp;</span><span style="color:#a6e22e">mut</span> <span style="color:#66d9ef">impl</span> Write,
</span></span><span style="display:flex;"><span>    pixel_color: <span style="color:#a6e22e">Color</span>,
</span></span><span style="display:flex;"><span>    samples_per_pixel: <span style="color:#66d9ef">i32</span>,
</span></span><span style="display:flex;"><span>) -&gt; Result<span style="color:#f92672">&lt;</span>(), io::Error<span style="color:#f92672">&gt;</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> r <span style="color:#f92672">=</span> pixel_color.x;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> g <span style="color:#f92672">=</span> pixel_color.y;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> b <span style="color:#f92672">=</span> pixel_color.z;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Divide the color by the number of samples
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">let</span> scale <span style="color:#f92672">=</span> <span style="color:#ae81ff">1.0</span> <span style="color:#f92672">/</span> samples_per_pixel <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">f64</span>;
</span></span><span style="display:flex;"><span>    r <span style="color:#f92672">=</span> (scale <span style="color:#f92672">*</span> r).sqrt();
</span></span><span style="display:flex;"><span>    g <span style="color:#f92672">=</span> (scale <span style="color:#f92672">*</span> g).sqrt();
</span></span><span style="display:flex;"><span>    b <span style="color:#f92672">=</span> (scale <span style="color:#f92672">*</span> b).sqrt();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">match</span> stream.write_fmt(<span style="color:#a6e22e">format_args!</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>,
</span></span><span style="display:flex;"><span>        (<span style="color:#ae81ff">256.0</span> <span style="color:#f92672">*</span> r.clamp(<span style="color:#ae81ff">0.0</span>, <span style="color:#ae81ff">0.999</span>)) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>,
</span></span><span style="display:flex;"><span>        (<span style="color:#ae81ff">256.0</span> <span style="color:#f92672">*</span> g.clamp(<span style="color:#ae81ff">0.0</span>, <span style="color:#ae81ff">0.999</span>)) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>,
</span></span><span style="display:flex;"><span>        (<span style="color:#ae81ff">256.0</span> <span style="color:#f92672">*</span> b.clamp(<span style="color:#ae81ff">0.0</span>, <span style="color:#ae81ff">0.999</span>)) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>
</span></span><span style="display:flex;"><span>    )) {
</span></span><span style="display:flex;"><span>        Ok(_) <span style="color:#f92672">=&gt;</span> Ok(()),
</span></span><span style="display:flex;"><span>        Err(e) <span style="color:#f92672">=&gt;</span> Err(e),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>You can see, that the ubiquitous <code>match</code> construct is used once again here. Of course at the callee side we should do something with our error, and for this simple problem I will simply report it to the <em>stderr</em> like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#66d9ef">match</span> write_color(<span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> handle, pixel_color, <span style="color:#66d9ef">SAMPLES_PER_PIXEL</span>) {
</span></span><span style="display:flex;"><span>    Ok(_) <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">continue</span>,
</span></span><span style="display:flex;"><span>    Err(e) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">eprint!</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;Oops, error </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> saving pixel </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> for indices i </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> j </span><span style="color:#e6db74">{}</span><span style="color:#e6db74">&#34;</span>,
</span></span><span style="display:flex;"><span>        e, pixel_color, i, j
</span></span><span style="display:flex;"><span>    ),
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>You can see the obvious downside to this? Yes, while verbosity is often a desired feature and makes understanding code easier, being over-verbose counters this effect, effectively (no pun intended) bloating the code - rendering it tedious to comprehend. Thankfully we have a syntactic sugar made just for this occasion - <code>?</code> operator. This allows for propagating any error that arose until it is finally handled in the outer scope. So now we simply write:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span>stream.write_fmt(<span style="color:#a6e22e">format_args!</span>(
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>,
</span></span><span style="display:flex;"><span>      (<span style="color:#ae81ff">256.0</span> <span style="color:#f92672">*</span> r.clamp(<span style="color:#ae81ff">0.0</span>, <span style="color:#ae81ff">0.999</span>)) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>,
</span></span><span style="display:flex;"><span>      (<span style="color:#ae81ff">256.0</span> <span style="color:#f92672">*</span> g.clamp(<span style="color:#ae81ff">0.0</span>, <span style="color:#ae81ff">0.999</span>)) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>,
</span></span><span style="display:flex;"><span>      (<span style="color:#ae81ff">256.0</span> <span style="color:#f92672">*</span> b.clamp(<span style="color:#ae81ff">0.0</span>, <span style="color:#ae81ff">0.999</span>)) <span style="color:#66d9ef">as</span> <span style="color:#66d9ef">i32</span>
</span></span><span style="display:flex;"><span>  ))<span style="color:#f92672">?</span>;
</span></span></code></pre></div><p>and we handle the error in the <code>main</code> function. Of course we need to change <code>main</code>s signature to also return a <code>Result&lt;(), io::Error&gt;</code>.</p>
<p>This is by no means complete introduction to error handling and this subject is quite broad. I recommend of course reading the <a href="https://doc.rust-lang.org/book/ch09-00-error-handling.html">chapter</a> on error handling in the official book and then follow various resources liked there for building on top of it.</p>
<h2 id="conclusions">Conclusions</h2>
<p>Whew, that was quite a lot of information to digest. I hope you took your time and learned some valuable knowledge about the language and how it differs from the C++ or other languages you are familiar with. I skipped over some subjects, like <a href="https://doc.rust-lang.org/std/keyword.unsafe.html"><code>unsafe</code></a> Rust or <a href="https://doc.rust-lang.org/stable/embedded-book/intro/index.html">embedded</a> Rust applications. There is also much more you can do with the <code>trait</code> system, <a href="https://doc.rust-lang.org/book/ch16-00-concurrency.html">concurrency</a>, <a href="https://rust-lang.github.io/async-book/"><code>async</code></a> programming and <a href="https://doc.rust-lang.org/book/ch13-00-functional-features.html">closures</a>. There are also many other functional topics and of course <a href="https://doc.rust-lang.org/book/ch08-00-common-collections.html">data structures</a>, under the guise of <em>collections</em>.</p>
<p>All credit for the raytracer algorithms + the guide I based this post on, goes to the author - Peter Shirley. Once again, thank you for sharing with us your expertise about computer graphics and providing the readers with valuable insights and tricks. If you are interested in deepening your knowledge on this topic - check out his other <a href="https://in1weekend.blogspot.com/">books</a>.</p>
<p>Also, thank you kind reader for the patience to read this thing through. Don&rsquo;t hesitate to leave review below or reach to me directly via my <a href="mailto:j.duchniewicz@gmail.com">mail</a>. Enjoy the newly met Rust language and let it help you in your programming adventures!</p>
<h2 id="ending-words">Ending words</h2>
<p>As of today, the subject of the error handling is so important, there is a whole <a href="https://github.com/rust-lang/project-error-handling">project group</a> in the Rust community, of which I am a proud member. Come over and chat with us if something is bothering you about the current state of error handling or you would like to get involved in the process.</p>
<p>If you like what I&rsquo;m doing and you would like to see more of it - consider buying me a [coffee] &#x2615;
[coffee]: <a href="https://www.buymeacoffee.com/jduchniewicz">https://www.buymeacoffee.com/jduchniewicz</a></p>
]]></content>
        </item>
        
        <item>
            <title>Workman</title>
            <link>https://jduchniewicz.com/posts/2021/02/workman/</link>
            <pubDate>Wed, 17 Feb 2021 14:04:12 +0200</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2021/02/workman/</guid>
            <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;h3 id=&#34;update-2802&#34;&gt;Update 28.02&lt;/h3&gt;
&lt;p&gt;I am already writing with almost 70 wpm constant. So this is quite productive layout all in all.&lt;/p&gt;
&lt;p&gt;This entry is a special one! It is dedicated to people brave or crazy enough to do a keyboard layout switch. I won&amp;rsquo;t go into details on why you should consider a different layout if you are like me, spending rather big part of your life going clack-clack and pretending you are working and not browsing reddit and social media. I curated some materials you may want to study in order to make up your mind:&lt;/p&gt;</description>
            <content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<h3 id="update-2802">Update 28.02</h3>
<p>I am already writing with almost 70 wpm constant. So this is quite productive layout all in all.</p>
<p>This entry is a special one! It is dedicated to people brave or crazy enough to do a keyboard layout switch. I won&rsquo;t go into details on why you should consider a different layout if you are like me, spending rather big part of your life going clack-clack and pretending you are working and not browsing reddit and social media. I curated some materials you may want to study in order to make up your mind:</p>
<ul>
<li><a href="https://workmanlayout.org/">original</a> - The official Workman layout</li>
<li><a href="https://icyphox.sh/blog/workman/">icyphox</a> - an opinionated blog describing similar experience to mine</li>
<li><a href="http://patorjk.com/keyboard-layout-analyzer/#/main">Keyboard Layout Analyzer</a> - website that analyzes the text you input and spews out the most optimal layout for it</li>
<li><a href="http://mkweb.bcgsc.ca/carpalx/">carpalx</a> - two layouts in one, a popular alternative to Workman and Colemak</li>
<li><a href="https://keyboard-design.com/best-layouts.html">keyboard-design</a> - a good source of info from a person experimenting a lot with kb layouts</li>
</ul>
<p>There seem to be a shortage of relevant study on this topic, which was surprising to me, as nowadays we all use keyboards daily (especially these awful laptop ones). If you, dear reader are a specialist, please consider doing such research and help us all find the perfect layout. My hope is that we will be soon having personalized layouts so that our hands do not strain so much.</p>
<p>I decided to switch layouts because I started to feel fatigue after prolonged sessions of writing journals or even ordinary code. Foreseeing future and being fond of my hands I knew something had to be done!</p>
<h2 id="enter-workman">Enter Workman</h2>
<p>My interest was piqued by several layouts, namely Colemak, Colemak-DH and classic and well-known Dvorak. However, I was sold on Workman as the upgraded Colemak (which is also repaired by the DH mod). I may try the DH mod in some time and decide it is superior to Workman but this is unlikely. Having spent just 12 hours practicing I am able to type with 50 WPM and found most keys easy to learn and replace.</p>

    <img src="/workman/workman.png"  alt="Workman layout"  class="center"  style="border-radius: 8px;"  />


<p>As for the practice website, I can highly recommend <a href="https://www.keybr.com/">keybr</a>, which guides you quite well through all keys in a reasonable order, gives you neat graphs and even some competition! Additionally if you want to have some fun while you are at it, try <a href="https://zty.pe/">ztype</a> - a small typing space shooter game.</p>
<h2 id="installation-x11-setup">Installation (X11 setup)</h2>
<p>As for the X11 (main system) keyboard setup and for other systems, in the basic form it requires only installation of the layout from official <a href="https://github.com/workman-layout/Workman/">workman</a> repo - system specific instructions are provided there. In my case I wanted to have both German and Polish special signs and followed this great <a href="https://michal.kosmulski.org/computing/articles/custom-keyboard-layouts-xkb.html">tutorial</a> by Michał and ended up with <a href="https://gist.github.com/JDuchniewicz/eb1346f8759340a1ffeed81ed1022877">such</a> a configuration.</p>
<p>Remember to create a fresh file, otherwise you won&rsquo;t be able to turn the layout on with the command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>setxkbmap -v workman_pl_de <span style="color:#f92672">&amp;&amp;</span> xset r <span style="color:#ae81ff">66</span>
</span></span></code></pre></div><p>Where <code>xset</code> part takes care of proper autorepeat rate of keys.</p>
<h2 id="setup-vim">Setup Vim</h2>
<h3 id="vanilla">Vanilla</h3>
<p>Assuming you need a text editor, you probably do not want to alter your muscle memory and relearn where each special key is after the switch. Thankfully, vim provides users with a method <code>langmap</code> which allows for easy remapping of all key combinations to a new layout leaving your muscle memory intact.</p>
<p>I found this to be quite tempting but soon fell into the habit of striking the Workman keys more and more and turned it off. Here is the relevant <a href="https://github.com/nicwest/vim-workman">plugin</a>, but it is in my opinion not that developed (shortcuts like <code>Ctrl-WW</code> are missing).</p>
<p>In order to make my life with <code>hjkl</code> bearable (too much muscle memory) I remapped them to<code>Alt-[yneo]</code> so they are in the same place as before with just the modifier key added. Hopefully, in time I will become true vim ninja not needing these puny keys and relying only on motions and commands, but today I am still too used to corrections and off-by-one movements.
The bindings can be seen here (the funny <code>^[</code> sign is the escape sign for the <code>Alt</code> key and you obtain it by pressing <code>Ctrl-V</code> in insert mode and pressing the key you want to input).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-vimrc" data-lang="vimrc"><span style="display:flex;"><span><span style="color:#75715e">&#34;&#34;&#34; Workman</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">&#34; Map to Alt-yneo instead of hjkl</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">nnoremap</span> ^[<span style="color:#a6e22e">y</span> <span style="color:#a6e22e">h</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">nnoremap</span> ^[<span style="color:#a6e22e">n</span> <span style="color:#a6e22e">j</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">nnoremap</span> ^[<span style="color:#a6e22e">e</span> <span style="color:#a6e22e">k</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">nnoremap</span> ^[<span style="color:#a6e22e">o</span> <span style="color:#a6e22e">l</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">vnoremap</span> ^[<span style="color:#a6e22e">y</span> <span style="color:#a6e22e">h</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">vnoremap</span> ^[<span style="color:#a6e22e">n</span> <span style="color:#a6e22e">j</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">vnoremap</span> ^[<span style="color:#a6e22e">e</span> <span style="color:#a6e22e">k</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">vnoremap</span> ^[<span style="color:#a6e22e">o</span> <span style="color:#a6e22e">l</span>
</span></span></code></pre></div><p>In case you are not familiar with vim remappings, <code>nnoremap</code> is for the normal mode and <code>vnoremap</code> is for the visual. This way I can use my long-learned habits of <code>hjkl</code> with only a slight complication.
Of course now we come to the topic of plugins but this is only slightly more convolved.</p>
<h3 id="plugins">Plugins</h3>
<p>This post is not dedicated to advocating any particular plugins, but if you are curious which I am using, take a look at my <a href="https://github.com/JDuchniewicz/dotfiles/blob/master/.vimrc">vimrc</a>.
Because my muscle memory was not that tied to particular keys and instead remembered the combination by name, I did not change anything here. You, however might want to do some jumping around here, depending on your usage of non-vanilla vim.</p>
<h2 id="setup-fish">Setup Fish</h2>
<p>This setting applies to every shell there is and I will focus on the fish shell (which you should try out if you never did!). Most probably you already know about going forwards and backward through the shell history commands (<code>Ctrl-p</code> and <code>Ctrl-n</code> - previous and next) and if you didn&rsquo;t they try it out and don&rsquo;t thank me :) These keys are actually in quite handy place on the keyboard so no need to change them for me, even more, they are now handier to use in my opinion!</p>
<p>The keys I am having most trouble with are <code>Ctrl-c</code> and <code>Ctrl-v</code> which are shifted one column to the right. Also, moving around the command parts in the shell prompt is non-intuitive and I might remap this later via <a href="https://fishshell.com/docs/current/cmds/bind.html">fish-bind</a>.</p>
<p>The last of inconveniences are related to a plugin I am using systemwise (<a href="https://github.com/junegunn/fzf">fzf</a> - smart searching and directory changing). This plugin is a lifesaver but getting used to misplaced <code>r</code>, <code>t</code> and <code>c</code> is annoying. Of course it can be remapped, but not worth it anymore.</p>
<p>Lastly, browsing diffs, manpages and all other utilities basing on the emacs/vim bindings is a stretch, but as possible one and even as I was browsing manpages today, I did not have as much trouble as I thought.</p>
<h2 id="setup-tmux">Setup Tmux</h2>
<p>Setting up tmux is fairly easy, as since several versions it has become highly customizable. Below you may find the most important settings along their QWERTY counterparts.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-vimrc" data-lang="vimrc"><span style="display:flex;"><span>### <span style="color:#a6e22e">QWERTY</span> ###
</span></span><span style="display:flex;"><span># <span style="color:#a6e22e">Use</span> <span style="color:#a6e22e">vim</span> <span style="color:#a6e22e">type</span> <span style="color:#a6e22e">keys</span> <span style="color:#a6e22e">for</span> <span style="color:#a6e22e">navigating</span> <span style="color:#a6e22e">between</span> <span style="color:#a6e22e">windows</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">h</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">L</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">l</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">R</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">k</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">U</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">j</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">D</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># <span style="color:#a6e22e">Use</span> <span style="color:#a6e22e">vim</span> <span style="color:#a6e22e">type</span> <span style="color:#a6e22e">keys</span> <span style="color:#a6e22e">for</span> <span style="color:#a6e22e">re</span>-<span style="color:#a6e22e">sizing</span> <span style="color:#a6e22e">panes</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> -<span style="color:#a6e22e">r</span> &lt; <span style="color:#a6e22e">resize</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">L</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> -<span style="color:#a6e22e">r</span> &gt; <span style="color:#a6e22e">resize</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">R</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> -<span style="color:#a6e22e">r</span> - <span style="color:#a6e22e">resize</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">D</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> -<span style="color:#a6e22e">r</span> + <span style="color:#a6e22e">resize</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">U</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># <span style="color:#a6e22e">Copying</span> <span style="color:#a6e22e">with</span> <span style="color:#a6e22e">vim</span> <span style="color:#a6e22e">shortcuts</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">v</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">begin</span>-<span style="color:#a6e22e">selection</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">y</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">selection</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">r</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">rectangle</span>-<span style="color:#a6e22e">toggle</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">P</span> <span style="color:#a6e22e">paste</span>-<span style="color:#a6e22e">buffer</span>
</span></span><span style="display:flex;"><span>#<span style="color:#66d9ef">set</span>-<span style="color:#a6e22e">option</span> -<span style="color:#a6e22e">s</span> <span style="color:#66d9ef">set</span>-<span style="color:#a6e22e">clipboard</span> <span style="color:#a6e22e">off</span>
</span></span><span style="display:flex;"><span>#
</span></span><span style="display:flex;"><span>## <span style="color:#a6e22e">copy</span> <span style="color:#a6e22e">to</span> <span style="color:#a6e22e">the</span> <span style="color:#a6e22e">xclip</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">Enter</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">pipe</span>-<span style="color:#a6e22e">and</span>-<span style="color:#a6e22e">cancel</span> <span style="color:#e6db74">&#34;xclip -sel clip -i&#34;</span>
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">MouseDragEnd1Pane</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">pipe</span>-<span style="color:#a6e22e">and</span>-<span style="color:#a6e22e">cancel</span> <span style="color:#e6db74">&#34;xclip -sel clip -i&#34;</span>
</span></span><span style="display:flex;"><span>#
</span></span><span style="display:flex;"><span>#<span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">c</span> <span style="color:#a6e22e">source</span>-<span style="color:#a6e22e">file</span> ~<span style="color:#e6db74">/.tmux/</span><span style="color:#a6e22e">dev</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>### <span style="color:#a6e22e">Workman</span> ####
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">y</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">L</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">i</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">R</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">e</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">U</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">n</span> <span style="color:#a6e22e">select</span>-<span style="color:#a6e22e">pane</span> -<span style="color:#a6e22e">D</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">m</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">begin</span>-<span style="color:#a6e22e">selection</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">j</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">selection</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">r</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">rectangle</span>-<span style="color:#a6e22e">toggle</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">P</span> <span style="color:#a6e22e">paste</span>-<span style="color:#a6e22e">buffer</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">set</span>-<span style="color:#a6e22e">option</span> -<span style="color:#a6e22e">s</span> <span style="color:#66d9ef">set</span>-<span style="color:#a6e22e">clipboard</span> <span style="color:#a6e22e">off</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># <span style="color:#a6e22e">copy</span> <span style="color:#a6e22e">to</span> <span style="color:#a6e22e">the</span> <span style="color:#a6e22e">xclip</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">Enter</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">pipe</span>-<span style="color:#a6e22e">and</span>-<span style="color:#a6e22e">cancel</span> <span style="color:#e6db74">&#34;xclip -sel clip -i&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span>-<span style="color:#a6e22e">key</span> -<span style="color:#a6e22e">T</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">mode</span>-<span style="color:#a6e22e">vi</span> <span style="color:#a6e22e">MouseDragEnd1Pane</span> <span style="color:#a6e22e">send</span>-<span style="color:#a6e22e">keys</span> -<span style="color:#a6e22e">X</span> <span style="color:#a6e22e">copy</span>-<span style="color:#a6e22e">pipe</span>-<span style="color:#a6e22e">and</span>-<span style="color:#a6e22e">cancel</span> <span style="color:#e6db74">&#34;xclip -sel clip -i&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">bind</span> <span style="color:#a6e22e">m</span> <span style="color:#a6e22e">source</span>-<span style="color:#a6e22e">file</span> ~<span style="color:#e6db74">/.tmux/</span><span style="color:#a6e22e">dev</span>
</span></span></code></pre></div><p>With these binding handy, I can do most tasks as before. The only problems being the vim mode bindings which seem to be hardcoded in the tmux source code. After using them for a while I can say it that they are mostly comfortable and I do not plan to change them.</p>
<h2 id="browser">Browser</h2>
<p>Like most modern people, I am using a GUI browser (Firefox) and sometime don&rsquo;t want to get distracted by removing my hands from the keyboard. I tried using some plugins to automate that, starting from saka key, to finish on Vimium.It allows for key rebinding, so my precious <code>hjkl</code> is safe. Because I am terrible at keeping it clean, my tabbar has over 350! tabs (don&rsquo;t ask) - thus last year I decided to write a small plugin which would automate my switching to them and searching in different windows only - <a href="https://addons.mozilla.org/en-US/firefox/addon/find-tab/">find-tab</a>. Now, with Vimium I got most of its functionality already there, but Vimium is slightly over-dumbing it and I prefer using my plugin.</p>
<h2 id="conclusions">Conclusions</h2>
<p>While the transition to the new layout is not smooth and without its hindrances, I am glad I could rebind almost everything as wanted and achieve a portable layout without any system hacking and rebinding keys in the Xorg configs. Typing with some speed this soon after switching is a pleasure for my ego (I improved 5 WPM since starting to write this post - of course with some training in between :)</p>
<p>I am keyed up (no pun intended) with the speeds and pleasure I will have from mastering this layout soon. I also hope I will be able to switch to QWERTY from time to time and not be totally baffled by it (reddit users claim this is not a big deal after some time so I remain positive).</p>
<p>I hope this post will help you with choosing the proper layout, and if it is workman, then transitioning to it as well. We should take great care of our bodies and especially hands, since most of us are earning their lives with their help. Thank you for reading and stay safe! Please comment below and help me make this blog a better place.</p>
<p>Btw. I changed the comment engine to <a href="https://utteranc.es/">  utterances </a> as it is more responsible in terms of privacy than disqus.</p>
<p>Considering that you like what I&rsquo;m doing and you would like to see more of it - consider buying me a [coffee] &#x2615;
[coffee]: <a href="https://www.buymeacoffee.com/jduchniewicz">https://www.buymeacoffee.com/jduchniewicz</a></p>
]]></content>
        </item>
        
        <item>
            <title>First Thesis Released!</title>
            <link>https://jduchniewicz.com/posts/2020/10/first-thesis-released/</link>
            <pubDate>Sun, 18 Oct 2020 17:00:18 +0200</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2020/10/first-thesis-released/</guid>
            <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I am bursting with excitement as I am writing this - I can finally share with the world something I have been working very hard for the first half of this overly eventful year!&lt;/p&gt;
&lt;p&gt;Today I have uploaded my Bachelor&amp;rsquo;s thesis for open access - it can be viewed at &lt;a href=&#34;https://jduchniewicz.com/FPGA-synth.pdf&#34;&gt;this link&lt;/a&gt;. If this was something not worth your time or digital space (&lt;a href=&#34;https://www.visualcapitalist.com/wp-content/uploads/2019/04/data-generated-each-day-wide.html&#34;&gt;already polluted&lt;/a&gt;), I would not blog about it :)&lt;/p&gt;</description>
            <content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>I am bursting with excitement as I am writing this - I can finally share with the world something I have been working very hard for the first half of this overly eventful year!</p>
<p>Today I have uploaded my Bachelor&rsquo;s thesis for open access - it can be viewed at <a href="https://jduchniewicz.com/FPGA-synth.pdf">this link</a>. If this was something not worth your time or digital space (<a href="https://www.visualcapitalist.com/wp-content/uploads/2019/04/data-generated-each-day-wide.html">already polluted</a>), I would not blog about it :)</p>
<p>This project was probably the most ambitious one in my whole life, and what is most important - successful. Back in my previous job, my colleagues who have already graduated presented me with their theses, one of which utilized an FPGA for megahertz signal synthesis. Much as I like tackling challenges, <a href="https://www.amazon.com/High-Speed-Digital-Design-Handbook/dp/0133957241">black magic</a> was not something I was eager to dab in. However, my curiosity on the subject of FPGAs was born, and soon I begun development of my thesis.</p>
<p>In case you are a busy person and don&rsquo;t want to dig into the thesis too much, here is the link to my <a href="https://jduchniewicz.com/about/">about</a> subpage containing the abstract of the paper, and here are some sounds generated on the FPGA and recorded on the Linux side of the SoC.</p>
<h4 id="sine-wave">Sine wave</h4>
<p><audio src="/69sine.mp3" controls preload></audio></p>
<h4 id="square-wave">Square wave</h4>
<p><audio src="/69square.mp3" controls preload></audio></p>
<h4 id="sawtooth-wave">Sawtooth wave</h4>
<p><audio src="/69sawtooth.mp3" controls preload></audio></p>
<h4 id="triangle-wave">Triangle wave</h4>
<p><audio src="/69triangle.mp3" controls preload></audio></p>
<h4 id="polyphonic-capabilities">Polyphonic capabilities</h4>
<p><audio src="/polyphony.mp3" controls preload></audio></p>
<h4 id="beatles---let-it-be-intro-tragic-cover-by-me">Beatles - Let it be intro (tragic cover by me…)</h4>
<p><audio src="/letitbe.mp3" controls preload></audio></p>
<h4 id="favourite-song-of-pope-jp-ii---barka">Favourite song of Pope JP II - Barka</h4>
<p><audio src="/barka.mp3" controls preload></audio></p>
<h2 id="line-up">Line-up</h2>
<p>Barring some digital circuits courses at WUT, I was on uncharted waters and had to quickly get a grasp on the subject. In this series of posts I wish to give you brief introduction to the subject of FPGAs and sound synthesis, along with some tips I wish somebody told me when I started learning it. The listing below may be changed in future, so do not take it for granted, additional topics may yet arise.</p>
<h3 id="agenda">Agenda</h3>
<ul>
<li>FPGAs for software engineers</li>
<li>Digital Synthesis basics and tips</li>
<li>Digital Filtering basics and State Variable Filter Overview</li>
<li>FPGAs and Linux</li>
<li>Linux Device Drivers basics</li>
<li>Linux ALSA and DMA Drivers</li>
</ul>
<h2 id="update-022021">Update 02.2021</h2>
<p>I did not write these blog entries yet as the end of the year time was rife with other project (Envidrawer, Robotics) and I will be coming back to the topic pretty soon from a different angle (I hope so!). If somebody cannot wait that long, please message me and I will be glad to share my experience.</p>
<p>The code (with detailed guides etc.) will be available on GitHub soon (although astute readers will find almost all necessities in the paper already).</p>
<h2 id="other-updates">Other updates</h2>
<p>I recently got chosen to participate in a project on element14 - a sustainable closed-space smart gardening solution utilizing less than 1m<sup>3</sup> of space <a href="https://www.element14.com/community/roadTestApps/39149/l/1-meter-of-pi-envidrawer">Envidrawer</a>. I will probably post some more updates regarding this once the project is worth showing off :)</p>
<p>I am gradually falling in love with Rust and will be trying some embedded solutions, probably mixing some freshly learned Machine Learning tricks to spice it up. Meanwhile, stay tuned for first post of FPGA series, coming this month!</p>
<p>Thanks for reading!</p>
<p>If you like what I&rsquo;m doing and you would like to see more of it - consider buying me a [coffee] &#x2615;
[coffee]: <a href="https://www.buymeacoffee.com/jduchniewicz">https://www.buymeacoffee.com/jduchniewicz</a></p>
]]></content>
        </item>
        
        <item>
            <title>ALSA Adventures</title>
            <link>https://jduchniewicz.com/posts/2020/09/alsa-adventures/</link>
            <pubDate>Tue, 29 Sep 2020 18:51:47 +0200</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2020/09/alsa-adventures/</guid>
            <description>&lt;h2 id=&#34;a-few-words-of-explanation&#34;&gt;A few words of explanation&lt;/h2&gt;
&lt;p&gt;This is my second post, glaringly differing from the previous one in terms of topics presented. Right now I am working on a visualizer-equalizer project in Rust language (for hands-on learning experience!).
As the name implies, it concerns Linux Audio and specifically Advanced Linux Audio System, which is one of more popular low-level frameworks on this OS. Since Rust audio frameworks are mostly in their infancy at the time of writing this, I decided to use [cpal] library which interfaces several other backends for portability of the application.&lt;/p&gt;</description>
            <content type="html"><![CDATA[<h2 id="a-few-words-of-explanation">A few words of explanation</h2>
<p>This is my second post, glaringly differing from the previous one in terms of topics presented. Right now I am working on a visualizer-equalizer project in Rust language (for hands-on learning experience!).
As the name implies, it concerns Linux Audio and specifically Advanced Linux Audio System, which is one of more popular low-level frameworks on this OS. Since Rust audio frameworks are mostly in their infancy at the time of writing this, I decided to use [cpal] library which interfaces several other backends for portability of the application.</p>
<p>Right now the application is utilizing GTK for the GUI part and is not yet ready for show-off (unfortunately), but it will be soon!</p>
<h2 id="goal">Goal</h2>
<p>Because in principle I want to display frequency components of the audio signal being played in my headphones, I need to split the sound source for recording. This will be achieved by modifying ALSA&rsquo;s <code>.asoundrc</code> file, or any other configuration file found in <code>/etc/alsa/conf.d/</code> (note that ones with higher index will overwrite variables set in these with lower).
Once, the configuration is proper, I want to see the device listed with either <code>aplay -L</code> or <code>arecord -L</code> and make sure I can use it as desired. Astute readers may notice that I use <em>device</em> for something not residing in <code>/dev/</code>, which is because ALSA allows for virtual devices that do not have 1 to 1 mapping with these from <code>/dev/</code>.</p>
<h2 id="small-alsa-introduction">Small ALSA introduction</h2>
<p>I have mentioned ALSA too many times before without explaining why does one even need to use it in the first place. In the days of yore, there was the Open Sound System, which was the go-to audio backend for Unices. Once we entered more modern days, something more robust and thread-safe was required, and thus ALSA was born. Inside Linux kernel, all audio devices are served via the ALSA API (which is not the most pleasant API to work with).</p>
<p>Whenever any audio-related functionality is performed on Linux, it goes through ALSA eventually (or OSS if it is a dinosaur kernel). Other sound servers such as JACK or PulseAudio are a kind of <em>extension</em> of ALSA&rsquo;s functionality and they are two most popular audio servers. JACK is favoured by people enamored with good audio quality and low latency, whereas PulseAudio is distributed with most major Linux distros, such as Ubuntu or Fedora. Therefore, getting a grasp on basics of ALSA is often useful when you would like to modify audio related settings in your system.</p>
<h2 id="alsa-config">ALSA config</h2>
<p>The [minimal configuration file] that satisfied my needs took me a while to find. After understanding the syntax of the config files (which is explained nicely [here]), I was able to understand and tweak the <code>.asoundrc</code> but still no device would show up when queried. After hours of searching to and fro, I decided to dig into <code>cpal</code>&rsquo;s code and then into Rust&rsquo;s ALSA bindings. It turns out that ALSA devices can have <em>hints</em> which are used to describe it more verbosely and as it turned out: <strong>virtual devices need hints</strong>. Below you may see what does the proper config file look like to allow for simultaneous sound playback and recording.</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">defaults.pcm.dmix.!rate 48000
defaults.pcm.dmix.!format S32_LE
pcm.multi {
    type multi
    slaves.a.pcm &#34;dmix:PCH&#34;
    slaves.a.channels 2
    slaves.b.pcm &#34;dmix:Loopback&#34;
    slaves.b.channels 2
    bindings.0 { slave a; channel 0; } # bind channels to slave devices
    bindings.1 { slave a; channel 1; }
    bindings.2 { slave b; channel 0; }
    bindings.3 { slave b; channel 1; }
}
pcm.both { # duplicates channels for &#39;multi&#39; module 
    type route
    slave.pcm &#34;multi&#34;
    ttable.0.0 1
    ttable.1.1 1
    ttable.0.2 1
    ttable.1.3 1
}
pcm.!default { # override default PCM
    type asym # type asymmetrical
    playback.pcm &#34;plug:both&#34;
    capture.pcm &#34;plug:dsnoop:PCH&#34;
    # Need a hint, else aplay -L won&#39;t show this device
    hint.description &#34;Default output device forwarding captured data to Loopback loop&#34; # THIS IS THE OFFENDER (rather lack of it)
}

#pcm.loop &#34;plug:\&#34;dsnoop:Loopback,1\&#34;&#34; # this is the same as below - just compact
pcm.loop {
    type plug
    slave.pcm &#34;dsnoop:Loopback,1&#34;
    hint.description &#34;Loopback device which captures from default PCM&#34;
}
</code></pre><p>Brief explanation, this config overrides default sampling rate and format for this devices streams. It defines several PCM modules (kind of ALSA&rsquo;s processing entities), and connects them, multiplexing the playback to both a Loopback device and audio device down the chain. This SO [anwser] goes into much detail about it if you wish to understand more about it.</p>
<h2 id="pulseaudio-config">PulseAudio config</h2>
<p>As most users won&rsquo;t need to dabble in ALSA, instead relying on PA or JACK, I will present below another <code>.asoundrc</code> which captures the monitors(duplicates) of desired PulseAudio devices (sorry, no JACK config - I am not familiar with it yet).</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">pcm.steelseries_game {
    type pulse
    device &#34;alsa_output.usb-SteelSeries_SteelSeries_Arctis_5_00000000-00.analog-game.monitor&#34;
    hint.description &#34;PulseAudio Game Monitor&#34;
}

pcm.steelseries_chat {
    type pulse
    device &#34;alsa_output.usb-SteelSeries_SteelSeries_Arctis_5_00000000-00.analog-chat.monitor&#34;
    hint.description &#34;PulseAudio Chat Monitor&#34;
}
</code></pre><p>Again, without the <code>hint.description</code> tag, they won&rsquo;t show up in the <code>aplay</code>&rsquo;s listings.</p>
<h2 id="conclusions">Conclusions</h2>
<p>Having read this post you will be able to create your own ALSA configuration for simultaenous capture and playback for both ALSA and PulseAudio. This is not the end of my ALSA adventures, but the next time I will write about it will be from the device driver perspective, so we will be looking at some kernel topics, such as DMA and timers. I hope you will find this post useful and educating :) I also hope to be posting some more in the upcoming weeks, as currently I have some free time due to current world situation. So stay productive and stay safe.</p>
<p>As always, if you like what I&rsquo;m doing and you would like to see more of it - consider buying me a [coffee] &#x2615;
[coffee]: <a href="https://www.buymeacoffee.com/jduchniewicz">https://www.buymeacoffee.com/jduchniewicz</a>
[cpal]: <a href="https://docs.rs/cpal/0.12.1/cpal/index.html">https://docs.rs/cpal/0.12.1/cpal/index.html</a>
[here]: <a href="https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture#Configuration">https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture#Configuration</a>
[minimal configuration file]: <a href="https://ristovski.github.io/posts/master-alsa-config/">https://ristovski.github.io/posts/master-alsa-config/</a>
[anwser]: <a href="https://stackoverflow.com/a/44217925/7092926">https://stackoverflow.com/a/44217925/7092926</a></p>
]]></content>
        </item>
        
        <item>
            <title>GitHub Actions</title>
            <link>https://jduchniewicz.com/posts/2020/05/github-actions/</link>
            <pubDate>Fri, 08 May 2020 20:47:48 +0200</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2020/05/github-actions/</guid>
            <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This post will make you familiar with some basic features of GitHub Actions featuring code for cross-platform Continous Integration. This is my first post so any feedback is appreciated :)&lt;/p&gt;
&lt;h2 id=&#34;why&#34;&gt;Why?&lt;/h2&gt;
&lt;p&gt;Until a few years ago, managing continuous integration and deployment of a software product was quite sophisticated and required much toilsome work.
I do not claim it is easy now, but it is certainly much easier thanks to tools like GitHub Actions. While [PolyEngine] had pretty good CI and CD already running it was divided between Travis(Linux and macOS) and Appveyor(Windows). Thankfully GitHub Actions try to make developer&amp;rsquo;s life as easy as possible and allow for builds for all 3 platforms in one place. I decided to give it a go while doing our side project [PolyDock] which is a standalone plugin for managing windows in a Firefox/Chrome-like manner.&lt;/p&gt;</description>
            <content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>This post will make you familiar with some basic features of GitHub Actions featuring code for cross-platform Continous Integration. This is my first post so any feedback is appreciated :)</p>
<h2 id="why">Why?</h2>
<p>Until a few years ago, managing continuous integration and deployment of a software product was quite sophisticated and required much toilsome work.
I do not claim it is easy now, but it is certainly much easier thanks to tools like GitHub Actions. While [PolyEngine] had pretty good CI and CD already running it was divided between Travis(Linux and macOS) and Appveyor(Windows). Thankfully GitHub Actions try to make developer&rsquo;s life as easy as possible and allow for builds for all 3 platforms in one place. I decided to give it a go while doing our side project [PolyDock] which is a standalone plugin for managing windows in a Firefox/Chrome-like manner.</p>
<h2 id="the-basics">The basics</h2>
<p>The language in which it is written is YAML, which is a recursive acronym for &ldquo;YAML Ain&rsquo;t Markup Language&rdquo;, the language itself is quite punishing and required usage of spaces instead of tabs(no bias here at all). However, when editing it in GitHub IDE you get nice suggestions and autocompletion - it would still benefit much from interpreting it on-the-go. The painful truth you have to accept is that your commit count will bloat once you start configuring GH Actions. There is a tool([Act]) which allows for testing them offline, but only Linux builds are supported :/</p>
<p>This said, it is time to show some code:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># You start with the workflow name</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">CI</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># This workflow is triggered on pushes and PR&#39;s to the repository</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: [<span style="color:#ae81ff">push, pull_request]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># And you specify jobs it has to run</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ci</span>: <span style="color:#75715e"># in this case CI</span>
</span></span></code></pre></div><p>Every job is composed of steps, which specify what will happen sequentially when it is run - take this into account when writing your own workflows! You have to specify a name and the commands it should run. <strong>Something I struggled to find is - how to run given step conditionally.</strong> Well, nothing simpler! Just bash an <code>if</code> statement at the end of particular step and v&rsquo;oila - it triggers only on particular conditions.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>  <span style="color:#f92672">steps</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Install Dependencies (Linux)</span> <span style="color:#75715e"># notice that each step begins with &#39;-&#39; followed by a space</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">run</span>: <span style="color:#ae81ff">|</span> <span style="color:#75715e"># pipe operator allows you to chain commands in several lines</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ae81ff">sudo apt-get update</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ae81ff">sudo apt-get install -y -qq cmake</span> <span style="color:#75715e"># qq for limiting verbosity</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">if</span>: <span style="color:#ae81ff">matrix.os == &#39;ubuntu-latest&#39;</span> <span style="color:#75715e"># for now ignore the &#39;matrix&#39; part</span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Echo Something</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">run</span>: <span style="color:#ae81ff">echo &#34;Hey!&#34;</span>
</span></span></code></pre></div><p>Remember not to include new-lines between entries in jobs, otherwise GH Actions will complain about YAML issues and refuse to run your job - prepare a next commit&hellip;</p>
<h2 id="going-cross-platform">Going cross-platform</h2>
<p>Now for the <code>matrix</code> part:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">jobs</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ci</span>:
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">${{ matrix.os }}</span>
</span></span><span style="display:flex;"><span>   
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">strategy</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">matrix</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">os</span>: [<span style="color:#ae81ff">ubuntu-latest, macOS-latest, windows-latest]</span>
</span></span></code></pre></div><p>Matrix is the specified configuration you would like to run the job on. Apart from specifying the OS, you can also set desired package versions (but keep in mind that some packages may be not present in pre-built OS images), and customize settings for any of the operating systems of choice by <code>include</code> or <code>exclude</code> keywords. It is worth noting that if you are running several jobs in parallel(multiple OS compilation), if one fails, all will fail too. If you wish to run all the jobs till the end even if one fails specify <code>fail-fast: false</code> in the <code>strategy</code> settings.</p>
<h2 id="additional-commands">Additional commands</h2>
<p>If you wish to use external actions - no problem! Just specify a <code>uses</code> clause and add the path of the action you want to use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Install Qt</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">jurplel/install-qt-action@v2</span> <span style="color:#75715e"># specify the user and repository along with the version of this action</span>
</span></span></code></pre></div><p>If you want to run a series of commands and do not want to specify a directory each time (or directory structures vary between systems) - use <code>working-directory</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>   - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Setup CMake</span>
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        mkdir &#34;${{ runner.workspace }}/PolyDock/Build&#34; # runner.workspace is the variable of the current runner 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        cd &#34;${{ runner.workspace }}/PolyDock/Build&#34; 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        cmake ../PolyDock</span>
</span></span></code></pre></div><p>Probably the most used action is the <code>checkout</code> action which checks out your repository on the runner, basically performing a <code>git pull</code>. However be careful when you have submodules! It won&rsquo;t initialize them automatically, so you have to specify it by hand like so:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>   - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Get Sources</span>
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v2</span>
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">with</span>:
</span></span><span style="display:flex;"><span>       <span style="color:#f92672">submodules</span>: <span style="color:#e6db74">&#39;true&#39;</span>    
</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>While I covered some basic features, and some that I simply needed, your configuration will be probably much more complex. Thus, I recommend consulting the official docs (they present the basics pretty well, but obscure some details like <code>if</code> statements in steps) and/or this excellent [post series] by Edward Thomson, which dig deeper into this subject. I hope that now you have some knowledge about the amazing world of GitHub Actions and will automate your own repositories :)</p>
<p>On closing words, if you like what I&rsquo;m doing and you would like to see more of it - consider buying me a [coffee] &#x2615;
[coffee]: <a href="https://www.buymeacoffee.com/jduchniewicz">https://www.buymeacoffee.com/jduchniewicz</a>
[PolyEngine]: <a href="https://github.com/PolyEngineTeam/PolyEngine/">https://github.com/PolyEngineTeam/PolyEngine/</a>
[PolyDock]: <a href="https://github.com/PolyEngineTeam/PolyDock/">https://github.com/PolyEngineTeam/PolyDock/</a>
[Act]: <a href="https://github.com/nektos/act">https://github.com/nektos/act</a>
[post series]: <a href="https://www.edwardthomson.com/blog/github_actions_advent_calendar.html">https://www.edwardthomson.com/blog/github_actions_advent_calendar.html</a></p>
]]></content>
        </item>
        
        <item>
            <title>Welcome!</title>
            <link>https://jduchniewicz.com/posts/2020/04/welcome/</link>
            <pubDate>Thu, 30 Apr 2020 19:35:40 +0200</pubDate>
            
            <guid>https://jduchniewicz.com/posts/2020/04/welcome/</guid>
            <description>&lt;h2 id=&#34;opening-word&#34;&gt;Opening word&lt;/h2&gt;
&lt;p&gt;I always wanted to have my own personal place for sharing my both technical and geeky content with the general public. Well, here it is and I hope it will be of some use to you.
In the upcoming days I am mostly doing my thesis project and cannot publish it until it is done and defended&amp;hellip; However, I will post some other posts related to some side projects of my own and of course &lt;a href=&#34;https://github.com/PolyEngineTeam/PolyEngine/&#34;&gt;PolyEngine&lt;/a&gt;.&lt;/p&gt;</description>
            <content type="html"><![CDATA[<h2 id="opening-word">Opening word</h2>
<p>I always wanted to have my own personal place for sharing my both technical and geeky content with the general public. Well, here it is and I hope it will be of some use to you.
In the upcoming days I am mostly doing my thesis project and cannot publish it until it is done and defended&hellip; However, I will post some other posts related to some side projects of my own and of course <a href="https://github.com/PolyEngineTeam/PolyEngine/">PolyEngine</a>.</p>
]]></content>
        </item>
        
    </channel>
</rss>
