<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Robopenguins</title>
    <description>Project Archive</description>
    <link>/</link>
    <atom:link href="/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 19 May 2026 05:39:48 +0000</pubDate>
    <lastBuildDate>Tue, 19 May 2026 05:39:48 +0000</lastBuildDate>
    <generator>Jekyll v4.3.3</generator>
    
      <item>
        <title>Location Display Map with PCB Art</title>
        <description>&lt;p&gt;I used a free PCB sponsorship as an excuse to build the biggest board I’ve ever designed. I turned it into a living map of my family.&lt;/p&gt;

&lt;p&gt;To my great surprise, &lt;a href=&quot;https://www.pcbway.com/&quot;&gt;PCBWay&lt;/a&gt; reached out and offered to cover the manufacturing costs for a board in exchange for a mention on this hallowed blog. While I’ve avoided monetizing this blog in any way (&lt;a href=&quot;/server-side-site-analytics/&quot;&gt;including removing analytics&lt;/a&gt;), it turns out I’m not incorruptible when presented with an excuse to design a giant PCB. As you’ll probably be able to tell from the rest of the article, PCBWay had no involvement itself in the project or write up beyond agreeing to manufacture it.&lt;/p&gt;

&lt;p&gt;I like using constraints as inspiration, and I wanted to build something that took advantage of the PCB medium itself.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/real_map.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/real_map.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of the designs and source code for this project can be found at: &lt;a href=&quot;https://github.com/axlan/pcb-map&quot;&gt;https://github.com/axlan/pcb-map&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While I don’t think I rushed the project, I did try to move faster than usual. With a new baby in the house, project time could sometimes feel borrowed, either from my family or from my already limited sleep. Still, making things is important to me, and in its own way, this project became a form of self-care. In some places that tradeoff worked out well. In others, not so much. See the &lt;a href=&quot;#improvements&quot;&gt;Improvements&lt;/a&gt; section for the consequences of moving a little too quickly.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#previous-pcb-designs&quot;&gt;Previous PCB Designs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#brainstorming&quot;&gt;Brainstorming&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#high-level-design&quot;&gt;High Level Design&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#making-the-pcb&quot;&gt;Making the PCB&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#pcb-design&quot;&gt;PCB Design&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#pcb-manufacturing&quot;&gt;PCB Manufacturing&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#software&quot;&gt;Software&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#led-matrix-driver&quot;&gt;LED Matrix Driver&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#network-discover-provisioning-and-configuration&quot;&gt;Network Discover Provisioning and Configuration&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#simulator&quot;&gt;Simulator&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#python-controls&quot;&gt;Python Controls&lt;/a&gt;
        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#device-setup&quot;&gt;device-setup&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#control-server&quot;&gt;control-server&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#results&quot;&gt;Results&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#pcb-solar-light&quot;&gt;PCB Solar Light&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#full-application&quot;&gt;Full Application&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#improvements&quot;&gt;Improvements&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#hardware&quot;&gt;Hardware&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#software-1&quot;&gt;Software&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;previous-pcb-designs&quot;&gt;Previous PCB Designs&lt;/h1&gt;

&lt;p&gt;As a kid doing hacky electronics projects, having a custom PCB made felt like an unimaginable luxury. It was exciting when I got to college and was able to get a discount on manufacturing a board for my final project (&lt;a href=&quot;/persistence-of-vision/&quot;&gt;a persistence of vision display&lt;/a&gt;). Even then, I still ended up making the second of the two boards the project needed myself using toner transfer and ferric acid copper etching.&lt;/p&gt;

&lt;p&gt;More recently, I made a &lt;a href=&quot;/custom-pcb/&quot;&gt;little game handheld&lt;/a&gt; that could play snake or track the state of a Magic the Gathering game. Here, I had fun adding some decorative flourishes and got to practicing using a modern KiCad version.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2021/life_tracker/back.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2021/life_tracker/back_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;brainstorming&quot;&gt;Brainstorming&lt;/h1&gt;

&lt;p&gt;While I knew I wanted the PCB itself to be the centerpiece, I went through a long list of ideas before settling on one.&lt;/p&gt;

&lt;p&gt;I spent some time specifically looking at other PCB art projects. There’s a lot of &lt;a href=&quot;https://hackaday.com/tag/pcb-art/&quot;&gt;beautiful&lt;/a&gt; &lt;a href=&quot;https://hackaday.com/tag/badge/&quot;&gt;stuff&lt;/a&gt; &lt;a href=&quot;https://boldport.com/shop/dreamer&quot;&gt;out&lt;/a&gt; &lt;a href=&quot;https://hackaday.com/2016/01/28/beautiful-and-bizarre-boards/&quot;&gt;there&lt;/a&gt;. One site I found particularly interesting was &lt;a href=&quot;https://boldport.com/&quot;&gt;Boldport&lt;/a&gt;. In particular,  &lt;a href=&quot;https://boldport.com/blog/2013/09/the-lifegame.html&quot;&gt;https://boldport.com/blog/2013/09/the-lifegame.html&lt;/a&gt; reminded of my &lt;a href=&quot;/eye-chart-hidden-message/&quot;&gt;recent wedding project&lt;/a&gt;. They actually have a whole design tool for PCB art &lt;a href=&quot;https://github.com/boldport/pcbmode&quot;&gt;https://github.com/boldport/pcbmode&lt;/a&gt; which I looked into. Unfortunately, it seems like the site and the tool haven’t really been active for a few years.&lt;/p&gt;

&lt;p&gt;Another PCB art project that inspired me was &lt;a href=&quot;https://chaijiaxun.com/blog/pcb-metro-map-build-log/&quot;&gt;https://chaijiaxun.com/blog/pcb-metro-map-build-log/&lt;/a&gt;. The author created meticulous transit maps as PCBs with light animations.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/95dd423edd5fa2da682620668c5b896e_original.webp&quot; /&gt;&lt;/p&gt;

&lt;p&gt;These two projects both dealt with illuminating PCB’s from the back. I used them as points of reference as I settled on my own design. The creator of the &lt;a href=&quot;https://chaijiaxun.com/blog/pcb-metro-map-build-log/&quot;&gt;PCB Metro Map&lt;/a&gt; Chai Jia Xun in particular spent a lot of effort on perfecting his approach. He ended up shining light through the via holes in the board, coloring them with paper, and using a printed mask to avoid light leaking between holes.&lt;/p&gt;

&lt;p&gt;With my prior art research done, I focused on coming up with my own design.&lt;/p&gt;

&lt;p&gt;My default instinct for an interesting display project is always to turn it into a clock. I explored designs that combined static PCB artwork with dynamic elements like LEDs, LCDs, e-ink panels, and seven-segment displays. I considered building a traditional clock, a calendar, and even an &lt;a href=&quot;https://en.wikipedia.org/wiki/Orrery&quot;&gt;orrery&lt;/a&gt;. But the more I explored those ideas, the more conventional they felt. I wanted something stranger and more personal.&lt;/p&gt;

&lt;p&gt;In the end, the most interesting direction was a display that reflected the daily rhythms of my family in real time.&lt;/p&gt;

&lt;p&gt;Of course, this takes inspiration from the “Weasley family clock” from Harry potter. Many people have made beautiful projects recreating the clock, and a few that incorporate the electronics to make it function like in the books as well. To put my own spin on it, I decided to combine the idea with the &lt;a href=&quot;https://chaijiaxun.com/blog/pcb-metro-map-build-log/&quot;&gt;PCB Metro Map&lt;/a&gt; to make the display a map.&lt;/p&gt;

&lt;h1 id=&quot;high-level-design&quot;&gt;High Level Design&lt;/h1&gt;

&lt;p&gt;First, I had to settle a few basic layout questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What geographic area should the map cover?&lt;/li&gt;
  &lt;li&gt;Should the map be contiguous, or split into multiple regions?&lt;/li&gt;
  &lt;li&gt;Should it include zoomed-in sections?&lt;/li&gt;
  &lt;li&gt;How would I indicate which family member was which? Would I need RGB LEDs to create distinct colors?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also considered an approach where a row of circles along the bottom of the board would call out points of interest like home or school, with lines connecting them back to their locations on the map.&lt;/p&gt;

&lt;p&gt;There was also the question of how to light the board. I could either place LEDs on top of the PCB or mount them underneath it. LEDs mounted below the board would need some way for the light to shine through. Either holes through the PCB or regions without copper. The &lt;a href=&quot;https://chaijiaxun.com/blog/pcb-metro-map-build-log/&quot;&gt;PCB Metro Map project&lt;/a&gt; meticulously tested the lighting and tempted me to take one of the more complicated approaches. Chai Jia Xun ended up shining light through via holes in the PCB, coloring them with paper, and using a printed mask to prevent light from leaking between holes.&lt;/p&gt;

&lt;p&gt;As I explored lighting options, I also started thinking about the assembly process. I’ve built several projects that required soldering dozens of RGB LEDs (like the &lt;a href=&quot;/icosahedron-travel-globe/&quot;&gt;Icosahedron Globe&lt;/a&gt; and the &lt;a href=&quot;/wreath-pixel-display/&quot;&gt;Pixel Wreath&lt;/a&gt;) and it can be both tedious and finicky. Over time, I’ve learned that starting with the right off-the-shelf LED hardware can save an enormous amount of effort.&lt;/p&gt;

&lt;p&gt;Since the goal was ultimately to illuminate points on a map, what I really needed was a dense LED grid. It turns out there are plenty of inexpensive RGB LED matrix panels available, and I found 64x32 panels selling for around $30. That was dramatically cheaper (and far less work) than populating the board with individual RGB LEDs.&lt;/p&gt;

&lt;p&gt;Once I committed to using an LED matrix, the rest of the design started to come together. I decided to make the largest PCB I could reasonably pair with a 64x32 panel. I included the surrounding hills and water to create a more balanced, square composition, while centering the LED panel on the areas we actually travel through.&lt;/p&gt;

&lt;p&gt;After ordering a panel, I found that it looked fine shining through a test PCB without copper or solder mask, which simplified the design considerably.&lt;/p&gt;

&lt;p&gt;As usual, I ended up using an ESP32 development board to drive the display.&lt;/p&gt;

&lt;h1 id=&quot;making-the-pcb&quot;&gt;Making the PCB&lt;/h1&gt;

&lt;h2 id=&quot;pcb-design&quot;&gt;PCB Design&lt;/h2&gt;

&lt;p&gt;All the design files can be found at &lt;a href=&quot;https://github.com/axlan/pcb-map/tree/master/design&quot;&gt;https://github.com/axlan/pcb-map/tree/master/design&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I usually try to make my projects as automated and repeatable as possible (often to a fault). I’ll spend far more time building tooling and infrastructure than it would take to do a one-off task manually. For the map artwork, though, I gave myself permission to just wing it and focus on getting the design finished as directly as possible.&lt;/p&gt;

&lt;p&gt;I initially considered using the &lt;a href=&quot;https://github.com/boldport/pcbmode&quot;&gt;Boldport PCBmodE tool&lt;/a&gt;, but it appeared to be unmaintained and seemed like it would come with a steep learning curve. Instead, I decided to try the image converter now built into KiCad.&lt;/p&gt;

&lt;p&gt;Since the KiCad converter only works with bitmap images (JPGs, PNGs, and similar formats), I didn’t need to worry about building everything as vector artwork.&lt;/p&gt;

&lt;p&gt;I also explored more abstract map styles, including this design from &lt;a href=&quot;https://archiespress.com/collections/city-map-prints-minimalist-neighborhood-map-art-archies-press/products/bay-area-map&quot;&gt;Archie’s Press&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://archiespress.com/collections/city-map-prints-minimalist-neighborhood-map-art-archies-press/products/bay-area-map&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/BayArea_1024x1024@2x.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end, though, I decided to stick with a normal geographic map.&lt;/p&gt;

&lt;p&gt;I was surprised by how difficult it was to find a good source for the map imagery. If I had wanted to be truly meticulous, there are probably mapping APIs that expose the underlying geographic features directly so you can render everything exactly how you want. Instead, I mainly needed an online map tool where labels (road names, points of interest, etc.) could be disabled cleanly.&lt;/p&gt;

&lt;p&gt;Eventually, I found &lt;a href=&quot;https://snazzymaps.com&quot;&gt;Snazzy Maps&lt;/a&gt;, which was almost exactly what I was looking for. It provides a JSON-based styling interface with fairly fine-grained control over map appearance. I started from the existing &lt;a href=&quot;https://snazzymaps.com/style/72543/assassins-creed-iv&quot;&gt;Assassin’s Creed IV style&lt;/a&gt; and disabled railroads and local streets.&lt;/p&gt;

&lt;p&gt;The site includes an export button, but it only supports images up to 1000x1000 pixels. Instead, I rendered the map at high resolution and captured screenshots manually.&lt;/p&gt;

&lt;p&gt;Next I had to decide what map features I wanted to have on which PCB layers.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/0_NiplN4TgWC6sJxPz.webp&quot; /&gt;&lt;/p&gt;

&lt;p&gt;PCBs normally have these layers on both the front and back of the board, though additional copper layers can also be sandwiched internally. Since I planned to shine light through the PCB, I realized I could also use the back-side layers to block or dim light without affecting the visible front surface. Vias (the plated holes that connect copper layers together) could even be used to channel light directly through the board.&lt;/p&gt;

&lt;p&gt;In the end, I decided to keep things simple:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Solder mask for water&lt;/li&gt;
  &lt;li&gt;Exposed copper for streets&lt;/li&gt;
  &lt;li&gt;Bare PCB substrate for land&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make the board translucent, I removed the copper and solder mask from the entire back side of the PCB. Once I started adding electronics, though, I limited this treatment to the land areas so that I could still place conventional components in the “water” regions.&lt;/p&gt;

&lt;p&gt;At that point, I just needed to generate images for each PCB layer I wanted to import into KiCad. Here was the process I ended up using:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Using &lt;a href=&quot;https://snazzymaps.com&quot;&gt;Snazzy Maps&lt;/a&gt;, I captured a screenshot of the region I wanted to use for the map.&lt;/li&gt;
  &lt;li&gt;Since I had decided on a final board size of 240x320 mm, I cropped the image to match the correct aspect ratio.&lt;/li&gt;
  &lt;li&gt;I created a reference layer with a 160x320 mm rectangle to verify that the LED matrix panel would fully cover the parts of the map I wanted illuminated.&lt;/li&gt;
  &lt;li&gt;Using &lt;a href=&quot;https://www.gimp.org/&quot;&gt;GIMP&lt;/a&gt;, I used the “select by color” tool to separate the image into independent layers for water, land+roads, and roads. I made each layer a solid opaque color.&lt;/li&gt;
  &lt;li&gt;The road layer ended up looking heavily pixelated and didn’t import cleanly into the KiCad image converter. To fix this, I copied the roads image into &lt;a href=&quot;https://inkscape.org/&quot;&gt;Inkscape&lt;/a&gt; and used the “trace bitmap” feature to generate a smoothed vector version of the roads. I then re-exported this at a higher resolution and brought it back into GIMP to create cleaner road geometry.&lt;/li&gt;
  &lt;li&gt;I exported PNG images for both the land+roads layer and the roads layer. I also created a horizontally flipped version of the land+roads image for use on the back side of the PCB.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Using the KiCad image converter, I imported the PNGs into the PCB design at a final scale of 240x320 mm:&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;The roads became a top-side copper layer.&lt;/li&gt;
      &lt;li&gt;The land+roads image became a top-side solder mask layer.&lt;/li&gt;
      &lt;li&gt;The flipped land+roads image became a bottom-side solder mask layer.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At that point, I had a PCB file containing the complete map artwork.&lt;/p&gt;

&lt;p&gt;Separately, I created another KiCad project for the actual electronics: the ESP32 development board, LED matrix interface, and power connectors. After verifying the footprints and laying out the PCB connections, I copied the completed electronics layout into the map PCB project.&lt;/p&gt;

&lt;p&gt;At one point I considered trying to keep the board single-sided, so I intentionally selected ESP32 GPIO pins that minimized routing complexity and avoided needing additional copper layers.&lt;/p&gt;

&lt;p&gt;When I finally ran the design rule checker (DRC), I discovered a few clearance violations near the board edges, so I added roughly half a millimeter of additional margin around the design. It also had issues with the single sided board, so I left it two sided.&lt;/p&gt;

&lt;p&gt;One feature I especially appreciated during this process was KiCad’s 3D PCB viewer, which made it easy to preview how the finished board would actually look before sending it off for manufacturing.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/map_board_preview.png&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;pcb-manufacturing&quot;&gt;PCB Manufacturing&lt;/h2&gt;

&lt;p&gt;I was curious how &lt;a href=&quot;https://www.pcbway.com/&quot;&gt;PCBWay&lt;/a&gt; would react to a giant decorative PCB, so I was pretty eager to get the design into their system and see what happened.&lt;/p&gt;

&lt;p&gt;Their upload and ordering interface was straightforward enough. As someone with hobbyist PCB experience I found the process fairly painless. While exploring the manufacturing options, I was briefly tempted by the “hard gold” surface finish. Since my design intentionally exposed a large amount of copper, this would have effectively plated huge portions of the board in gold. Unfortunately, a 30-micron gold finish increased the estimated price from roughly $120 to $572. I also suspected the standard silver finish would probably look better and be less likely to be rejected, so I stuck with that.&lt;/p&gt;

&lt;p&gt;One feature I especially appreciated was the ability to preview the board after uploading the design files. It made it easy to sanity-check that the solder mask color and surface finish matched the aesthetic I had in mind.&lt;/p&gt;

&lt;p&gt;Once the board was submitted, I had to wait for the design review process. I was curious how this would go, and sure enough, the design was flagged for confirmation:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi,&lt;/p&gt;

  &lt;p&gt;Thanks for your inquiry, here is a question for project No.W1047802AS4C1_map_board.zip&lt;/p&gt;

  &lt;p&gt;Pls find the attached pic and confirm whether the design is normal or not?&lt;/p&gt;

  &lt;p&gt;Your timely response would be greatly appreciated!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The attached image was the entire copper layer of the board.&lt;/p&gt;

&lt;p&gt;I replied:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is the intended layout for the top copper layer. The large section is there for appearances only to make the board look like a metal map.&lt;/p&gt;

  &lt;p&gt;Thanks for double checking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;which got the reply:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Thanks for your reply!&lt;/p&gt;

  &lt;p&gt;W1047802AS4C1_map_board has been approved now, the PCB price is $126.17, with an estimated lead time of 3–4 days, pls kindly login to check the details and proceed to checkout if everything is in order. :D&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Honestly, that felt like the right response. A board that is mostly decorative and only partially functional seems worth double-checking before fabrication, and it was easy enough to clarify the intent. I am curious what the exchange would have looked like if I hadn’t cleaned up the design rule check (DRC) errors before submitting it.&lt;/p&gt;

&lt;p&gt;From there, everything went smoothly. PCBWay covered the manufacturing and shipping costs, though I still had to deal with import tariffs. In practice, that just meant FedEx sent me an invoice after delivery for a 31% tariff, plus a $15 processing fee for handling the import payment on my behalf.&lt;/p&gt;

&lt;h1 id=&quot;software&quot;&gt;Software&lt;/h1&gt;

&lt;p&gt;From the start, I knew I wanted to keep the panel firmware as simple and generic as possible. Ideally, I could reuse it for other display projects in the future. The device would receive commands over MQTT to drive all dynamic behavior.&lt;/p&gt;

&lt;p&gt;This also meant I would need to write a separate host-side application to run on a PC, responsible for querying family locations and translating that data into commands sent to the device.&lt;/p&gt;

&lt;h2 id=&quot;led-matrix-driver&quot;&gt;LED Matrix Driver&lt;/h2&gt;

&lt;p&gt;I bought the LED matrix panel with the hope that controlling it wouldn’t be too much of a pain. From what I can tell, HUB75 is an informal standard that many LED panels implement &lt;a href=&quot;https://learn.lushaylabs.com/led-panel-hub75/&quot;&gt;https://learn.lushaylabs.com/led-panel-hub75/&lt;/a&gt;. Since it’s informal, there are many small variations that need to be validated when buying a new model.&lt;/p&gt;

&lt;p&gt;The matrix display that this project was tested with is the:
&lt;a href=&quot;https://www.amazon.com/dp/B0CLV5MHPX&quot;&gt;Waveshare RGB Full-Color LED Matrix Panel, 5mm Pitch, 64x32 Pixels&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was labeled as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;P5(2121)-3264-16S-M5&lt;/code&gt; (32x64 1/16 scan) and used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RUC7258D&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SM16208SJ&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MW245BC&lt;/code&gt; control chips.&lt;/p&gt;

&lt;p&gt;Like most embedded projects, finding the “best” library to use is a bit of a pain. It seems many owe their ancestry to the Adafruit graphics library, which has many descendants targeting different platforms and display technologies. After some research, I decided that the &lt;a href=&quot;https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA&quot;&gt;https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA&lt;/a&gt; library seemed to be the most capable and compatible option for the ESP32.&lt;/p&gt;

&lt;p&gt;I wired up the panel directly to an ESP32 and tried the example script. The display sort of worked, but everything was slightly glitchy or shifted. Reading the control library README, I tried changing the clock phase setting, and just like that the panel was working correctly.&lt;/p&gt;

&lt;p&gt;I did a bit more experimenting and eventually found other display artifacts, but these went away when I switched from jumper cables to my custom PCB. As it turns out, they’re not kidding when they say these boards are sensitive to needing a beefy power supply and short cables. The signal integrity issues might also be partly due to the panel expecting 5V signals while the ESP32 outputs 3.3V.&lt;/p&gt;

&lt;p&gt;When my custom PCB arrived, I was delighted that the connection between the ESP32 and the LED panel worked without issue. It’s not that the layout is particularly complicated, but there’s a lot of room for something to get flipped left/right or top/bottom.&lt;/p&gt;

&lt;p&gt;As I developed my application, I found the &lt;a href=&quot;https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA&quot;&gt;panel library&lt;/a&gt; mostly worked as expected and was pretty solid. When I started having issues with flickering, I enabled the library’s built-in double buffering, which fixed the issue.&lt;/p&gt;

&lt;p&gt;With the driver done, I needed to implement the display control interface. I didn’t approach this particularly systematically and mostly just added features as needed. I ended up with two basic ways to draw things on the display.&lt;/p&gt;

&lt;p&gt;First, I added an interface for drawing a background image. This is simply sending a bitmap of pixel colors for the whole panel to be statically displayed when nothing else overwrites them. When I started testing this, I realized that the MQTT library I was using had a 256-byte message limit. Since I didn’t want to rely on sending 4 KB (64x32x2 bytes, where 2 bytes per pixel is the RGB565 color scheme) messages, I set up the interface to update the background row by row (128-byte payloads).&lt;/p&gt;

&lt;p&gt;I also wanted to support drawing elements that could be updated independently and could have some dynamic behaviors (e.g., pulsing). I created a concept of sprites indexed by a name identifier. The only sprite type I implemented was a pixel sprite that could oscillate between two colors. This also enabled the panel to periodically cycle between sprites sharing the same position, to handle the case where multiple people were at the same address and I wanted both to appear on the map. These sprites could then be updated by future commands referencing their name. There are other sprite types I could have added (such as driving routes) but I decided not to add complexity to the firmware until it was actually needed.&lt;/p&gt;

&lt;h2 id=&quot;network-discover-provisioning-and-configuration&quot;&gt;Network Discover Provisioning and Configuration&lt;/h2&gt;

&lt;p&gt;One of the first things I focused on when building out the firmware was making the network configuration completely reliable. In previous projects, I’d taken a variety of approaches to handling Wi-Fi credentials and MQTT configuration, but this time I wanted something more polished and dependable. I put extra effort into making the setup process stable and user-friendly so that, if I ever wanted to duplicate the project or revisit it in the future, getting it running again would be straightforward.&lt;/p&gt;

&lt;p&gt;Setting or updating Wi-Fi credentials requires a side channel to configure the device before it has network access. For the first time, I read through the &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisioning/index.html&quot;&gt;Espressif provisioning documentation&lt;/a&gt;. The &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisioning/provisioning.html&quot;&gt;Espressif unified provisioning libraries&lt;/a&gt; provide a robust way to provision a device over Bluetooth or an ad-hoc Wi-Fi access point. The downside is that the library is fairly complex and requires the host machine to either support Bluetooth or manually connect to the ad-hoc network.&lt;/p&gt;

&lt;p&gt;There was also a library called &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/network/esp_smartconfig.html&quot;&gt;SmartConfig&lt;/a&gt;, which uses clever techniques to decode network credentials from the length of encrypted packets by monitoring Wi-Fi traffic. Unfortunately, the documentation suggested this approach may not work consistently across all Wi-Fi drivers.&lt;/p&gt;

&lt;p&gt;I ultimately fell back on the &lt;a href=&quot;https://github.com/tzapu/WiFiManager&quot;&gt;WiFiManager library&lt;/a&gt;, which I’ve used in previous projects. It still requires manually connecting to an ad-hoc Wi-Fi network, but it creates a captive portal that makes entering credentials straightforward.&lt;/p&gt;

&lt;p&gt;To streamline finding the device on the network, I spent some time better understanding how mDNS works. On my Linux system, at least, it let me use the device’s local hostname directly instead of tracking down its assigned IP address.&lt;/p&gt;

&lt;p&gt;Once the device is connected and configured, all communication happens over MQTT. This gives me flexibility in choosing between a local or remote broker, handling authentication, and avoiding a lot of lower-level protocol edge cases. Even after the device was online, though, I still needed a way to configure the MQTT host and authentication settings.&lt;/p&gt;

&lt;p&gt;I ended up creating a simple UDP command packet format to configure all the parameters used for MQTT authentication. I spent a fair amount of time working through MQTT TLS certificate management before ultimately disabling certificate validation.&lt;/p&gt;

&lt;p&gt;Supporting arbitrary brokers securely would have also required transmitting the root certificate through this configuration interface. The added complexity of managing certificates didn’t feel worth the relatively small security benefit of guarding against potential man-in-the-middle attacks for a project at this scale. For a commercial device the calculus would be different. I’d likely target a specific broker, embed the root certificate directly in the firmware, and skip this level of configurability entirely.&lt;/p&gt;

&lt;p&gt;I’ll go into the details of how I tried to automate device setup in the Python controls &lt;a href=&quot;#find-devices&quot;&gt;find-devices&lt;/a&gt; section.&lt;/p&gt;

&lt;h2 id=&quot;simulator&quot;&gt;Simulator&lt;/h2&gt;

&lt;p&gt;See &lt;a href=&quot;https://github.com/axlan/pcb-map/tree/master/firmware/simulation&quot;&gt;https://github.com/axlan/pcb-map/tree/master/firmware/simulation&lt;/a&gt; for the simulator source code.&lt;/p&gt;

&lt;p&gt;While updating the firmware and testing on the device isn’t that painful, I wanted to make development as quick as possible. Since the interface to the display is so basic, it was relatively easy to create a small CMake application to simulate it locally.&lt;/p&gt;

&lt;p&gt;I primarily wanted to test the MQTT handling and display logic, so I included the relevant source files from the firmware in my simulator build. To do this I created dummy header files that mocked out any Arduino or driver calls to allow them to compile. I used the SFML graphics library to render my simulated panel overlaid on a transparent map image.&lt;/p&gt;

&lt;iframe width=&quot;1000&quot; height=&quot;515&quot; src=&quot;https://www.youtube.com/embed/Oj52eqXgJHk&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;python-controls&quot;&gt;Python Controls&lt;/h2&gt;

&lt;p&gt;I made two Python tools for interacting with the board. I continue to mostly design Python projects with uv in mind, and here I really tried to get good command-line ergonomics. I used the Typer library for the first time to handle parsing command-line arguments. It worked out well once I learned enough to cover my use cases. One feature I was happy to find was that you can map command-line arguments to environment variables, which makes it easy to set credentials without typing them in each time and without any extra code.&lt;/p&gt;

&lt;h3 id=&quot;device-setup&quot;&gt;device-setup&lt;/h3&gt;

&lt;p&gt;The goal of this tool was to eliminate the tedious process of setting up an IoT device. Things like not knowing whether it’s connected to Wi-Fi, or having to log into the router to find it on the network. The states it detects and configures are:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/mdns_wifi_state_machine.svg&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;control-server&quot;&gt;control-server&lt;/h3&gt;

&lt;p&gt;Once the device is fully configured, further operation is controlled over MQTT. This tool handles that control for various tests and applications.&lt;/p&gt;

&lt;p&gt;The main application is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;display-shared-locations&lt;/code&gt;. It loads the user’s and their friends’ positions to draw on the map, and checks calendar events for positions to draw routes to.&lt;/p&gt;

&lt;p&gt;For testing purposes I also created a way to specify changing user positions and routes as a JSON file.&lt;/p&gt;

&lt;p&gt;One issue I hit while developing this interface is that there’s no great way to access your location data over an API from Google. Google tracks your position and lets you share it with friends through Google Maps, but there’s no official way to access this data outside the app or website. There is a Python library that handles parsing the data, but it requires session cookies, which can be fragile for a long-running server.&lt;/p&gt;

&lt;p&gt;I could use a side channel to report positions, but I wanted to avoid requiring my family to run any special software on their phones. Both for simplicity and for privacy.&lt;/p&gt;

&lt;p&gt;Position data could also come from other services. If my kids get some sort of non-phone location beacon (like an AirTag), I could potentially integrate that as well, since it would just be an update to the Python server.&lt;/p&gt;

&lt;p&gt;Drawing the routes was a bit more involved. I initially used an API from OpenRouteService since its free tier would have covered my usage, but it returned incorrect positions for the test addresses I tried. I switched to the Google Maps routing API, which requires a Google Cloud account but should also be effectively free.&lt;/p&gt;

&lt;p&gt;Converting user locations to panel coordinates was a fairly straightforward mapping from latitude/longitude to the panel’s X/Y. Drawing routes was more complex: I receive the route as a series of line segments and need to map these onto the grid. The algorithm I used could almost certainly be improved, but I got something quick and dirty working.&lt;/p&gt;

&lt;p&gt;I decided to add route drawing later in the process. Rather than adding a new sprite type for routes, I found it easier to draw them as part of the background image and manage them from the server side.&lt;/p&gt;

&lt;p&gt;Once I had everything working, I spent some time hardening the application so it would behave more reliably as a long-running server process. I added MQTT status reporting so I could monitor whether the hacky cookie sharing mechanism needed to be refreshed or if some other unexpected failure had occurred.&lt;/p&gt;

&lt;p&gt;To run it on my server, I Dockerized the application and wrote scripts to update the authentication credentials as needed. I also set up &lt;a href=&quot;https://github.com/louislam/uptime-kuma&quot;&gt;Uptime Kuma&lt;/a&gt; to monitor the service and alert me if anything failed.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/kuma.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/kuma.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;results&quot;&gt;Results&lt;/h1&gt;

&lt;p&gt;I ended up with two complementary projects: the PCB, which is beautiful on its own, and the position display server and firmware for the LED matrix. Using a PCB for the static map is a great aesthetic touch, but the whole thing would be completely functional with a printed paper map instead.&lt;/p&gt;

&lt;h2 id=&quot;pcb-solar-light&quot;&gt;PCB Solar Light&lt;/h2&gt;

&lt;p&gt;Since the minimum order for a custom PCB was 5, I had four extra boards to work with. They seemed like they’d make nice gifts as-is, but I still wanted to give them some basic functionality. Since I wasn’t expecting people to run a server to display locations, I came up with the idea of fitting the guts of a solar garden light onto a board so it would glow at night.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/solar_lamp.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/solar_lamp.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/solar_map_front.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/solar_map_front.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/solar_map_back.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/solar_map_back.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/solar_map_dark.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/solar_map_dark.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;full-application&quot;&gt;Full Application&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/real_map.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/real_map.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/assembled_back.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/assembled_back.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This demo shows a simulated scenario where Joe is driving to Sue’s house. Once he arrives, the map alternates between them:&lt;/p&gt;

&lt;iframe width=&quot;1000&quot; height=&quot;515&quot; src=&quot;https://www.youtube.com/embed/QWq_C7uRPfs&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Here’s some samples of uploading background images to the display:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/compass.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/compass.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/oakland.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/oakland.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/pichu.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/map_pcb/pichu.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end I got everything I wanted working, but in the next section I’ll go into some of the many improvements I could make.&lt;/p&gt;

&lt;p&gt;All designs and code for this project can be found at: &lt;a href=&quot;https://github.com/axlan/pcb-map&quot;&gt;https://github.com/axlan/pcb-map&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;improvements&quot;&gt;Improvements&lt;/h1&gt;

&lt;h2 id=&quot;hardware&quot;&gt;Hardware&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Choose a more common ESP32/ESP8266 footprint&lt;/strong&gt; - The particular board I had on hand was one I got from AliExpress years ago. Its pinout wasn’t very standardized. Since I’m using it on a printed board, it probably would have been worth targeting a better-documented dev board footprint.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Select a thinner PCB&lt;/strong&gt; - One of the PCBWay options I left at the default was board thickness. The lights are visible through the PCB, but they’re a little dimmer in daylight than I’d like. I think this would have been simply addressed by ordering a thinner board.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Avoid blocking the ESP32 antenna&lt;/strong&gt; - I laid out the connectors without much thought. In hindsight, I wouldn’t have placed the ESP32 on the back behind a solid copper layer. It still works, but the Wi-Fi signal strength is much worse than it could be, and it probably wouldn’t work at all if the device weren’t fairly close to the router.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Avoid blocking the ESP32 USB&lt;/strong&gt; - A similar mistake was placing the ESP32 too close to the LED matrix HUB75 connector. The USB and the display can’t be connected simultaneously since they block each other. I originally didn’t see this as a problem since I was planning on using a separate power connector, but once I was using the board I realized I could have used this port with data-only cables or high-power USB-C supplies.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Add more silkscreen info&lt;/strong&gt; - I didn’t include any useful silkscreen on the board. I should have at least labeled the orientation of each connector to make plugging them in easier.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;software-1&quot;&gt;Software&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Support special location indicators&lt;/strong&gt; - This was an idea for better indicating when users are at known places like home or school. Originally I had thought I could shine LEDs under the “water” sections of the map with arrows pointing to their locations. Since the copper makes those sections opaque, I could instead add LEDs to the top of the board, or integrate them into the legend somehow.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Add Event Indicators&lt;/strong&gt; - In addition to showing the route to events, I could have some indicator that an event start time is coming.&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate>
        <link>/pcb-map/</link>
        <guid isPermaLink="true">/pcb-map/</guid>
        
        
        <category>Software</category>
        
        <category>Hardware</category>
        
        <category>Electronic Art</category>
        
        <category>IoT</category>
        
      </item>
    
      <item>
        <title>Making a Turtle Bot 2: Making a Dash Robot into a Turtle</title>
        <description>&lt;p&gt;Since a capable Dash robot fell into my lap, I could skip ahead and build a full child friendly turtle bot game. I went for simplicity and built the control logic and GUI in Python.&lt;/p&gt;

&lt;p&gt;This completes the game idea I described in:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/making-a-turtle-bot-pt1/&quot;&gt;Making a Turtle Bot 1: Hacking a Mint Cleaner&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and uses the interface I built in:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/reverse-dash/&quot;&gt;Reverse Engineering the Dash Learning Robot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s a basic demo of the bot along with part of the GUI window:&lt;/p&gt;
&lt;iframe width=&quot;1000&quot; height=&quot;515&quot; src=&quot;https://www.youtube.com/embed/gdieOVodkvw&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;hr /&gt;

&lt;p&gt;and a longer demo of using cards to plan out a path to the goal:&lt;/p&gt;
&lt;iframe width=&quot;1000&quot; height=&quot;515&quot; src=&quot;https://www.youtube.com/embed/4csbya6z6S4&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;hr /&gt;

&lt;p&gt;The full source can be found in: &lt;a href=&quot;https://github.com/axlan/dash-turtle-game&quot;&gt;https://github.com/axlan/dash-turtle-game&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;turning-the-dash-into-a-turtle&quot;&gt;Turning the Dash into a Turtle&lt;/h1&gt;

&lt;p&gt;My first goal was to use the interface I made in &lt;a href=&quot;https://github.com/axlan/WonderPy&quot;&gt;https://github.com/axlan/WonderPy&lt;/a&gt; to send commands and get the sensor data I needed to implement the game.&lt;/p&gt;

&lt;p&gt;Using the interface for real, I quickly found tons of bugs. Most were simple typos, but quite a few were also around how I wrapped the asyncio BLE library so it could be used from a traditional threaded application. There’s lots of nuance especially around graceful shutdown and error handling that made this a real pain to get right. I understand why many libraries I’ve seen create separate implementations for these use cases.&lt;/p&gt;

&lt;p&gt;The bulk of this initial work involved getting the robot to follow the game grid. Getting the bot to turn in place and move forward was extremely simple. The difficulty was aligning these movements to the game board and keeping it aligned.&lt;/p&gt;

&lt;p&gt;After experimenting with the Dash robot, I decided that inertial positioning (the robot’s estimate based on accelerometer, gyro, and wheel sensors) was good enough for this game. I had successfully tested using &lt;a href=&quot;https://wiki.ros.org/apriltag_ros&quot;&gt;AprilTags&lt;/a&gt; to generate absolute position from markers built into the game board. However, this would have required a camera to monitor the game space, which seemed cumbersome for something I wanted to set up quickly. I also considered using light sensors to detect lines or features under the robot, but this was no longer an option since I was using a stock robot without these sensors. While drift in the inertial measurements is easy to notice, it rarely was enough for the bot to be off by enough to be off the grid in the dozen or so steps needed to solve the maze.&lt;/p&gt;

&lt;p&gt;One weird thing I found in testing was that the Dash robot would occasionally turn on a television if pointed directly at it. At first it was like a poltergeist. I believe this relates to its IR beacon feature, where robots identify others nearby by decoding data sent from IR transceivers. I had also considered using this for absolute positioning, but that would have required significant reverse engineering effort and seemed unnecessary.&lt;/p&gt;

&lt;p&gt;The Dash robot’s interface reports its current pose and includes a “pose” command. This lets you specify x and y positions in centimeters along with an orientation it should move to. This meant all I needed to do was map the orientation and x, y positions from the robot’s coordinate system to the game board.&lt;/p&gt;

&lt;p&gt;Since I started planning this turtle game, I’d been thinking about what would make a good game board. I looked into buying a giant checkerboard or a picnic table cover. In the end, the most cost effective items I found were puzzle piece foam mats meant for gyms or children’s playrooms.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/dash/mat.webp&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Since I wasn’t planning on detecting the mat edges for positioning, I got an alphabet mat to make it easier to map the mat tiles to the virtual game board.&lt;/p&gt;

&lt;p&gt;The Dash robot’s coordinate system is described in &lt;a href=&quot;https://github.com/playi/WonderPy/blob/master/doc/WonderPy.md#coordinate-systems&quot;&gt;https://github.com/playi/WonderPy/blob/master/doc/WonderPy.md#coordinate-systems&lt;/a&gt;. Each time the robot boots, it initializes its pose to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&quot;x&quot;=0, &quot;y&quot;=0, &quot;degrees&quot;=0}&lt;/code&gt;. It also has additional commands to reset its coordinates, but I didn’t reverse engineer that part of the command interface since I could compensate on the host side. To simplify the controller logic, I created a series of functions to translate, rotate, and scale the pose reported by the robot to a coordinate on the game board where each tile is one unit long.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Remove start offset so robot starts at 0,0
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;bot_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sensors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_pose_robot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bot_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sensors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_pose_robot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Apply rotation so robot starts at correct angle
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# -90 to handle turtle bot coordinates face in +y direction
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;bot_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bot_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rotate_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bot_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bot_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TurtlePose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bot_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_pose_virtual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bot_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_pose_virtual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;normalize_ang360&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sensors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once all the bugs were worked out, this provided a solid starting point for building the game controller.&lt;/p&gt;

&lt;h1 id=&quot;making-the-gui-and-adding-features&quot;&gt;Making the GUI and Adding Features&lt;/h1&gt;

&lt;p&gt;One of the reasons I explored ROS in my previous turtle bot iteration was that it provides a very modular way of connecting a robot to control and visualization systems. Hypothetically, the controls and game board idea I had could all be implemented as ROS packages. In practice, however, I found that the complexity of ROS added significant overhead when using it as the glue for my project. My use case was so simple that most of what ROS brought to the table was overkill. With that in mind, I decided to implement the game in the way I found most expedient and not worry about building it out of modular components that could be reused in other projects.&lt;/p&gt;

&lt;p&gt;I went with PyGame for the GUI since it’s simple and I’d used it before. I added another transform to go back and forth between robot coordinates, game map coordinates, and pixels on the PyGame map. To command the robot, I used the arrow keys reported by PyGame.&lt;/p&gt;

&lt;p&gt;The main challenge was setting up the threading strategy to handle the robot and GUI. I went from one big function to separating components more logically into classes.&lt;/p&gt;

&lt;p&gt;I realized this would be a great application for the &lt;a href=&quot;/toy-controller/&quot;&gt;Giving a Toy Controller WiFi&lt;/a&gt; I had made. I added an MQTT client to supplement keyboard commands with button presses from the toy controller. I figured I could also wire in the turtle board game controls over MQTT when I got to it.&lt;/p&gt;

&lt;p&gt;At this point, adding features was straightforward:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;GUI shows positioning estimate and can queue up a sequence of commands to execute when connected.&lt;/li&gt;
  &lt;li&gt;Simulation mode allows testing without a Dash bot connected.&lt;/li&gt;
  &lt;li&gt;IR distance sensors provide basic collision detection.&lt;/li&gt;
  &lt;li&gt;The front, right, and left LEDs match the colors of the controller buttons to help the player understand how clockwise and counterclockwise turns correspond to the bot’s relative position.&lt;/li&gt;
  &lt;li&gt;The light on top of the bot indicates if it’s busy. When sending commands in real time, it will sigh if a new command is sent while executing the previous one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I went on a little side quest when I was trying to get the robot’s sound effects working. To get the Dash to play sound, the command specifies a sound effects file name on the bot. A lot of the files in the original library were no longer working. I downloaded the APK and extracted the files with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apktool&lt;/code&gt;. This would have been another avenue for reverse engineering the interface since it had the java implementation including debug information. It also had the robot’s firmware with the actual audio files that got compiled in.&lt;/p&gt;

&lt;h1 id=&quot;making-the-nfc-card-reader&quot;&gt;Making the NFC Card Reader&lt;/h1&gt;

&lt;p&gt;The code for the reader can be found at:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/axlan/dash-turtle-game/tree/master/reader_firmware&quot;&gt;https://github.com/axlan/dash-turtle-game/tree/master/reader_firmware&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To “play” the cards from the original turtle game as commands to the robot, I decided the easiest approach was to stick them on NFC cards. I got 40 cards for less than $15.&lt;/p&gt;

&lt;p&gt;While I could have used a phone as a reader, I’ve had bad luck running servers on phones. Instead, I made a standalone reader by connecting an &lt;a href=&quot;https://www.elechouse.com/elechouse/images/product/PN532_module_V3/PN532_%20Manual_V3.pdf&quot;&gt;Elechouse PN532 NFC module&lt;/a&gt; to an ESP32. For simplicity, I used the high speed UART connection to the ESP32’s serial2 pins.&lt;/p&gt;

&lt;p&gt;I did a quick test with the Elechouse library &lt;a href=&quot;https://github.com/elechouse/PN532&quot;&gt;https://github.com/elechouse/PN532&lt;/a&gt;. This library was somewhat annoying since it isn’t packaged as a library that can easily be pulled into a PlatformIO or Espressif project. Even including it as a submodule was cumbersome since I needed to delete code for the extra interfaces. Once I got it working, though, it worked great.&lt;/p&gt;

&lt;p&gt;I decided to try a better packaged Adafruit library: &lt;a href=&quot;https://github.com/adafruit/Adafruit-PN532&quot;&gt;https://github.com/adafruit/Adafruit-PN532&lt;/a&gt;. This library required a much deeper understanding of NFC cards. I eventually got it working, but it performed significantly worse than the Elechouse library. I ended up switching back and just adding the files I needed to my repo.&lt;/p&gt;

&lt;p&gt;I think the Elechouse library was just packaging together a bunch of libraries as reference in &lt;a href=&quot;https://github.com/Seeed-Studio/PN532&quot;&gt;https://github.com/Seeed-Studio/PN532&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This library is based on &lt;a href=&quot;https://github.com/adafruit/Adafruit_NFCShield_I2C&quot;&gt;Adafruit_NFCShield_I2C&lt;/a&gt;.
&lt;a href=&quot;hhttps://www.seeedstudio.com/&quot;&gt;Seeed Studio&lt;/a&gt; rewrite the library to make it easy to support different interfaces and platforms.
&lt;a href=&quot;https://github.com/don&quot;&gt;@Don&lt;/a&gt; writes the &lt;a href=&quot;https://github.com/don/NDEF&quot;&gt;NDEF library&lt;/a&gt; to make it more easy to use.
&lt;a href=&quot;https://github.com/JiapengLi&quot;&gt;@JiapengLi&lt;/a&gt; adds HSU interface.
&lt;a href=&quot;https://github.com/awieser&quot;&gt;@awieser&lt;/a&gt; adds card emulation function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;but I didn’t bother going back to test this.&lt;/p&gt;

&lt;p&gt;To integrate the cards into the game, I used the “NFC Tools” app on my phone to add the card identifier (UP, LEFT, RIGHT, etc.) as a text record on each card. This was sent along with the card UID as JSON to my MQTT server, where the turtle game could listen for them.&lt;/p&gt;

&lt;p&gt;Once the firmware was working, I just stuck the electronics in a box and connected a USB battery.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;While I ended up adding a ton of features, this all came together pretty quickly. The final product is fairly solid and has mostly held up to use by a four year old. The inertial positioning is the biggest limitation. Probably more because initial conditions need to be set manually than due to drift during the run.&lt;/p&gt;

&lt;p&gt;If I wanted to make this more standalone, I could require set start and goal points on the mat. For feedback, I could probably create a dedicated display attached to a Raspberry Pi or ESP32.&lt;/p&gt;

&lt;p&gt;I’m still considering finishing the vacuum cleaner robot I started or implementing an absolute positioning system, but those are shelved for another day.&lt;/p&gt;

&lt;p&gt;As for using this as an actual toy, my daughter thought it was neat, but it was just another toy in toy room. She’s not really old enough to plan out the robot’s course and I think I’d need to add some story elements to keep her engaged. The actual software designed for the Dash is much more polished, but seems like it would be more suitable for an 8+ year old. Rather than being a toy I think she’d learn from directly, I hope she gets something on seeing me make something an using it to play with her.&lt;/p&gt;
</description>
        <pubDate>Tue, 03 Mar 2026 00:00:00 +0000</pubDate>
        <link>/dash-turtle-game/</link>
        <guid isPermaLink="true">/dash-turtle-game/</guid>
        
        
        <category>Software</category>
        
        <category>Hardware</category>
        
      </item>
    
      <item>
        <title>New Baby, New Umbilical Art</title>
        <description>&lt;p&gt;Our second child was born! So we had to make a new weird shrine with the umbilical cord so we’re not playing favorites.&lt;/p&gt;

&lt;p&gt;When our daughter was born we made a shrine in reference to the artifacts you find in the game Bloodborne (see: &lt;a href=&quot;/baby-misc/&quot;&gt;baby projects&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;My wife and I had recently played the game “Chants of Sennaar”, so we decided to make the shrine using glyphs from that game.&lt;/p&gt;

&lt;p&gt;The game focusing on decoding a series of languages from glyphs by finding how the glyphs are written and spoken while solving puzzles to progress through a Tower of Babel.&lt;/p&gt;

&lt;p&gt;We made a message saying “We love you little XXX” where we wrote out his name using a somewhat creative interpretation of the alchemist language:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chantsofsennaar.miraheze.org/wiki/Alchemist_(language)&quot;&gt;https://chantsofsennaar.miraheze.org/wiki/Alchemist_(language)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;building on the fan made periodic table.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/umbilical/glyphs.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/umbilical/glyphs.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/umbilical/display.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/umbilical/display.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/umbilical/both.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/umbilical/both.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a fun update, I got a response from the person who originally made the periodic tables when I posted this on the Chants of Sennaar Reddit:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Oh wow, never imagined this could be an indirect outcome of my going a bit mad and making a periodic table a couple years ago! Many congratulations on your new arrival, and the memento looks beautiful.&lt;/p&gt;

  &lt;p&gt;A little behind-the-scenes on it - the silicon symbol technically breaks the rules of Alchemist glyphs as the circle on the right ought to be connected to the main symbol, but it looked unsatisfying like that and rules are inevitably broken now and again in languages. It’s meant to be an abstract representation of a logic gate (with the dot as a 0 and circle as a 1), given what I associate with silicon, although that logic probably doesn’t make sense in-universe.&lt;/p&gt;

  &lt;p&gt;Oxygen is far more straightforward - it’s a nonmetal that incorporates the cross symbol seen in some living things like Plant and Monster. A particularly suitable glyph for a piece celebrating a new life.&lt;/p&gt;

  &lt;p&gt;Congratulations again!&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Sun, 01 Mar 2026 00:00:00 +0000</pubDate>
        <link>/another-umbilical/</link>
        <guid isPermaLink="true">/another-umbilical/</guid>
        
        
        <category>Personal</category>
        
        <category>Baby</category>
        
        <category>Laser Cutter</category>
        
      </item>
    
      <item>
        <title>Reverse Engineering the Dash Learning Robot</title>
        <description>&lt;p&gt;I brushed up on my Ghidra to add to the open source interface for a Dash robot I found at Goodwill. Finally, another thrift store project!&lt;/p&gt;

&lt;p&gt;Since &lt;a href=&quot;/making-a-turtle-bot-pt1/&quot;&gt;Making a Turtle Bot 1: Hacking a Mint Cleaner&lt;/a&gt;, I’ve been keeping an eye out for other cheap robotic vacuums to play with. On a recent trip, I noticed a decent looking robot in the toy section for $15 &lt;a href=&quot;https://store.makewonder.com/products/dash&quot;&gt;https://store.makewonder.com/products/dash&lt;/a&gt;. A quick search showed the company was still in business and there was a repo that at least claimed to offer Python controls. I figured worse case, I could replace the controller and use it for its motors.&lt;/p&gt;

&lt;p&gt;If you just want to use the library I updated for controlling the Dash in Python, see: &lt;a href=&quot;https://github.com/axlan/WonderPy&quot;&gt;https://github.com/axlan/WonderPy&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;dash-robot-used-as-intended&quot;&gt;Dash Robot Used as Intended&lt;/h1&gt;

&lt;p&gt;First, I gave it a spin using it as intended. It is meant to be controlled through an app and has a pretty nice remote control and visual programming language. Everything seemed to be working and already had a pretty neat toy out of my purchase.&lt;/p&gt;

&lt;p&gt;Here’s an Overview of its features:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/dash/dash-personality.svg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/dash/dash-personality.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;commercial-educational-robot-toys&quot;&gt;Commercial Educational Robot Toys&lt;/h2&gt;

&lt;p&gt;I can’t really say where the Dash falls in the ranking of learning robot toys. Its ecosystem seems fine, and the bot is cute while still having a bunch of features. On the other hand, I have a strong bias toward wanting something that’s an open system.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;They are more likely to teach generalizable skills&lt;/li&gt;
  &lt;li&gt;They can more easily outlive their parent company&lt;/li&gt;
  &lt;li&gt;Their incentives are better aligned to be good rather than sticky&lt;/li&gt;
  &lt;li&gt;They’re more likely to be interoperable with other systems widening the play space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is how I justify it anyway.&lt;/p&gt;

&lt;h1 id=&quot;the-official-python-interface&quot;&gt;The Official Python Interface&lt;/h1&gt;

&lt;p&gt;Much to their credit, the MakeWonder company released an official Python library.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/playi/WonderPy&quot;&gt;https://github.com/playi/WonderPy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rather than being cutesy, or a stripped down basic interface, it breaks out all the controls and sensors in a reasonable way. It even covers overlapping functionality to expose high level features like getting a position estimate and moving to a certain pose as well as low level features like motor control and accelerometer readings.&lt;/p&gt;

&lt;p&gt;Here’s the documentation of the features it covers:
&lt;a href=&quot;https://github.com/playi/WonderPy/blob/master/doc/WonderPy.md&quot;&gt;https://github.com/playi/WonderPy/blob/master/doc/WonderPy.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They even have some handy diagrams for the coordinate system:
&lt;a href=&quot;https://github.com/playi/WonderPy/blob/master/doc/WonderPy.md#coordinate-systems&quot;&gt;https://github.com/playi/WonderPy/blob/master/doc/WonderPy.md#coordinate-systems&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This would more than cover all the features I wanted for my turtle bot. The catch is that it only works in Python 2 on x86 OSX.&lt;/p&gt;

&lt;h1 id=&quot;porting-the-library&quot;&gt;Porting the Library&lt;/h1&gt;

&lt;p&gt;I found a few efforts to port the library to Python 3 and other OSs.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/IlyaSukhanov/morseapi&quot;&gt;https://github.com/IlyaSukhanov/morseapi&lt;/a&gt; - As far as I can tell, this was the only real reverse engineering effort. I hadn’t looked at it in detail until writing this article, since I figured the forks would have been mostly additive. As it turned out, this project has more functionality then its “children” and even had a partial implementation of the command I was interested in.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/havnfun/python-dash-robot&quot;&gt;https://github.com/havnfun/python-dash-robot&lt;/a&gt; - Is built on the previous project. It adds Python 3 compatibility along with dropping a bunch of the previously supported commands and sensors&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mewmix/bleak-dash&quot;&gt;https://github.com/mewmix/bleak-dash&lt;/a&gt; - Is built on the previous projects. Switches the BlueTooth support library and adds back the some of the sensor decoding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since I assumed the latest project would be the most complete, I used it as my starting point. In testing, the movement commands worked, but even doing something as simple as turning 90 degrees wasn’t easy to achieve. Instead of using the high level pose command like the original library, it used low level motor control in a way that didn’t seem well tuned.&lt;/p&gt;

&lt;p&gt;To illustrate here’s the evolution of the turning command:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;# https://github.com/playi/WonderPy
# This uses the robot&apos;s pose command to turn the robot in place.
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_turn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed_deg_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
    This is a somewhat naive drive command because it moves relative to the robot&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s measured position,
    which means error can accumulate.
    &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do_pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speed_deg_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;WWRobotConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WWPoseMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WW_POSE_MODE_RELATIVE_MEASURED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;WWRobotConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WWPoseDirection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WW_POSE_DIRECTION_INFERRED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;# https://github.com/IlyaSukhanov/morseapi
# This still uses the pose command, but the command no longer actually maps to the full pose.
# It appears that only relative movements are supported and some of the other flags are missing.
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;turn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed_dps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;360&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.094&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
    Turn Dash specified distance.

    This is a blocking call.

    :param degrees: How many degrees to turn.
    Positive values spin clockwise and negative counter-clockwise.
    :param speed: Speed to turn at, in degrees/second
    &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;360&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotImplementedError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Cannot turn more than one rotation per move&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speed_dps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# def _get_move_byte_array(distance_mm=0, degrees=0, seconds=1.0, eight_byte=0x80):
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;byte_array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_get_move_byte_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;byte_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# self.sleep does not work and api says not to use time.sleep...
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;# https://github.com/mewmix/bleak-dash
# This is the worst of all since it uses the drive command to try to spin the
# wheels open-loop, and doesn&apos;t appear to make logical sense since the speed_dps
# used to compute duration isn&apos;t related to the actual speed applied to the motors.
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;turn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed_dps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;360&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.094&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
    Turns the robot a specific number of degrees at a certain speed.
    This method simplifies the operation to a &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;spin&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; command for a calculated duration.
    Adjust this method based on your robot&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s capabilities.
    &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;360&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Cannot turn more than one rotation per move&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;# Assuming positive degrees for clockwise, negative for counter-clockwise
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Calculate duration based on speed and degrees to turn
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degrees&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed_dps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Adjust for negative speeds if necessary
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;drive&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytearray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
        &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Placeholder for potential additional parameters
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xff&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I originally assumed that these ports were rewriting the original Python implementation. However the original Python code doesn’t generate the commands to send to the robot directly. It builds a JSON string that it passes to a native OSX binary library that generates the binary data to send to the robot over Bluetooth.&lt;/p&gt;

&lt;p&gt;This explains why the original library was so limited and why the ports mostly just remix each other. If I wanted to get robust controls, I’d need to do some reverse engineering myself.&lt;/p&gt;

&lt;h1 id=&quot;reverse-engineering&quot;&gt;Reverse Engineering&lt;/h1&gt;

&lt;p&gt;The authors of the previous ports don’t explain how they reverse engineered the existing features. Only &lt;a href=&quot;https://github.com/IlyaSukhanov/morseapi&quot;&gt;https://github.com/IlyaSukhanov/morseapi&lt;/a&gt; seems to have actually done original work and he describes it as a process of trial and error, looking at the binary data sent when doing certain behaviors.&lt;/p&gt;

&lt;p&gt;While they don’t go into details as far as I can tell, the two ways I’d guess they might have tried would be:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Spy on the BlueTooth packets sent when using the android app (For example: &lt;a href=&quot;https://www.instructables.com/Reverse-Engineering-Smart-Bluetooth-Low-Energy-Dev/&quot;&gt;https://www.instructables.com/Reverse-Engineering-Smart-Bluetooth-Low-Energy-Dev/&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Use the original Python library on OSX and capture the binary data from various commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since I didn’t have a suitable OSX machine, the second option was out.&lt;/p&gt;

&lt;p&gt;While capturing the Android BlueTooth packets sounded interesting (and might be the only way for some other devices), it would be a lot of tedious trial and error.&lt;/p&gt;

&lt;p&gt;Rather than take either of these approaches, I decided to go back to the original program. Since the JSON commands were already very comprehensive, I predicted that reverse engineering the OSX dylib wouldn’t be too hard. This is mostly due to the JSON being all string based. Somewhere the key value pairs being sent would be mapped to the command data.&lt;/p&gt;

&lt;p&gt;The file I needed to decompile is: &lt;a href=&quot;https://github.com/playi/WonderPy/blob/master/WonderPy/lib/WonderWorkshop/osx/libWWHAL.dylib&quot;&gt;https://github.com/playi/WonderPy/blob/master/WonderPy/lib/WonderWorkshop/osx/libWWHAL.dylib&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While I haven’t done any serious decompiling in the past, I had used the NSA open source decompiler &lt;a href=&quot;https://github.com/NationalSecurityAgency/ghidra&quot;&gt;Ghidra&lt;/a&gt; for some capture the flag reverse engineering games. Decompiling dylibs is supported out of the box, so I imported the library and gave it a go. Fortunately, the function names were compiled into the library, so I had a decent amount of context to understand the call trees.&lt;/p&gt;

&lt;p&gt;I probably only know a fraction of Ghidra’s functionality, and I’m not going to be going step by step through the menus. In general I only used a few features.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;The Symbol Tree - This is a list of the namespaces functions and other symbols in the binary. I would filter by the word (e.x. “pose”) and look at the decompilation of the functions with relevant names.&lt;/li&gt;
  &lt;li&gt;Search - I could search the binary for certain strings and see where they’re used. This is especially helpful since I knew exact JSON key names to look for.&lt;/li&gt;
  &lt;li&gt;In the decompilation window I would select variables and edit their names. I’d double click functions to go to their implementations.&lt;/li&gt;
  &lt;li&gt;To find a functions caller, I’d right click and search for the places that reference it.&lt;/li&gt;
  &lt;li&gt;The most advanced thing I’d do is edit data types. This let me specify the fields in a struct so Ghidra can figure out what members pointers are referencing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first thing I did was find where the strings for the keys related to the commands were being used. I started with a command that was fully supported in the unofficial ports to check that the JSON was turning into the expected binary packets.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__thiscall&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;APICore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parseBodyWheels&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cnx_json&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;har&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_nx_json_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;left_cm_s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;right_cm_s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A quick Google found that the nx_json refers to the &lt;a href=&quot;https://github.com/thestr4ng3r/nxjson&quot;&gt;https://github.com/thestr4ng3r/nxjson&lt;/a&gt; C JSON library which helpfully lists its structure definition in the README:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nx_json_type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NX_JSON_NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// this is null value&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NX_JSON_OBJECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// this is an object; properties can be found in child nodes&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NX_JSON_ARRAY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// this is an array; items can be found in child nodes&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NX_JSON_STRING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// this is a string; value can be found in text_value field&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NX_JSON_INTEGER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// this is an integer; value can be found in int_value field&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NX_JSON_DOUBLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// this is a double; value can be found in dbl_value field&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NX_JSON_BOOL&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// this is a boolean; value can be found in int_value field&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nx_json_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;nx_json_type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// type of json node, see above&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// key of the property; for object&apos;s children only&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// text value of STRING node&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// the value of INTEGER or BOOL node&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dbl_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// the value of DOUBLE node&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;// number of children of OBJECT or ARRAY&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// points to first child&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// points to next child&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this I could define the structure of nx_json in Ghidra&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/dash/nx_json_ghidra.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/dash/nx_json_ghidra.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and simplify the function to:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__thiscall&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;APICore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parseBodyWheels&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_nx_json_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_2c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;left_cm_s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbl_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_strcmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;right_cm_s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lVar2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbl_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is pretty readable without doing the extra steps to guess the structure of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HALMotorWheel_t&lt;/code&gt; and give the variables nicer names. This already was fairly different from the Python code. These values are being stored as doubles, and they don’t appear to be directly being used to build the packet structure that gets sent to the Robot. That means that the parsing process is more complicated.&lt;/p&gt;

&lt;p&gt;Looking at the references to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parseBodyWheels&lt;/code&gt; I found :&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;// A bunch of intermediate variables are removed for brevity.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;APICore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;convertCtlrMessageToPackets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;RobotHW&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this_00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALPamplemousse_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_1a8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALAudioSynth_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_1a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALPing_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_198&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALPower_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_190&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALBodyPose_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_188&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALBodyMotionLinearAngular_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_180&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALUserSetting_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_178&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALAnim_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_170&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALSpeaker_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_168&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALEyeRing_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_160&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALRGB_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_158&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALLED3_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_150&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALLED_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_148&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_140&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_138&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_130&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALComponentScalar_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALMotorServo_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_120&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALMotorServo_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_118&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALLedMsg_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_108&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HALLauncher_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this_00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RobotHW&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;initComponentsForCtlr2BotMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RobotHW&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbl_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this_00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_e8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_1b1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RobotHW&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packetizeCtlr2BotMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shared_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shared_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shared_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_1c8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;param_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nx_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_nx_json_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_e8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_190&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALPower_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPowerStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;parsePower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_190&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_160&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALEyeRing_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getEyeRingStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;parseEyeRing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_160&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x65&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;LAB_000662f5:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_158&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALRGB_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getRGBStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;parseLightRGB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_158&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x69&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;LAB_00066285:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_148&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALLED_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getLEDStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;parseLightLED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_148&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x6b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LAB_000662f5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x6c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_150&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALLED3_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getLED3Storage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x6c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;parseLightLED3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_150&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x6d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LAB_00066285&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_130&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getMotorWheelStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;parseMotorWheel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_130&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xca&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LAB_00066187&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xcb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LAB_0006614f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xcc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;local_180&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALBodyMotionLinearAngular_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getBodyMotionLinearAngularStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xcc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;parseBodyMotionLinearAngular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_180&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xcd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;local_188&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALBodyPose_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getBodyPoseStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xcd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;parseBodyPose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_188&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;LAB_00066187:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;local_120&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorServo_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getMotorServoStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;parseMotorHeadTiltServo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_120&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xcf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xd0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LAB_00066187&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xd1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xd2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;LAB_00066117:&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;local_110&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getNoParamsStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;parseNoParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALNoParams_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xd3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;local_138&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                              &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getMotorWheelStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;local_140&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorWheel_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                              &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getMotorWheelStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xc9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;parseBodyWheels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_138&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_140&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xd4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LAB_00066117&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xd5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_128&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALComponentScalar_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getScalarStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parseScalarPercentage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_168&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALSpeaker_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getSpeakerStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parseSpeaker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_168&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x12d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_170&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALAnim_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getAnimStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x12d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parseOnRobotAnim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_170&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x130&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_1a0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALAudioSynth_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getAudioSynthStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x130&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parseAudioSynth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_1a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALLauncher_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getLauncherStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parseLauncher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x19a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_108&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALLedMsg_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getLedMsgStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x19a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parseLedMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_108&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1c2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_1a8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALPamplemousse_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPamplemousseStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x1c2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parsePamplemousseStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_1a8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1c3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_1b0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALPamplemousse_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPamplemousseStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x1c3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parsePamplemousseStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_1b0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_178&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALUserSetting_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getUserSettingsStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parseUserSettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_178&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;local_198&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALPing_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPingStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;parsePing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_198&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;unknown component id: %d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LAB_000665c3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;LAB_0006614f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;local_118&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HALMotorServo_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getMotorServoStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;parseMotorHeadPanServo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BotMessengerBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_118&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;LAB_000665c3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RobotHW&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_RSI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbl_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pvVar1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ctlr2BotMsg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetHwData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RobotHW&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setCommand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pvVar1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_f4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local_e8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_e8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For my purposes this is the top level function. It does the following:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Initialize a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctlr2BotMsg&lt;/code&gt;. This has the storage for all the messages that might be sent.&lt;/li&gt;
  &lt;li&gt;Loop through the JSON and set the values in the corresponding HAL structure in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctlr2BotMsg&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;After setting the data for the each command call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setCommand&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Once all the commands have been setup, call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;packetizeCtlr2BotMsg&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first thing I looked for, was where the commands were being mapped to command IDs that we see in the Python port:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;COMMANDS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;neck_color&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x03&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;tail_brightness&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x04&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;eye_brightness&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x08&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;eye&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x09&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;left_ear_color&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;right_ear_color&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;head_color&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;head_pitch&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x07&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;head_yaw&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x06&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;say&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;beep&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x19&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;drive&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x02&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xc8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The JSON uses different integers to identify the commands:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RobotComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_POWER&lt;/span&gt;                      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;    &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_EYE_RING&lt;/span&gt;                   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_RGB_EYE&lt;/span&gt;              &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;101&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_RGB_LEFT_EAR&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;102&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_RGB_RIGHT_EAR&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;103&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_RGB_CHEST&lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;104&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_MONO_TAIL&lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;105&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_MONO_BUTTON_MAIN&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;106&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_RGB_BUTTON_MAIN&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;107&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_MONO_BUTTONS&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;108&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_MONO_BUTTON_1&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;109&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# cue button light - circle
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_MONO_BUTTON_2&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;110&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# cue button light - square
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LIGHT_MONO_BUTTON_3&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;111&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# cue button light - triangle
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_HEAD_POSITION_TILT&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;202&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_HEAD_POSITION_PAN&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;203&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_BODY_LINEAR_ANGULAR&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;204&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_BODY_POSE&lt;/span&gt;                  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;205&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_MOTOR_HEAD_BANG&lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;210&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_BODY_WHEELS&lt;/span&gt;                &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;211&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_BODY_COAST&lt;/span&gt;                 &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;212&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_HEAD_PAN_VOLTAGE&lt;/span&gt;           &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;213&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_HEAD_TILT_VOLTAGE&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;214&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_SPEAKER&lt;/span&gt;                    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_ON_ROBOT_ANIM&lt;/span&gt;              &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;301&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LAUNCHER_FLING&lt;/span&gt;             &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LAUNCHER_RELOAD&lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_LED_MESSAGE&lt;/span&gt;                &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;410&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WW_COMMAND_SET_PING&lt;/span&gt;                   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;9000&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The JSON integers can be seen (as hex) in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convertCtlrMessageToPackets&lt;/code&gt; which makes sense. They are also referenced in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setCommand&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RobotHW_rev0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setCommand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sVar1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x28c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x80000000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;error: unsupported brightnessMode: %d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x58&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xffff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xfffffffffffffbff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xfffffffffffffdff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x54&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x65&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x66&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x84&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here the JSON commands are mapped to the one or more bit mask flags.&lt;/p&gt;

&lt;p&gt;These flags are then checked in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;packetizeCtlr2BotMsg&lt;/code&gt;. The pose command I’m interested in has the JSON ID of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xCD&lt;/code&gt;, which sets the bit flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x20000&lt;/code&gt;. In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;packetizeCtlr2BotMsg&lt;/code&gt; this is handled in this snippet.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;uVar19&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testAndClearCommandMaskBit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prVar25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x20000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar19&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;uVar17&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2f8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar17&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_688&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uVar17&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uVar17&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2U&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_200&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2f8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2f8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_3e0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x14U&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2f8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_3e1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;robot_hw0_cmd_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_3e1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;robot_hw0_cmd_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x29&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_690&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;32767.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_690&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_690&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;32767.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_690&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;32768.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_698&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;32768.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_698&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_690&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;local_3e1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;SUB21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ushort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_40a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parseBodyPose&lt;/code&gt;, I’d already created a data type for the pose data. It appeared that the data parsed from the JSON was being accessed here and serialized into the packet to send to the robot. I made a new data type to map the pose data to the right offset&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/dash/pose_data_map.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/dash/pose_data_map.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and made this block much clearer:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testAndClearCommandMaskBit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prVar12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x20000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_688&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_200&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// Logic for generating command to change the global coordinate origin&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_411&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_420&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x14U&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_430&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_438&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;100.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_440&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_438&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_6d8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1000.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;65535.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_6d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_6d8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;65535.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_6d8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_6e0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_6e0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_6d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_448&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_6e0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_428&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pppHVar27&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x7e580&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dVar29&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_430&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_44a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dVar29&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pppHVar27&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x7e59b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dVar29&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_440&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_44c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dVar29&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pppHVar27&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x7e5b6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_6e2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;iVar18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_448&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_450&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;undefined2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iVar18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_200&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_6e2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_440&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;local_411&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_44a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_44c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iVar18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iVar18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ushort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_44a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ushort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_44c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_6e2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_6e2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_6e8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;local_6e8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_6e8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ease&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wrap_theta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uVar20&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_420&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_44e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_6e2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only complicated thing left is where these values are being written to. For some reason, this code loops through the data making three copies. The line:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;local_411&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Writes the command ID byte &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x23&lt;/code&gt; (which matches the value in the Python port) to an offset in memory. This value appears to be the result of following a pointer to a pointer of the structure that’s building the packets to send. Still, we get the clear sequence of data which can be cleaned up to:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;// Get base pointer to the buffer&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_3d8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field0_0x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_3d8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Initialize tracking variable&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_200&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Packet type/ID&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packet_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packet_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Scale and prepare pose data&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_scaled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_scaled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_scaled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;100.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_delta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_scaled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1000.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Clamp time to uint16 range&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;65535.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;65535.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Round values for encoding&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_scaled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_scaled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_delta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Update tracking variable with rounding error&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_200&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_delta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Serialize to buffer&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packet_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                              &lt;span class=&quot;c1&quot;&gt;// Byte 0: Packet ID (0x23)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;// Byte 1: X low byte&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;// Byte 2: Y low byte&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// Byte 3: Theta low byte&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// Byte 4: Time high byte&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;// Byte 5: Time low byte&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// Byte 6: X high 6 bits&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// Byte 7: Y high 6 bits&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Pack theta high bits into bytes 6 and 7&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xC0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Theta bits [9:8]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xC0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Theta bits [11:10]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Initialize control byte&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                                      &lt;span class=&quot;c1&quot;&gt;// Byte 8: Control flags&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Handle mode (convert mode 5 to mode 3)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Pack control flags into byte 8&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x03&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;// Bits [7:6]: mode&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ease&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// Bit 5: ease&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wrap_theta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Bit 4: wrap_theta&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x0F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// Bits [3:0]: direction&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Update write offset&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_offset_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packet_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is trivial to port to the Python library to add a more complete version of the missing functionality.&lt;/p&gt;

&lt;p&gt;As I continued to read through the original Python library, I realized that the expected behavior was to pack multiple commands into packets up to a max size. This finally let me figure out that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loop is just writing the command into the next packet with capacity. This gives the extra context for the pose serialization:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;#define POSE_CMD_BYTE 0x23
#define POSE_CMD_SIZE 9
#define MAX_PACKET_SIZE 20
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;POSE_CMD_BYTE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;msg_len&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;POSE_CMD_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// msg_hw_ptr-&amp;gt;packets are the struct:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// struct Packet {&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   uint32_t size;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   uint8_t data[20];&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// }&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;packet_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packet_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;POSE_CMD_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAX_PACKET_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Scale pose values to fixed-point integers&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_enc&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;100.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Clamp time to uint16 range&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1000.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;65535.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;65535.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_ms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Pack command byte and fixed-point values into packet&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packet_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// x low byte&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_enc&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// y low byte&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// theta low byte&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_enc&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// time high byte&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_enc&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// time low byte&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_enc&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// x high bits&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_enc&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// y high bits&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xC0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// theta bits 9:8 -&amp;gt; x high byte bits 7:6&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xC0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// theta bits 11:10 -&amp;gt; y high byte bits 7:6&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Pack flags byte&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Map mode 5 -&amp;gt; 3, otherwise pass through&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;                          &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x03&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// bits 7:6 = mode&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ease&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// bit  5   = ease&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wrap_theta&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// bit  4   = wrap_theta&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x0F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// bits 3:0 = dir&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;msg_hw_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;systematically-decoding-the-commands&quot;&gt;Systematically Decoding the Commands&lt;/h2&gt;

&lt;p&gt;Now the I understood the basic structure of the library, I took notes on the all of the commands and the process to encode them:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/axlan/WonderPy/blob/master/doc/reversing/ReversingDylib.md&quot;&gt;https://github.com/axlan/WonderPy/blob/master/doc/reversing/ReversingDylib.md&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ghidra can be a little slow to navigate, so I used its Python API to dump the decompilation of functions that matched a regex:
&lt;a href=&quot;https://gist.github.com/axlan/c38f7b01e54ab9f7cdefea51cd1dc9ed&quot;&gt;https://gist.github.com/axlan/c38f7b01e54ab9f7cdefea51cd1dc9ed&lt;/a&gt; . I included this output in case anyone wants to implement some of the commands I skipped.&lt;/p&gt;

&lt;p&gt;With the mapping of the JSON commands to the flags that get set to send the various command packets, it was fairly quick to go through the features I wanted to support and write the serialization in Python.&lt;/p&gt;

&lt;p&gt;In doing this investigation I found quite a few commands that weren’t actually referenced in the original Python library. While most were just variations, I found a “Pamplemousse” command that appears to be able to define autonomous behaviors.&lt;/p&gt;

&lt;h2 id=&quot;decoding-the-sensors&quot;&gt;Decoding the Sensors&lt;/h2&gt;

&lt;p&gt;Decoding the sensor data coming from the bot was more straight-forward than encoding the commands. Rather then going through multiple conversion stages, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_deserialize&lt;/code&gt; function retrieves the bytes accicociated with each value, and calls the functions to scale them and write them to their corresponding JSON keys.&lt;/p&gt;

&lt;p&gt;The infrared distance sensors were a bit interesting. The bot directly reports a value referred to as “reflectance”, but the library had a function for converting this to distance in cm. There’s a class that builds a model based on a series of observations for each of the 3 sensors. They compiled in a series of test observations to initialize the model and that’s what they used to do the conversion. While implementing this in Python would have been possible, it would probably be a lot easier to just make my own model based on my own bot and the environment I’m using it in.&lt;/p&gt;

&lt;p&gt;The other interesting sensor was the microphone. It’s supposed to report the direction of detected sound along with its confidence. The reported direction seemed to work (its quite inaccurate which isn’t too unexpected), but it never reported any level of confidence. This might just be a lack of decompiling skills or a mistake on my part, but it is also possible this interface changed at some point.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;While I present a pretty clear progression to understanding this library, the actual process was much messier. I didn’t know which leads would be the most fruitful, so sometimes I missed important details as I jumped back and forth, spending time analyzing parts of the library that didn’t turn out to be relevant.&lt;/p&gt;

&lt;p&gt;While this turned out to be more complicated than I expected, it was still a relatively straightforward library that I had a lot of external context for.&lt;/p&gt;

&lt;p&gt;This function should be all that I need for my project, but maybe I’ll take the time at some point to clean up these libraries a bit more.&lt;/p&gt;

&lt;p&gt;The last mystery is why was the original project designed this way? It’s possible hiding the actual packet specification in a binary library was intentional obfuscation, but my guess is that it was a side effect of minimizing effort.&lt;/p&gt;

&lt;p&gt;It’s possible that the Python library was initially an internal testing tool. Someone realized that making it public open source would get people like me to consider the dash. If development was standardized on OSX and Python 2.7, that might have been all they supported internally. Once it was released, if it didn’t generate a ton of buzz, there may not have been much will to keep updating it.&lt;/p&gt;

&lt;p&gt;To implement my findings I made a fork the original &lt;a href=&quot;https://github.com/playi/WonderPy&quot;&gt;https://github.com/playi/WonderPy&lt;/a&gt; with the following changes:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Making it Python 3 compatible&lt;/li&gt;
  &lt;li&gt;Switching from its deprecated BLE library to &lt;a href=&quot;https://github.com/hbldh/bleak&quot;&gt;https://github.com/hbldh/bleak&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Removing the OSX library and replacing it with Python conversions for the commands/sensors I want to support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See: &lt;a href=&quot;https://github.com/axlan/WonderPy&quot;&gt;https://github.com/axlan/WonderPy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is still far from complete. Partly, because some of the features are complicated, but mostly just to not having infinite time.&lt;/p&gt;
</description>
        <pubDate>Sun, 08 Feb 2026 00:00:00 +0000</pubDate>
        <link>/reverse-dash/</link>
        <guid isPermaLink="true">/reverse-dash/</guid>
        
        
        <category>Software</category>
        
        <category>Hardware</category>
        
      </item>
    
      <item>
        <title>Profiling ESP32 UDP Sends</title>
        <description>&lt;p&gt;With my new profiling setup, I decided to test efficiently sending UDP data logs.&lt;/p&gt;

&lt;p&gt;With my findings from &lt;a href=&quot;/making-a-tracing-profiler-pt3/&quot;&gt;Making an Embedded Profiler 3: ESP IDF Tools&lt;/a&gt;, I decided to stick with using &lt;a href=&quot;https://github.com/mabuware/MabuTrace&quot;&gt;MabuTrace&lt;/a&gt;. While it isn’t exactly what I wanted for profiling, it covers all the key features, and in many ways is better than anything I’d end up making.&lt;/p&gt;

&lt;p&gt;However, it doesn’t cover the continuous logging use case. While it would generally make more sense to use MQTT, ESP-IDF logging, or some other existing protocol, I wanted to try using my &lt;a href=&quot;https://github.com/axlan/min-logger&quot;&gt;https://github.com/axlan/min-logger&lt;/a&gt; since I made it with the exact features I wanted.&lt;/p&gt;

&lt;p&gt;For the ESP32, &lt;a href=&quot;https://github.com/axlan/min-logger&quot;&gt;min-logger&lt;/a&gt; was still missing a backend for buffering logged data and sending it to the host.&lt;/p&gt;

&lt;p&gt;I quickly setup a ESP-IDF framework test application, and began to experiment with different approaches. &lt;a href=&quot;https://github.com/mabuware/MabuTrace&quot;&gt;MabuTrace&lt;/a&gt; was great in letting me see exactly what was happening with each approach.&lt;/p&gt;

&lt;p&gt;My goal was to set up a system where multiple tasks on multiple cores could write data simultaneously with minimal latency. This data would be buffered and periodically sent to the host over UDP. Since I don’t care about latency and each send has overhead, each send would be the maximum UDP packet size. I wanted to find a way to do this while being efficient with CPU and memory usage.&lt;/p&gt;

&lt;p&gt;Code for these tests is found at: &lt;a href=&quot;https://github.com/axlan/esp32-idf-udp-send-profiling&quot;&gt;https://github.com/axlan/esp32-idf-udp-send-profiling&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this article is about figuring out how to efficiently send UDP data, based on these results I added a &lt;a href=&quot;https://github.com/axlan/min-logger/tree/master?tab=readme-ov-file#esp32-buffered-platform-min_logger_buffered_esp32h&quot;&gt;buffered UDP output option to min-logger&lt;/a&gt;. I fell down a bit of a rabbit hole making a custom ring buffer for the use case: &lt;a href=&quot;https://github.com/axlan/min-logger/blob/master/src/min_logger/platform_implementations/lock_free_ring_buffer.h&quot;&gt;https://github.com/axlan/min-logger/blob/master/src/min_logger/platform_implementations/lock_free_ring_buffer.h&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;data-synchronization&quot;&gt;Data Synchronization&lt;/h1&gt;

&lt;p&gt;After reading the &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/index.html&quot;&gt;ESP-IDF documentation&lt;/a&gt;, I found the &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/freertos_additions.html#ring-buffers&quot;&gt;FreeRTOS ring buffer addition&lt;/a&gt;. Specifically, I could use it in “byte buffer” mode. This meant I could efficiently write arbitrarily sized chunks from multiple tasks and combine them into a single large read for sending over UDP. Initially, I set it up to drain the ring buffer into an array in the UDP send task. However, I realized that by sizing the buffer to be twice the desired UDP write size, I could effectively double-buffer the data and not need to worry about tearing on the consumer side.&lt;/p&gt;

&lt;p&gt;Here’s a little demo below. Note that as long as each read is half the buffer size, the data will always be contiguous.&lt;/p&gt;

&lt;style&gt;
    .buffer-container {
        max-width: 800px;
        margin: 0 auto;
    }
    .step {
        background: white;
        padding: 20px;
        margin: 20px 0;
        border-radius: 8px;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    .step-title {
        font-size: 18px;
        font-weight: bold;
        margin-bottom: 15px;
        color: #2c3e50;
    }
    .buffer {
        display: flex;
        gap: 2px;
        margin: 15px 0;
        flex-wrap: nowrap;
    }
    .cell {
        width: 32px;
        height: 32px;
        border: 2px solid #333;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 9px;
        font-weight: bold;
        position: relative;
        background: white;
        flex-shrink: 0;
    }
    .cell.filled {
        background: #4CAF50;
        color: white;
    }
    .cell.empty {
        background: #e0e0e0;
        color: #999;
    }
    .pointer {
        font-size: 10px;
        position: absolute;
        font-weight: bold;
    }
    .read-ptr {
        top: -18px;
        color: #e74c3c;
    }
    .write-ptr {
        bottom: -18px;
        color: #3498db;
    }
    .info {
        margin-top: 10px;
        padding: 10px;
        background: #f8f9fa;
        border-left: 4px solid #3498db;
        font-size: 14px;
    }
    .legend {
        display: flex;
        gap: 20px;
        margin: 20px 0;
        justify-content: center;
        flex-wrap: wrap;
    }
    .legend-item {
        display: flex;
        align-items: center;
        gap: 8px;
    }
    .legend-box {
        width: 20px;
        height: 20px;
        border: 2px solid #333;
    }
&lt;/style&gt;

&lt;div class=&quot;buffer-container&quot;&gt;
    &lt;h1&gt;Ring Buffer Operations (Size: 20)&lt;/h1&gt;

    &lt;div class=&quot;legend&quot;&gt;
        &lt;div class=&quot;legend-item&quot;&gt;
            &lt;div class=&quot;legend-box&quot; style=&quot;background: #4CAF50;&quot;&gt;&lt;/div&gt;
            &lt;span&gt;Filled&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class=&quot;legend-item&quot;&gt;
            &lt;div class=&quot;legend-box&quot; style=&quot;background: #e0e0e0;&quot;&gt;&lt;/div&gt;
            &lt;span&gt;Empty&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class=&quot;legend-item&quot;&gt;
            &lt;span style=&quot;color: #e74c3c; font-weight: bold;&quot;&gt;↓ Read Pointer&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class=&quot;legend-item&quot;&gt;
            &lt;span style=&quot;color: #3498db; font-weight: bold;&quot;&gt;↑ Write Pointer&lt;/span&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- Initial State --&gt;
    &lt;div class=&quot;step&quot;&gt;
        &lt;div class=&quot;step-title&quot;&gt;Initial State&lt;/div&gt;
        &lt;div class=&quot;buffer&quot;&gt;
            &lt;div class=&quot;cell empty&quot;&gt;
                &lt;span class=&quot;pointer read-ptr&quot;&gt;R&lt;/span&gt;
                &lt;span class=&quot;pointer write-ptr&quot;&gt;W&lt;/span&gt;
                0
            &lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;1&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;2&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;3&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;4&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;5&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;6&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;7&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;8&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;9&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;10&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;11&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;12&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;13&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;14&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;15&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;16&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;17&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;18&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;19&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;info&quot;&gt;Read = 0, Write = 0, Count = 0&lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- After Write 5 --&gt;
    &lt;div class=&quot;step&quot;&gt;
        &lt;div class=&quot;step-title&quot;&gt;Step 1: Write 5 elements&lt;/div&gt;
        &lt;div class=&quot;buffer&quot;&gt;
            &lt;div class=&quot;cell filled&quot;&gt;
                &lt;span class=&quot;pointer read-ptr&quot;&gt;R&lt;/span&gt;
                0
            &lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;1&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;2&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;3&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;4&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;
                &lt;span class=&quot;pointer write-ptr&quot;&gt;W&lt;/span&gt;
                5
            &lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;6&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;7&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;8&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;9&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;10&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;11&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;12&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;13&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;14&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;15&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;16&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;17&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;18&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;19&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;info&quot;&gt;Read = 0, Write = 5, Count = 5&lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- After Write 6 --&gt;
    &lt;div class=&quot;step&quot;&gt;
        &lt;div class=&quot;step-title&quot;&gt;Step 2: Write 6 elements&lt;/div&gt;
        &lt;div class=&quot;buffer&quot;&gt;
            &lt;div class=&quot;cell filled&quot;&gt;
                &lt;span class=&quot;pointer read-ptr&quot;&gt;R&lt;/span&gt;
                0
            &lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;1&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;2&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;3&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;4&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;5&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;6&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;7&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;8&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;9&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;10&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;
                &lt;span class=&quot;pointer write-ptr&quot;&gt;W&lt;/span&gt;
                11
            &lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;12&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;13&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;14&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;15&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;16&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;17&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;18&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;19&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;info&quot;&gt;Read = 0, Write = 11, Count = 11&lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- After Read 10 --&gt;
    &lt;div class=&quot;step&quot;&gt;
        &lt;div class=&quot;step-title&quot;&gt;Step 3: Read 10 elements&lt;/div&gt;
        &lt;div class=&quot;buffer&quot;&gt;
            &lt;div class=&quot;cell empty&quot;&gt;0&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;1&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;2&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;3&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;4&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;5&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;6&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;7&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;8&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;9&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;
                &lt;span class=&quot;pointer read-ptr&quot;&gt;R&lt;/span&gt;
                10
            &lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;
                &lt;span class=&quot;pointer write-ptr&quot;&gt;W&lt;/span&gt;
                11
            &lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;12&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;13&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;14&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;15&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;16&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;17&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;18&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;19&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;info&quot;&gt;Read = 10, Write = 11, Count = 1&lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- After Write 12 --&gt;
    &lt;div class=&quot;step&quot;&gt;
        &lt;div class=&quot;step-title&quot;&gt;Step 4: Write 12 elements (wraps around)&lt;/div&gt;
        &lt;div class=&quot;buffer&quot;&gt;
            &lt;div class=&quot;cell filled&quot;&gt;0&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;1&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;2&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;3&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;4&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;5&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;6&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;7&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;8&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;9&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;
                &lt;span class=&quot;pointer read-ptr&quot;&gt;R&lt;/span&gt;
                10
            &lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;11&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;12&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;13&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;14&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;15&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;16&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;17&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;18&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;19&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;info&quot;&gt;Read = 10, Write = 3 (wrapped), Count = 13&lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- After Read 10 --&gt;
    &lt;div class=&quot;step&quot;&gt;
        &lt;div class=&quot;step-title&quot;&gt;Step 5: Read 10 elements&lt;/div&gt;
        &lt;div class=&quot;buffer&quot;&gt;
            &lt;div class=&quot;cell filled&quot;&gt;
                &lt;span class=&quot;pointer read-ptr&quot;&gt;R&lt;/span&gt;
                0
            &lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;1&lt;/div&gt;
            &lt;div class=&quot;cell filled&quot;&gt;2&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;
                &lt;span class=&quot;pointer write-ptr&quot;&gt;W&lt;/span&gt;
                3
            &lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;4&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;5&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;6&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;7&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;8&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;9&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;10&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;11&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;12&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;13&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;14&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;15&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;16&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;17&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;18&lt;/div&gt;
            &lt;div class=&quot;cell empty&quot;&gt;19&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;info&quot;&gt;Read = 0 (wrapped), Write = 3, Count = 3&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The issue with implementing this approach is that the &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/freertos_additions.html#ring-buffers&quot;&gt;FreeRTOS ring buffer addition&lt;/a&gt; doesn’t have a way to wait for a certain threshold of data to be available. This meant I needed to poll the buffer to determine when it was full enough to read from.&lt;/p&gt;

&lt;h1 id=&quot;lwip-udp-send-options&quot;&gt;lwIP UDP Send Options&lt;/h1&gt;

&lt;p&gt;The first place I looked for an example of efficiently sending UDP packets was the ESP32 Arduino library. It has the &lt;a href=&quot;https://github.com/espressif/arduino-esp32/blob/master/libraries/AsyncUDP/&quot;&gt;AsyncUDP&lt;/a&gt; library. This library introduced me to an API I hadn’t seen before: the &lt;a href=&quot;https://www.nongnu.org/lwip/2_0_x/group__udp__raw.html&quot;&gt;lwIP raw/callback-style API&lt;/a&gt;. I spent considerable time trying to unravel this poorly documented interface. Once I started to understand it, I noticed the &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/lwip.html&quot;&gt;esp32-idf lwIP documentation&lt;/a&gt; mentioned that this API is not supported and to instead use a similar &lt;a href=&quot;https://www.nongnu.org/lwip/2_0_x/api_8h.html&quot;&gt;netconn API&lt;/a&gt;. Additionally, even this netconn API is only unofficially supported, and the BSD sockets are the recommended interface.&lt;/p&gt;

&lt;p&gt;Regardless, I completed a basic test application with both the BSD and raw APIs:&lt;/p&gt;

&lt;p&gt;Raw:
&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/mabu_trace.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/mabu_trace.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;BSD:
&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/profiling/gen_trace2_open.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/profiling/gen_trace2_open.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even looking at heap usage it isn’t obvious that the raw API has any advantage over the BSD.&lt;/p&gt;

&lt;p&gt;This was somewhat surprising since I set up the raw API to perform zero-copy operations:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;udp_client_task_raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pvParameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;udp_pcb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pcb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pcb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;udp_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;udp_bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pcb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IP_ADDR_ANY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;ip_addr_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest_ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dest_ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IPADDR_TYPE_V4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;IP4_ADDR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest_ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;192&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;168&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;111&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Allocate a pbuf that will point to a block of read only memory. In this case it will point to a half of the ring buffer being held.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;pbuf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pbuf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pbuf_alloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PBUF_TRANSPORT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UDP_MESSAGE_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PBUF_ROM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pbuf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// This is effectively const, but needs to be mutable to match pbuf typing since it&apos;s used for receive calls as well as send.&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;held_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Check if UDP send is done. If so return data to ring buffer.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;held_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pbuf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;vRingbufferReturnItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;held_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;held_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Check if a UDP packet&apos;s worth of data is ready to send.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xRingbufferGetCurFreeSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UDP_MESSAGE_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// By always reading half the buffer size, the read will never be limited by rolling over the end of the buffer.&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;held_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xRingbufferReceiveUpTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;portMAX_DELAY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UDP_MESSAGE_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UDP_MESSAGE_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pbuf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;held_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pbuf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tot_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UDP_MESSAGE_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;udp_sendto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pcb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pbuf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest_ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vTaskDelay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;portTICK_PERIOD_MS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s also surprising that for both implementations, the send call usually blocks for 3.5ms with just a single send every couple of seconds.&lt;/p&gt;

&lt;p&gt;There are several possibilities for this result:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;As mentioned, the raw API isn’t maintained, so it may be doing something less efficient than the better-supported BSD sockets.&lt;/li&gt;
  &lt;li&gt;Since no other data is being sent, each send call transmits the packet immediately. The behavior might be different if data was being queued.&lt;/li&gt;
  &lt;li&gt;The BSD socket appears to leverage the tiT (the lwIP background) task. It’s possible it’s using resources that are already allocated there.&lt;/li&gt;
  &lt;li&gt;The expected behavior may be for these functions to block to reduce buffer usage.&lt;/li&gt;
  &lt;li&gt;There may be more optimal compile-time configuration settings that would improve the raw interface if sockets weren’t being used anywhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a final test, I also implemented this with the netconn API. It ended up performing being fairly similar to the BSD code, passing off the processing to the tiT task.&lt;/p&gt;

&lt;p&gt;Here are the three implementations:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;bsd: &lt;a href=&quot;https://github.com/axlan/esp32-idf-udp-send-profiling/blob/f92c54270bbf05a5d4f08c3ff62366de2720ff9a/src/main.cpp#L226&quot;&gt;https://github.com/axlan/esp32-idf-udp-send-profiling/blob/f92c54270bbf05a5d4f08c3ff62366de2720ff9a/src/main.cpp#L226&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;netconn: &lt;a href=&quot;https://github.com/axlan/esp32-idf-udp-send-profiling/blob/f92c54270bbf05a5d4f08c3ff62366de2720ff9a/src/main.cpp#L173&quot;&gt;https://github.com/axlan/esp32-idf-udp-send-profiling/blob/f92c54270bbf05a5d4f08c3ff62366de2720ff9a/src/main.cpp#L173&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;raw: &lt;a href=&quot;https://github.com/axlan/esp32-idf-udp-send-profiling/blob/f92c54270bbf05a5d4f08c3ff62366de2720ff9a/src/main.cpp#L124&quot;&gt;https://github.com/axlan/esp32-idf-udp-send-profiling/blob/f92c54270bbf05a5d4f08c3ff62366de2720ff9a/src/main.cpp#L124&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, for this use case, the BSD sockets make the most sense since they are the simplest and best documented. The only real behavioral advantage I could identify is that the raw implementation spends more time in the user task instead of the lwIP task. This could potentially help the latency of other user tasks since they could more easily preempt it.&lt;/p&gt;
</description>
        <pubDate>Thu, 29 Jan 2026 00:00:00 +0000</pubDate>
        <link>/lwip-udp-profiling/</link>
        <guid isPermaLink="true">/lwip-udp-profiling/</guid>
        
        
        <category>Software</category>
        
        <category>IoT</category>
        
      </item>
    
      <item>
        <title>Making an Embedded Profiler 3: ESP IDF Tools</title>
        <description>&lt;p&gt;I want to settle on the tooling I’ll use for a large ESP32 project. I gave the raw ESP-IDF Espressif tools (without the Arduino wrapper) a try for the first time and found two additional logging/profiling tools to evaluate.&lt;/p&gt;

&lt;p&gt;This is a follow up to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/making-a-tracing-profiler-pt1/&quot;&gt;Making an Embedded Profiler 1: Surveying Existing Tracing Tools&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/making-a-tracing-profiler-pt2/&quot;&gt;Making an Embedded Profiler 2: Minimal Logging Library&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m at the point where I want to actually figure out the workflows and tools to use to continue my work on &lt;a href=&quot;/making-a-turtle-bot-pt1/&quot;&gt;Making a Turtle Bot 1: Hacking a Mint Cleaner&lt;/a&gt;. I had been frustrated by the limited feedback I was getting during development. So this time I wanted to make sure I could:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Easily dump data for analysis.&lt;/li&gt;
  &lt;li&gt;Get a wholistic view of what the system was doing.&lt;/li&gt;
  &lt;li&gt;Have useful debugging and logging tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having completed my own &lt;a href=&quot;https://github.com/axlan/min-logger&quot;&gt;https://github.com/axlan/min-logger&lt;/a&gt;, my plan A was to make an ESP32 specific design. My high-level plan was to write the logs to a buffer that would be drained by a separate task sending the data over UDP.&lt;/p&gt;

&lt;p&gt;As I began to look into the details of making this implementation I stumbled on two additional candidate libraries I wanted to cover. They both seem worth considering for use in my own development process, and also have interesting implementation details.&lt;/p&gt;

&lt;h1 id=&quot;mabutrace&quot;&gt;MabuTrace&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/mabuware/MabuTrace&quot;&gt;https://github.com/mabuware/MabuTrace&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like my initial assessment of profiling tools, this library also decides to capture binary data to convert into &lt;a href=&quot;https://ui.perfetto.dev/&quot;&gt;Perfetto&lt;/a&gt; logs.&lt;/p&gt;

&lt;p&gt;This library wraps the functionality in a super easy UI. To use it you:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Include the MabuTrace library in the build.&lt;/li&gt;
  &lt;li&gt;Initialize MabuTrace during application setup.&lt;/li&gt;
  &lt;li&gt;Instrument your code with tracing macros.&lt;/li&gt;
  &lt;li&gt;When your process runs, it creates an HTTP server and captures data into a ring buffer.&lt;/li&gt;
  &lt;li&gt;Going to the webserver lets you dump the ring of logged profiling data into your browser and seamlessly load it in &lt;a href=&quot;https://ui.perfetto.dev/&quot;&gt;Perfetto&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I initially tried to use their Arduino example in PlatformIO, but found that it used a newer version of the ESP Arduino library than PlatformIO supported. This is something that had been worrying me for a while since Espressif had decided to stop directly supporting PlatformIO. I decided that if I was going to need to use the ESP-IDF interface to test this library, I might as well go all the way and just use it directly without PlatformIO.&lt;/p&gt;

&lt;p&gt;Once I got the ESP-IDF toolchain setup (which was surprisingly painful), the &lt;a href=&quot;https://github.com/mabuware/MabuTrace/tree/master/examples/MabuTraceIdfExample&quot;&gt;https://github.com/mabuware/MabuTrace/tree/master/examples/MabuTraceIdfExample&lt;/a&gt; example worked out of the box.&lt;/p&gt;

&lt;p&gt;The output was exactly what I was looking for and I may very well decide to use this tool as part of my development.&lt;/p&gt;

&lt;p&gt;One thing I was surprised by was the inclusion of the CPU scheduling information. My reading of the Espressif FreeRTOS integration was that while some FreeRTOS features like the idle/tick hooks or the run time stats were accessible, the majority of the &lt;a href=&quot;https://freertos.org/Documentation/02-Kernel/02-Kernel-features/09-RTOS-trace-feature&quot;&gt;https://freertos.org/Documentation/02-Kernel/02-Kernel-features/09-RTOS-trace-feature&lt;/a&gt; weren’t available:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/freertos.html#&quot;&gt;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/freertos.html#&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/freertos_idf.html&quot;&gt;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/freertos_idf.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In looking at how Mabu achieves this, they have:&lt;/p&gt;

&lt;p&gt;mabutrace_hooks.h:&lt;/p&gt;
&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;trace_task_switch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// This macro is called when a task is about to be switched out.&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define traceTASK_SWITCHED_OUT() \
  do { \
    trace_task_switch(7); \
  } while(0)
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// This macro is called when a task has just been switched in.&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define traceTASK_SWITCHED_IN() \
  do { \
    trace_task_switch(6); \
  } while(0)
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which are included into the CMake build with:&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nf&quot;&gt;idf_build_set_property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;COMPILE_OPTIONS &lt;span class=&quot;s2&quot;&gt;&quot;-include&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CMAKE_CURRENT_SOURCE_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/src/mabutrace_hooks.h&quot;&lt;/span&gt; APPEND&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The trace_task_switch feeds the data into the profiler &lt;a href=&quot;https://github.com/mabuware/MabuTrace/blob/master/src/mabutrace.c#L330&quot;&gt;https://github.com/mabuware/MabuTrace/blob/master/src/mabutrace.c#L330&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While the IDF build is complicated, it seems that this effectively forces all the files in the build to add this include &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html#index-include&quot;&gt;https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html#index-include&lt;/a&gt;. This sets the macro for the FreeRTOS compilation.&lt;/p&gt;

&lt;p&gt;Even if I don’t use this library directly, this seems like a useful (if possibly brittle) way to customize FreeRTOS beyond what’s available as configuration settings.&lt;/p&gt;

&lt;p&gt;One thing to note is that this library uses the Perfetto JSON format instead of protobuf. This means that the way they represent the task core affinity is a bit of a hack.&lt;/p&gt;

&lt;p&gt;You can see the core affinity is being shown as “process 2”:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/mabu_trace.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/mabu_trace.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;instead of the built-in mechanism that I used in my tests:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/profiling/gen_trace2_open.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/profiling/gen_trace2_open.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this isn’t quite as nice as having the cores as their own part of the display, it’s a great workaround for getting most of the way there with the much simpler JSON interface.&lt;/p&gt;

&lt;h1 id=&quot;esp-idf-binary-logging-library&quot;&gt;ESP-IDF Binary Logging Library&lt;/h1&gt;

&lt;p&gt;In giving a thorough review of all the libraries and features in the ESP-IDF framework, I was surprised to find &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/log.html#binary-logging&quot;&gt;https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/log.html#binary-logging&lt;/a&gt;. This was surprisingly similar to my &lt;a href=&quot;https://github.com/axlan/min-logger&quot;&gt;https://github.com/axlan/min-logger&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;At a high level, its usage is the same as the design I came up with. The code makes normal logging calls that can either emit text like normal logs or packed binary messages with the strings replaced with integer IDs. On the host side, a special tool is needed to convert the binary back to messages and add back in the missing strings from a local repository.&lt;/p&gt;

&lt;p&gt;There are some major differences, though. Functionally, &lt;a href=&quot;https://github.com/axlan/min-logger&quot;&gt;min-logger&lt;/a&gt; is much simpler with many fewer features. However, it does out of the box support directly logging values and profiling data, while esp-idf logging is really just about generating formatted log messages.&lt;/p&gt;

&lt;p&gt;In terms of implementation, the magic to swap out the strings is very different between the libraries. As explained in &lt;a href=&quot;https://github.com/axlan/min-logger&quot;&gt;min-logger&lt;/a&gt;, the strings are captured by a Python script that uses a regex to identify the logging calls and capture the strings. The mapping is made by either manually assigning IDs or through a compile-time CRC of source file locations of the log call.&lt;/p&gt;

&lt;p&gt;The ESP-IDF logger uses the following macros:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;// https://github.com/espressif/esp-idf/blob/master/components/esp_common/include/esp_attr.h&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define _SECTION_ATTR_IMPL(SECTION, COUNTER) __attribute__((section(SECTION &quot;.&quot; _COUNTER_STRINGIFY(COUNTER))))
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// https://github.com/espressif/esp-idf/blob/master/components/esp_common/include/esp_attr.h&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Forces data to be removed from the final binary but keeps it in the ELF file&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define NOLOAD_ATTR _SECTION_ATTR_IMPL(&quot;.noload_keep_in_elf&quot;, __COUNTER__)
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// https://github.com/espressif/esp-idf/blob/v5.5.2/components/log/include/esp_private/log_attr.h&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Forces a string to be removed from the final binary but keeps it in the ELF file&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define ESP_LOG_NOLOAD_STR(str) (__extension__({static const NOLOAD_ATTR char __f[] = (str); (const char *)&amp;amp;__f;}))
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// https://github.com/espressif/esp-idf/blob/v5.5.2/components/log/include/esp_log_attr.h&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define ESP_LOG_ATTR_STR(str)           (__builtin_constant_p(str) ? ESP_LOG_NOLOAD_STR(str) : str)
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// https://github.com/espressif/esp-idf/blob/v5.5.2/components/log/include/esp_log.h#L184&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define ESP_LOG_LEVEL(configs, tag, format, ...) do { \
        esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT), tag, ESP_LOG_ATTR_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); \
    } while(0)
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What this does is declare the string as an array stored in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noload_keep_in_elf&lt;/code&gt; memory section. The pointer to this array is what is logged in the binary message.&lt;/p&gt;

&lt;p&gt;Presumably, one of the build steps strips this section when the ELF is being turned into the binary to send to the device.&lt;/p&gt;

&lt;p&gt;The monitor Python tool then recovers these strings from the ELF using the &lt;a href=&quot;https://github.com/eliben/pyelftools&quot;&gt;pyelftools&lt;/a&gt; library:
&lt;a href=&quot;https://github.com/espressif/esp-idf-monitor/blob/master/esp_idf_monitor/base/binlog.py&quot;&gt;https://github.com/espressif/esp-idf-monitor/blob/master/esp_idf_monitor/base/binlog.py&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an interesting approach, and I had considered doing something like this before I came up with the CRC approach. It is probably more robust than my regex approach, but it is more complex and potentially less efficient in needing to store and parse the ELF to interpret the logs.&lt;/p&gt;

&lt;p&gt;It’s interesting to see another library that achieved the same goals I was trying for. I might use the approach of putting data in a section that is stripped out for future use cases where I want to capture data from the compiler without adding it to the production binary.&lt;/p&gt;
</description>
        <pubDate>Tue, 27 Jan 2026 00:00:00 +0000</pubDate>
        <link>/making-a-tracing-profiler-pt3/</link>
        <guid isPermaLink="true">/making-a-tracing-profiler-pt3/</guid>
        
        
        <category>Software</category>
        
        <category>IoT</category>
        
      </item>
    
      <item>
        <title>Making an Embedded Profiler 2: Minimal Logging Library</title>
        <description>&lt;p&gt;I prototyped an embedded logging library. It focuses on flexibility, low resource usage, and compile-time configurability.&lt;/p&gt;

&lt;p&gt;The library can be found at: &lt;a href=&quot;https://github.com/axlan/min-logger/&quot;&gt;https://github.com/axlan/min-logger/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a follow up to &lt;a href=&quot;/making-a-tracing-profiler-pt1/&quot;&gt;Making an Embedded Profiler 1: Surveying Existing Tracing Tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I did the development described here shortly after the original article, but didn’t have a chance to write it up until now.&lt;/p&gt;

&lt;p&gt;In that time, another developer reached out to me about &lt;a href=&quot;https://github.com/RTEdbg/RTEdbg&quot;&gt;https://github.com/RTEdbg/RTEdbg&lt;/a&gt; which targets a very similar niche to the code I’ll discuss here. I’ve only had a chance to give it a fairly cursory look through, but it seems like a well thought-out project with a pretty end-to-end implementation for several processors. However, its tooling is Windows only and its build systems are all coupled with IDEs, so getting started would require a fair bit of work to adapt to the project structures I’m interested in.&lt;/p&gt;

&lt;p&gt;I called my library “min-logger” and focused on making a prototype that would run in Linux and on a &lt;a href=&quot;https://platformio.org/&quot;&gt;PlatformIO&lt;/a&gt; Espressif (the WiFi microcontrollers like the ESP32) build.&lt;/p&gt;

&lt;h1 id=&quot;design-priorities&quot;&gt;Design Priorities&lt;/h1&gt;

&lt;p&gt;Every now and then I find myself looking for a good embedded logging library. Unfortunately, there are a bunch of trade-offs in both resource usage and moving complexity between different parts of the system. For example:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The mechanism for getting the log data off the device can be a serial channel. Here you need to potentially contend with dropped data and initial synchronization. These channels are also often bandwidth limited.&lt;/li&gt;
  &lt;li&gt;Alternatively, logging may need to be done using a debugging tool like JTAG. This can make things very coupled to the specific processor and debugger (e.g. &lt;a href=&quot;https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/&quot;&gt;SEGGER RTT&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;It can use up precious storage space to compile in the strings used for logging.&lt;/li&gt;
  &lt;li&gt;The design of bare-metal, RTOS, and POSIX applications are very different, requiring different log handling.&lt;/li&gt;
  &lt;li&gt;Often continuous logging is not practical, so logging is only done when a trigger or crash occurs.&lt;/li&gt;
  &lt;li&gt;Does the logging need to be low latency? How much memory is available for buffering, and what should happen if a buffer fills up?&lt;/li&gt;
  &lt;li&gt;Different applications will want to log different amounts and types of data. Sometimes this requires instrumenting an RTOS or querying info from the kernel if present.&lt;/li&gt;
  &lt;li&gt;Different embedded systems have different build tools and compilers, which may limit the standard libraries that can be used.&lt;/li&gt;
  &lt;li&gt;To minimize resources on the device, context can be kept on the host collecting the log. This can make the host tools more complicated and require pre-build steps to generate files.&lt;/li&gt;
  &lt;li&gt;The code for calling the log function can be more permissive, or be more explicit and generate compile-time errors if it’s used incorrectly.&lt;/li&gt;
  &lt;li&gt;Ideally it should be easy to use. Making the logging calls should be simple.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So having a universal logging library is a bit of a pipe dream. Even if a single library did address all the use cases and trade-offs, it would be overwhelmingly complicated. There may be a way to thread that needle, but for now there are lots of small projects in this space that do an OK job at some of these priorities.&lt;/p&gt;

&lt;p&gt;So with this in mind, I decided to write my own library that hits the balance that I personally wanted.&lt;/p&gt;

&lt;h1 id=&quot;theory-and-high-level-design&quot;&gt;Theory and High Level Design&lt;/h1&gt;

&lt;h2 id=&quot;what-a-logger-captures&quot;&gt;What a Logger Captures&lt;/h2&gt;

&lt;p&gt;I’ve been particularly interested in making a logging library that didn’t need to send any static strings. For a log message like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOG_ERROR(&quot;CRITICAL ERROR&quot;)&lt;/code&gt;, there’s no information that needs to be conveyed except that the particular error occurred. The severity (‘LOG_ERROR’) and the string message can be inferred by just tracking which log call was triggered.&lt;/p&gt;

&lt;p&gt;This means that for a most minimal logging library that could only send static messages like this, the only thing that needs to be logged is an ID that maps to this unique log statement in the code. The host would then have a map of IDs back to their original context and could generate text or other data files with all the details like severity, source file+line, and a string message. This would be limited to very basic logging though.&lt;/p&gt;

&lt;p&gt;There are two main kinds of dynamic data that are usually added as part of a log. First, there are the values captured explicitly like: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOG_INFO(&quot;temp: %d&quot;, temp_val)&lt;/code&gt;. This example encodes the temperature as a string, though some logs will capture values in more structured ways. The second kind of values are the context that is captured implicitly. For example:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%(name)s: %(asctime)s | %(process)d:%(thread)d &amp;gt;&amp;gt;&amp;gt; %(message)s&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%Y-%m-%dT%H:%M:%SZ&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;unexpected error&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;captures the logger name, timestamp, process ID, and thread ID:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;root: 2023-02-05T14:11:56Z | 428223:128418208166016 &amp;gt;&amp;gt;&amp;gt; unexpected error
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Whether the values are captured explicitly or implicitly, I’d at least want a design that has the capacity for capturing dynamic values.&lt;/p&gt;

&lt;h2 id=&quot;dividing-up-the-design&quot;&gt;Dividing Up the Design&lt;/h2&gt;

&lt;p&gt;I’m at the point in my software development journey where it’s hard for me not to overengineer a &lt;a href=&quot;https://en.wikipedia.org/wiki/Greenfield_project&quot;&gt;greenfield project&lt;/a&gt; like this. To try to combat this, I like making things modular. It’s still a form of overengineering, but at least it lets me focus on the parts of a project I’m interested in. I can rationalize doing a basic job on the rest with the thought that I could always swap those sections for something better down the line.&lt;/p&gt;

&lt;p&gt;I divided up the logging library into the following parts:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Log specification - Any extra information that needs to be defined for the logging to work. For example, data to map enumeration values to log strings or logged data descriptions.&lt;/li&gt;
  &lt;li&gt;The logging calls - The way that the user code interacts with the library. It needs to be able to pass an ID and values to be logged.&lt;/li&gt;
  &lt;li&gt;Context generation - This layer adds values for implicit context like thread ID or timestamps.&lt;/li&gt;
  &lt;li&gt;Serialization - This layer generates the message in memory to send.&lt;/li&gt;
  &lt;li&gt;Transport - This layer sends out the data to the host.&lt;/li&gt;
  &lt;li&gt;Host capture - This tool logs the data coming from the device.&lt;/li&gt;
  &lt;li&gt;Data analysis - These are tools that can process the logs and generate visualization or other artifacts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’m primarily focused on layers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6.&lt;/code&gt;. I want to make the logging calls as polished as I can, and I want to be able to use the profiling visualization tool from &lt;a href=&quot;/making-a-tracing-profiler-pt1/&quot;&gt;Making an Embedded Profiler 1: Surveying Existing Tracing Tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m a bit less interested in 2-4 since these steps tend to be the most platform specific.&lt;/p&gt;

&lt;p&gt;To make the design modular, I need to think through what information passes from one step to the next.&lt;/p&gt;

&lt;h3 id=&quot;log-specification&quot;&gt;Log Specification&lt;/h3&gt;

&lt;p&gt;The log specification can potentially get the following details from a log ID:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The source file and line the log statement is on&lt;/li&gt;
  &lt;li&gt;The severity of the log statement&lt;/li&gt;
  &lt;li&gt;The expected payload size and structure&lt;/li&gt;
  &lt;li&gt;A string description&lt;/li&gt;
  &lt;li&gt;Log filter tags. For example, all the logs involved with request handling could have a “requests” tag that could be used for host-side filtering&lt;/li&gt;
  &lt;li&gt;A format string that references the included payload, or other information (e.g. “Error duration too long. [previous:%u, current:%u]”)&lt;/li&gt;
  &lt;li&gt;Special handling. For instance, certain log IDs could be reserved for capturing profiling data that would be processed differently from “generic” values&lt;/li&gt;
  &lt;li&gt;A relationship with other log messages. For example, two logs that captured timestamps could be matched up to compute the delay between them. This is useful for profiling execution times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This information could be its own file, but it could also be inferred from the logging calls implicitly. For example I could use a C parser to find the log calls and record their source location.&lt;/p&gt;

&lt;h3 id=&quot;logging-call-design&quot;&gt;Logging Call Design&lt;/h3&gt;

&lt;p&gt;I want adding log statements to be very low friction, so I want to minimize the boilerplate needed. The logging call could be as simple as:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IDType&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This requires making a concrete choice about the size of the ID. I’ll discuss that a bit later so for now we’ll treat it as its own integer type.&lt;/p&gt;

&lt;p&gt;There are a few reasons to make the logging call a bit more complex. First, I initially wanted to make this logging library capable of swapping between minimized binary and full string output. This would be a compile-time macro that would do something like the following:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;#define LOG_ID(id, level, msg, payload_type, payload, size)                              \
    if (!DISABLE_VERBOSE_LOGGING &amp;amp;&amp;amp; is_verbose()) {                                      \
        log_verbose(id, __FILE__, __LINE__, __func__, msg, level, payload_type, payload, \
                    size);                                                               \
    } else {                                                                             \
        log_binary(id, payload, size);                                                   \
    }
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Separately, I also didn’t like that the ID needed to be manually specified. The user would need to keep track of the values used. I wanted to see if I could figure out a way to generate the IDs at compile time.&lt;/p&gt;

&lt;h3 id=&quot;context-generation&quot;&gt;Context Generation&lt;/h3&gt;

&lt;p&gt;The context I’m most interested in is a timestamp and thread/task ID.&lt;/p&gt;

&lt;p&gt;I didn’t want to spend a ton of time engineering this process so I mostly just made simple solutions for Linux and Espressif.&lt;/p&gt;

&lt;p&gt;The main design point I needed to decide was how to log this additional data. To a certain extent this is tied up with the serialization. For example, to minimize bandwidth, the timestamps could be a relative time. If absolute time was needed, a periodic mapping message could be sent.&lt;/p&gt;

&lt;p&gt;Similarly, if I wanted to map log messages to named threads, I could publish this mapping periodically or send it with every message. These approaches would be less viable in a system where messages might be frequently dropped.&lt;/p&gt;

&lt;p&gt;Capturing this context or sending out periodic messages brings in the potential for processing delays, additional threads, and inter-thread synchronization. The design for a single-core system would be vastly different from one that’s multi-cored.&lt;/p&gt;

&lt;h3 id=&quot;serialization--transport&quot;&gt;Serialization / Transport&lt;/h3&gt;

&lt;p&gt;On the serialization side, there’s tons of design space. In some systems you’d need to work with an existing message framing protocol. Some interfaces are lossy, and some don’t have that concern (UART vs TCP). I make some basic choices for my implementation, but it should be easy enough to swap out for other platforms.&lt;/p&gt;

&lt;p&gt;The main thing to figure out is the layer between the serialization and the transport. Ideally, logging should not block on the data waiting to be sent out to the host. In my examples I used existing transport buffers. On a bare-metal system this might be best accomplished by using a ring buffer and setting up &lt;a href=&quot;https://en.wikipedia.org/wiki/Direct_memory_access&quot;&gt;DMA&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;host-capture&quot;&gt;Host Capture&lt;/h3&gt;

&lt;p&gt;Host capture can be surprisingly complicated to implement robustly. Some systems have tiny buffers for serial data by default that can silently drop data, and it can be hard to minimize latency if that’s a priority. However, here I’m doing the minimum to dump data to files.&lt;/p&gt;

&lt;h3 id=&quot;data-analysis&quot;&gt;Data Analysis&lt;/h3&gt;

&lt;p&gt;The most basic design for analysis would be to combine the information from the log specification to the data captured from the host and converting it into a machine-readable format (CSV, JSON, binary structs, etc.). It could involve syncing the data and error correcting, and propagating any persistent state between messages.&lt;/p&gt;

&lt;p&gt;For special message types like profiling, visualizations could be built in.&lt;/p&gt;

&lt;h1 id=&quot;my-implementation&quot;&gt;My Implementation&lt;/h1&gt;

&lt;p&gt;Based on my skill set, I wanted to make a C/C++ library that used Python for any pre-build processing and for analysis. I ended up going through a few iterations as I got far enough to realize that there was a simpler option.&lt;/p&gt;

&lt;p&gt;Throughout, I used CMake to manage the Linux build with test examples.&lt;/p&gt;

&lt;h2 id=&quot;attempt-1-generating-helper-functions&quot;&gt;Attempt 1: Generating Helper Functions&lt;/h2&gt;

&lt;p&gt;My first instinct was to use Python to generate C code that would capture the context for logging with strings. The advantage to generating the code this way was that in code, the log functions could be identified with a string (e.g. “example_temp_error”). The Python code could then turn all the values into numeric IDs that fit in the smallest number of bytes and include these IDs in the generated files.&lt;/p&gt;

&lt;p&gt;The code can be found here: &lt;a href=&quot;https://github.com/axlan/min-logger/tree/gen-helper-file&quot;&gt;https://github.com/axlan/min-logger/tree/gen-helper-file&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The CMake would run a pre-build Python command &lt;a href=&quot;https://github.com/axlan/min-logger/blob/gen-helper-file/cmake/BuildLogger.cmake&quot;&gt;https://github.com/axlan/min-logger/blob/gen-helper-file/cmake/BuildLogger.cmake&lt;/a&gt; to generate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_min_logger_gen.h&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The user would use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MIN_LOGGER_LOG&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;#define MIN_LOGGER_LOG(level, msg, id) \
    if (MIN_LOGGER_MIN_LEVEL &amp;gt;= level) { \
        min_logger_log_func_##id(); \
    }
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which would then call the generated code. For example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MIN_LOGGER_LOG(MIN_LOGGER_INFO, &quot;hello world&quot;, 0);&lt;/code&gt; would generate:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;min_logger_log_func_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;min_logging_is_verbose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()){&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if !MIN_LOGGER_DISABLE_VERBOSE_LOGGING
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;min_logger_format_and_write_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MIN_LOGGER_NO_TAGS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                        &lt;span class=&quot;s&quot;&gt;&quot;examples/hello_cpp/hello.cpp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                        &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                        &lt;span class=&quot;s&quot;&gt;&quot;hello world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                        &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;min_logger_write_msg_from_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;min_logger_write_msg_from_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I realized as I went to add additional logging functions that it was becoming quite complex to generate all this C code in Python. Naming the log statements actually seemed like more work than giving them a numeric value, so I decided to refactor to drop the whole code generation approach.&lt;/p&gt;

&lt;h2 id=&quot;attempt-2-generating-id-from-crc-of-source-location&quot;&gt;Attempt 2: Generating ID from CRC of Source Location&lt;/h2&gt;

&lt;p&gt;The code for this version can be found here: &lt;a href=&quot;https://github.com/axlan/min-logger/tree/verbose-logging&quot;&gt;https://github.com/axlan/min-logger/tree/verbose-logging&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had spent a lot of time brainstorming how to generate a unique ID on the device side that would be possible to determine for the host as well. There are a few macros that are often used for this sort of purpose:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__LINE__&lt;/code&gt; - The line number of the source file the macro expands on. This will have collisions if log statements occur on the same line in different files.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__COUNTER__&lt;/code&gt; - Not part of the C standard, but supported by most compilers. Each time it’s used, it expands to an integer literal one greater than its previous expansion. This would be difficult to predict the value from Python, and could have collisions for code with multiple compilation units.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__FILE__ + __LINE__&lt;/code&gt; - This would be fairly reliably unique, but there’s no simple compile-time method to convert this to an integer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am probably overly fond of C++ metaprogramming, and had been contemplating using recursive templating to hash the file+line number at compile time. When I decided to commit to using integers as an ID, I decided to actually implement this approach: &lt;a href=&quot;https://github.com/axlan/min-logger/blob/master/src/min_logger/min_logger_crc.h&quot;&gt;https://github.com/axlan/min-logger/blob/master/src/min_logger/min_logger_crc.h&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I didn’t want to drop C support, so I made a runtime implementation as well, but it had a few disadvantages.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The code to do the computation uses a lookup table which takes up RAM.&lt;/li&gt;
  &lt;li&gt;The code needs to run the first time a log is called, adding to the CPU usage.&lt;/li&gt;
  &lt;li&gt;The logic for caching the ID adds to the complexity of the logging calls.&lt;/li&gt;
  &lt;li&gt;The strings for the file+line need to be compiled into the program, making it larger.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To avoid these disadvantages, I left the option to explicitly specify the ID. This would also have a use in the C++ code to avoid having an ID change if the code was refactored and a log statement’s source location changed. If the IDs are hard-coded, old logs could be reprocessed without needing to archive or regenerate the log specification associated with that build.&lt;/p&gt;

&lt;p&gt;With this approach I finished off the basic features, and was able to get the end-to-end demo I was looking for. &lt;a href=&quot;https://github.com/axlan/min-logger/blob/master/examples/log_threads/log_threads.cpp&quot;&gt;https://github.com/axlan/min-logger/blob/master/examples/log_threads/log_threads.cpp&lt;/a&gt; could be visualized as:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/min_logger/verbose_profiling.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This version of the library uses a somewhat convoluted system for associating dynamic values with log messages. This has the disadvantage that the overhead of sending a log message needs to be duplicated for each value, but the values can be used by multiple different log statements. Variables are logged in their own log calls, and subsequent log messages can reference them:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;MIN_LOGGER_RECORD_STRING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MIN_LOGGER_INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;T_NAME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MIN_LOGGER_RECORD_VALUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MIN_LOGGER_INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;LOOP_COUNT&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MIN_LOGGER_PAYLOAD_U64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MIN_LOGGER_LOG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MIN_LOGGER_INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;task${T_NAME}: ${LOOP_COUNT}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The analyzed logs would be printed as:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;14780722.900970 INFO  examples/log_threads/log_threads.cpp:19 thread_id_1] tasktask2: 0
14780722.900990 INFO  examples/log_threads/log_threads.cpp:19 thread_id_0] tasktask2: 0
14780723.901040 INFO  examples/log_threads/log_threads.cpp:19 thread_id_1] tasktask2: 1
14780723.901062 INFO  examples/log_threads/log_threads.cpp:19 thread_id_0] tasktask1: 1
14780724.901795 INFO  examples/log_threads/log_threads.cpp:19 thread_id_0] tasktask2: 2
14780724.901811 INFO  examples/log_threads/log_threads.cpp:19 thread_id_1] tasktask2: 2
14780725.902618 INFO  examples/log_threads/log_threads.cpp:19 thread_id_1] tasktask2: 3
14780725.902661 INFO  examples/log_threads/log_threads.cpp:19 thread_id_0] tasktask2: 3
14780726.903073 INFO  examples/log_threads/log_threads.cpp:19 thread_id_0] tasktask2: 4
14780726.903142 INFO  examples/log_threads/log_threads.cpp:19 thread_id_1] tasktask2: 4
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This shows a bug/feature where the variables associated with the log lines aren’t thread specific. You can see that the name for the second thread would sometimes be interleaved with the log line from the first thread. This would be trivial to fix if I made the values thread specific, but the preferred behavior is situational. Ideally, I’d want to be able to specify the behavior as part of the format string.&lt;/p&gt;

&lt;h2 id=&quot;attempt-3-dropping-verbose-logging-to-streamline-logging-payloads&quot;&gt;Attempt 3: Dropping Verbose Logging to Streamline Logging Payloads&lt;/h2&gt;

&lt;p&gt;The code for this version can be found here: &lt;a href=&quot;https://github.com/axlan/min-logger/&quot;&gt;https://github.com/axlan/min-logger/&lt;/a&gt; (I finally spent the time to mostly clean up the documentation)&lt;/p&gt;

&lt;p&gt;A lot of the complexity and limitations in the code base were due to wanting to be able to switch between ASCII and binary logs at runtime.&lt;/p&gt;

&lt;p&gt;I had decided to support this feature since it made debugging easier, and it was nice to have a mode to get human-readable output directly. However, I decided that improving and documenting the library would be easier going forward if I simplified it to focus on the efficient binary output.&lt;/p&gt;

&lt;p&gt;This let me make the interface for logging arbitrary values much more robust:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C&quot;&gt;/**
 * Log a single fixed-size value (C++ only, auto-generates ID).
 *
 * The message ID is automatically generated from __FILE__ and __LINE__.
 *
 * Compile-time constraints:
 * - level must be an integer or priority constant
 * - name should contain only variable-name-valid characters
 * - type must match the actual type of value. If it is not a primitive type, it must be
 *   described in a type_defs JSON file when generating the mapping. The type must be a
 *   plain old data (POD) type with no pointers or references.
 * - value must be a variable that can be pointed to
 *
 * Runtime behavior:
 * - Serializes the value if level checks pass
 *
 * @param level The log level (MIN_LOGGER_DEBUG, MIN_LOGGER_INFO, etc.)
 * @param name  Descriptive name for the value (used in external mapping)
 * @param type  The C++ type of the value (must match actual type)
 * @param value The value to log (type-checked at compile time)
 *
 * Example:
 *   float current_temp = 25.5f;
 *   MIN_LOGGER_RECORD_VALUE(MIN_LOGGER_WARN, &quot;cpu_temp&quot;, float, current_temp)
 */
#define MIN_LOGGER_RECORD_VALUE(level, name, type, value)                 \
    {                                                                     \
        PRIVATE_MIN_LOGGER_LOG_MSG_GEN_ID(MIN_LOGGER_LOC);                \
        MIN_LOGGER_RECORD_VALUE_ID(min_log_id, level, name, type, value); \
    }

/**
 * Identical to MIN_LOGGER_RECORD_VALUE at runtime. The difference is that this macro
 * provides context for tools that extract log metadata to generate a message when this
 * value is sent. In the msg, use ${VALUE_NAME} to reference this or previously logged
 * values.
 */
#define MIN_LOGGER_RECORD_AND_LOG_VALUE(level, name, type, value, msg) \
    MIN_LOGGER_RECORD_VALUE(level, name, type, value)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now arbitrary data types can be logged, and if a log message should be printed each time a value is sent, this can be done with a single logging call. I also added the capability to save the recorded values to *.csv files.&lt;/p&gt;

&lt;p&gt;I supported this by making a quick and dirty JSON data type description format. This file is a dictionary of custom or ambiguous types to Python &lt;a href=&quot;https://docs.python.org/3/library/struct.html#format-characters&quot;&gt;struct format&lt;/a&gt; string values. These can reference other definitions in the file or C primitives. Struct formats must be a number of repetitions and a single value character. Custom types can also start with a number of repetitions for fixed-size arrays.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;int&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;i&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Point&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dummy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2i&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Rect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Point&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Point&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;padding&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;10x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;str&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;10s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;bytes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;10s&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See &lt;a href=&quot;https://github.com/axlan/min-logger/tree/master/examples/custom_type&quot;&gt;https://github.com/axlan/min-logger/tree/master/examples/custom_type&lt;/a&gt; for a full example.&lt;/p&gt;

&lt;p&gt;One last feature I added was a tool for cross-checking these type definitions with the structures as defined by the compiler. The easiest way I could think of was using the debugger to print the size of the type:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;gdb build/examples/custom_type/custom_type &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;print sizeof(Rect)&quot;&lt;/span&gt; 
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I made a Python script to automate this cross-check: &lt;a href=&quot;https://github.com/axlan/min-logger/tree/master/python/src/min_logger/validate_types.py&quot;&gt;https://github.com/axlan/min-logger/tree/master/python/src/min_logger/validate_types.py&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;serialization-and-transmission-limitations-and-improvements&quot;&gt;Serialization and Transmission Limitations and Improvements&lt;/h2&gt;

&lt;p&gt;The library has two serialization approaches built in. The default format (MIN_LOGGER_DEFAULT_BINARY_SERIALIZED_FORMAT / BINARY) isn’t optimized for any particular application, but would be reasonably robust to send over a UART interface. The micro format (MIN_LOGGER_MICRO_BINARY_SERIALIZED_FORMAT / MICRO_BINARY) is pretty minimal while still being suitable for multi-threaded execution profiling.&lt;/p&gt;

&lt;p&gt;It is trivial to use a different scheme on the device side. However, it would be somewhat complicated to add new formats to the Python parsing tool.&lt;/p&gt;

&lt;p&gt;The Python parsing tool is extremely inefficient. The message framing and decoding of any complex values is done naively in the Python code. If I wanted to support parsing large amounts of data, I would probably choose a dedicated compiled framing tool to sync and drop corrupt data. Then I could use a more well-supported deserialization tool like &lt;a href=&quot;https://kaitai.io/&quot;&gt;Kaitai&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the device side, I’ve mostly been relying on directly passing the data to the output with syscalls. This may add significant overhead to the logging calls. It would be fairly trivial to buffer the transmissions before the calls that may block on a separate thread. I plan on setting something like this up when I make a non-trivial use of this library.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;This library reached the level of capability I wanted for a real project.&lt;/p&gt;

&lt;p&gt;On the other hand, I made a bunch of choices that met my preferences, but might be baffling to anyone looking to use it.&lt;/p&gt;

&lt;p&gt;Some notable decisions:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Using macros (instead of functions) to allow auto-generated enums in C++&lt;/li&gt;
  &lt;li&gt;Using Python regexes to scan the C/C++ macros to record the metadata&lt;/li&gt;
  &lt;li&gt;Using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uv&lt;/code&gt; tool to orchestrate Python scripts in the glue logic&lt;/li&gt;
  &lt;li&gt;Focusing on passing the thread ID in the serialization and analysis&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 13 Jan 2026 00:00:00 +0000</pubDate>
        <link>/making-a-tracing-profiler-pt2/</link>
        <guid isPermaLink="true">/making-a-tracing-profiler-pt2/</guid>
        
        
        <category>Software</category>
        
      </item>
    
      <item>
        <title>Fatal Core Dump Game</title>
        <description>&lt;p&gt;I decided to make a somewhat educational murder mystery game, with debugging a core dump as the main piece of evidence.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;THIS ARTICLE HAS SPOILERS! IF YOU’RE INTERESTED, PLAY THE GAME HERE FIRST:&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;a href=&quot;https://www.robopenguins.com/fatal_core_dump/&quot;&gt;https://www.robopenguins.com/fatal_core_dump/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;All the code for this game can be found at: &lt;a href=&quot;https://github.com/axlan/fatal_core_dump&quot;&gt;https://github.com/axlan/fatal_core_dump&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the years, I’ve seen a couple of murder mysteries used to teach the basics of different software skills:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/cli-murder/&quot;&gt;CLI Murder Mystery&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/sql-murder-mystery/&quot;&gt;SQL Murder Mystery&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;I never wrote it up, but &lt;a href=&quot;https://deadlockempire.github.io/&quot;&gt;https://deadlockempire.github.io/&lt;/a&gt; is another fun entry in this genre&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a thought experiment, I tried to come up with the most esoteric computer skill I could package into a murder mystery. I came up with debugging a core dump.&lt;/p&gt;

&lt;h1 id=&quot;brainstorming&quot;&gt;Brainstorming&lt;/h1&gt;

&lt;p&gt;I’ve talked about core dumps before: &lt;a href=&quot;/core-dumps/&quot;&gt;Making Core Dumps Useful&lt;/a&gt;. I found the idea that an entire mystery’s worth of twists and turns could be captured in a program’s dying breath to be compelling.&lt;/p&gt;

&lt;p&gt;Initially, I wasn’t sure what kind of clues could be hidden. If the killer’s name was just sitting in an access log, that wouldn’t be particularly interesting. I knew I would need some sort of framing around the game so I could split information between the core dump itself and other sources.&lt;/p&gt;

&lt;p&gt;One of my first thoughts was that as you found answers to certain questions, you might gain access to additional source code or databases to query.&lt;/p&gt;

&lt;p&gt;My main inspiration was the way the mysteries worked in the games &lt;a href=&quot;https://obradinn.com/&quot;&gt;Return of the Obra Dinn&lt;/a&gt; and &lt;a href=&quot;https://www.thegoldenidol.com/&quot;&gt;The Case of the Golden Idol&lt;/a&gt;. Both have you exploring frozen scenes and uncovering clues that reframe the evidence you’ve already collected.&lt;/p&gt;

&lt;p&gt;Pretty early on, I settled on an airlock door controller as the program at the center of the mystery. It had a reasonable amount of complexity while also having obvious potential for murder.&lt;/p&gt;

&lt;p&gt;From there, I decided to use a sci-fi setting. The idea of a “company town” in space, using third party arbitration, jumped to mind. This helped provide motivations and justified limiting the player’s access to information.&lt;/p&gt;

&lt;h1 id=&quot;writing-the-airlock-controller&quot;&gt;Writing the Airlock Controller&lt;/h1&gt;

&lt;p&gt;Once I had the basic idea, I decided to actually write a simple airlock controller. I wanted to keep things as minimal as possible, so I wrote a C library with minimal dependencies. This may seem backwards, since I hadn’t decided on all the details of the mystery yet, but I felt it would be easier to make something feel realistic if the software wasn’t designed primarily as a puzzle.&lt;/p&gt;

&lt;p&gt;One challenge I realized right away was that I needed a way to set up the program state so it would look exactly the way I wanted when it generated the core dump.&lt;/p&gt;

&lt;p&gt;Initially, I considered having the process communicate with various sensors and servers. After some thought, though, I realized it would be simpler to send all external interactions through a library whose internals I could hide. Any dynamically linked libraries would be unavailable to the debugger unless I explicitly included them.&lt;/p&gt;

&lt;p&gt;In this project, the libraries used to generate fake interfaces that I didn’t want the player to see live in &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/tree/v0.1.2/lib&quot;&gt;https://github.com/axlan/fatal_core_dump/tree/v0.1.2/lib&lt;/a&gt;, while the only source code I intended players to examine is &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/src/airlock_ctrl.c&quot;&gt;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/src/airlock_ctrl.c&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think I went a bit overboard with the communication interface. I ended up writing an entire binary protocol for an imaginary “Station Device Network” (SDN) used for inter-device communication. In retrospect, I probably should have planned this better. It made some things needlessly complicated since I didn’t yet know the extent of what I’d want it to do.&lt;/p&gt;

&lt;p&gt;That said, this approach let me write the main controller as a loop waiting for messages on the SDN interface. I could then write the SDN library to generate the precise sequence of messages needed to set up the murder. While I considered reading these sequences from a text file, I ultimately cut out the middleman and hard coded them directly in C. See: &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/lib/sdn_interface.c#L523&quot;&gt;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/lib/sdn_interface.c#L523&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This let me create test scenarios to validate “normal” behavior, as well as capture the exact state I wanted in the core dump.&lt;/p&gt;

&lt;h1 id=&quot;figuring-out-the-mystery&quot;&gt;Figuring Out the Mystery&lt;/h1&gt;

&lt;p&gt;At some point while writing the controller, I decided I wanted the murder to be committed by abusing a buffer overflow to trigger the airlock.&lt;/p&gt;

&lt;p&gt;I wanted a balance between negligence on the part of the software designer and the cleverness of the murderer.&lt;/p&gt;

&lt;p&gt;This sent me down a series of twists and turns to make the attack plausible while still being solvable via a core dump.&lt;/p&gt;

&lt;p&gt;The first challenge was making the buffer overflow less obvious. I solved this in two ways:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Obfuscating the buffer size check&lt;/li&gt;
  &lt;li&gt;Having the attack “hide” in memory until a separate trigger was reached&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To obscure the bounds check failure, I made the buffer size a configuration parameter used at startup to allocate the buffer. I then added a debug command that could modify the configuration variable without resizing the buffer. I gated this behind multiple debug options to justify why it wouldn’t be enabled in production.&lt;/p&gt;

&lt;p&gt;From there, I wrote a series of small test programs to prototype the exploit: &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/tree/v0.1.2/minimal_example&quot;&gt;https://github.com/axlan/fatal_core_dump/tree/v0.1.2/minimal_example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To keep the exploit dormant until later, I initially explored self-modifying code (see &lt;a href=&quot;https://ephemeral.cx/2013/12/writing-a-self-mutating-x86_64-c-program/&quot;&gt;https://ephemeral.cx/2013/12/writing-a-self-mutating-x86_64-c-program/&lt;/a&gt; for a basic example). This approach had several drawbacks. First, it would cause the binary seen in the debugger to differ from the runtime version. While the core dump could technically capture this, I wanted to keep things as realistic as possible. Second, it would require making program memory writable via a system call (see &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/minimal_example/vuln_test3.py&quot;&gt;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/minimal_example/vuln_test3.py&lt;/a&gt;). At that point, I realized there was a more fundamental problem.&lt;/p&gt;

&lt;p&gt;My initial idea involved return-oriented programming (ROP): &lt;a href=&quot;https://tc.gts3.org/cs6265/tut/tut06-01-rop.html&quot;&gt;https://tc.gts3.org/cs6265/tut/tut06-01-rop.html&lt;/a&gt;. This relies on overwriting a return address on the stack, which only works if the stack is executable and other defenses are disabled. However, this is totally a non-starter for overflows on the heap. I couldn’t easily justify a stack overflow in an otherwise competently written program.&lt;/p&gt;

&lt;p&gt;However, I realized that if a heap overflow corrupted a callback pointer stored on the heap and pointed it to attack code stored on the stack, I could get the effect I wanted. If the stack memory persisted across messages, I wouldn’t need to write into program memory at all. After some experimentation, I arrived at &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/minimal_example/min_poc.c&quot;&gt;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/minimal_example/min_poc.c&lt;/a&gt; paired with &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/minimal_example/vuln_test5.py&quot;&gt;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/minimal_example/vuln_test5.py&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the end, the attack looked like this:&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;c1&quot;&gt;; This is needed to align the stack to a 16 byte offset.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; I don&apos;t update the rbp since it interferes with the core dump&apos;s backtrace.&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;rbp&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;movabs&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;r15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ADDRESS_OF_HANDLE_MESSAGE_CALLBACK&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rdi&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;OFFSET_TO_USER_ID_VALUE&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; Check if the message was sent by the murder target&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; If it&apos;s not from the target skip to &quot;.L_skip&quot;&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;DWORD&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PTR&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;USER_ID_OF_TARGET_FOR_MURDER&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;jne&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;.L_skip&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; Save the parameters passed to this function&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rdi&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;r13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rsi&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;r14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rdx&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; Call the ControlDoor function to open the outside door&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;movabs&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;rax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ADDRESS_OF_DOOR_OPEN_FUNCTION&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;DEVICE_ID_FOR_AIRLOCK_CONTROLLER&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;DEVICE_ID_FOR_OUTSIDE_DOOR&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;rax&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; Restore the original callback to erase this hack&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;rax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;THE_HEAP_ADDRESS_FOR_CALLBACK_POINTER&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;qword&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r15&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; Restore the parameters to call the message handler normally&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;rdi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r12&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;rsi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r13&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;rdx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r14&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.L_skip:&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;r15&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;pop&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;rbp&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;ret&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While it would have been ideal to make this work under fully realistic OS protections, I chose simplicity. I built the binary with extra compiler flags &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-fcf-protection=none -z execstack&lt;/code&gt; to make the stack executable and turn off some protections. Second, when I ran the executable I would do so like: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;env -i setarch $(uname -m) -R $PWD/bin/min_poc&lt;/code&gt; .&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;env -i&lt;/code&gt; cleared the environment variables so the memory offsets weren’t affected by them&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setarch $(uname -m) -R&lt;/code&gt; turned off the &lt;a href=&quot;https://en.wikipedia.org/wiki/Address_space_layout_randomization&quot;&gt;address space layout randomization&lt;/a&gt; so memory would be laid out consistently&lt;/li&gt;
  &lt;li&gt;Calling the executable with the absolute path also helped keep the memory offsets consistent between calling from the shell, and calling in GDB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the GDB side I just needed to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set exec-wrapper env -i&lt;/code&gt; to clear the environment variables. I would use GDB to find the memory offsets I’d be using in the hack, and hard code them.&lt;/p&gt;

&lt;p&gt;Once the mechanics were settled, I refactored the airlock controller to support this scenario. This required a few unrealistic memory layout decisions, but nothing too too crazy.&lt;/p&gt;

&lt;p&gt;The final piece was justifying the crash that produced the core dump. I decided the murderer would trick another person into loading malicious data into their spacesuit. If the data payload was unusually large, it wouldn’t be overwritten by subsequent users. I justified copying this data to the stack by having the airlock forward this data to the suit. Because the stack buffer didn’t go out of scope, it was suitable for storing the attack.&lt;/p&gt;

&lt;p&gt;To create an in-fiction reason for the crash, the patsy unexpectedly modifies the data, overwriting the code with actual settings data. I spent far more time than was justified making this feel plausible.&lt;/p&gt;

&lt;p&gt;I wrote a final script to generate the attack payload: &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/scripts/generate_shellcode.py&quot;&gt;https://github.com/axlan/fatal_core_dump/blob/v0.1.2/scripts/generate_shellcode.py&lt;/a&gt; . The exploit is appended to a settings string and partially corrupted by the overridden field.&lt;/p&gt;

&lt;p&gt;Here you can see the intact payload and the version overridden by a “bass volume” setting:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/fatal_core_dump/user_settings.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/fatal_core_dump/user_settings_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;making-an-rpg-maker-simulation&quot;&gt;Making an RPG Maker Simulation&lt;/h1&gt;

&lt;p&gt;I originally wanted the game to be more interactive, with dialogue trees and a graphical interface. While a website was the most accessible way to present the puzzle, I still wanted a small visual component. I ended up creating a simple pixel-art demo to illustrate the airlock and sequence of events of the murder.&lt;/p&gt;

&lt;p&gt;You can play this “game” at &lt;a href=&quot;https://www.robopenguins.com/fatal_core_dump/rpg_maker/index.html&quot;&gt;https://www.robopenguins.com/fatal_core_dump/rpg_maker/index.html&lt;/a&gt; and the source code is available at &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/tree/v0.1.2/rpg_maker_project&quot;&gt;https://github.com/axlan/fatal_core_dump/tree/v0.1.2/rpg_maker_project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I had a free copy of RPG Maker and thought it would be a good tool too make this. It was, but it has a strange learning curve. It’s trivial to make a basic RPG with the built-in assets, but trying to program complicated events or making your own assets introduces a lot of gotchas. Overall, it was probably slightly easier than using a general-purpose engine. I used a single plugin &lt;a href=&quot;https://someran.dev/rpgmaker/plugins/mz/SRD_HUDMakerUltra.js/&quot;&gt;https://someran.dev/rpgmaker/plugins/mz/SRD_HUDMakerUltra.js/&lt;/a&gt; to display console logs.&lt;/p&gt;

&lt;p&gt;Most of the logic lives in the event system, which took some time to understand. Events are tied to map tiles, and behavior is controlled via event pages with AND-ed conditions. The highest-numbered matching page wins. It was oddly reminiscent of a Zachtronics game.&lt;/p&gt;

&lt;p&gt;I spent the bulk of my time here on pixel editing. I started from &lt;a href=&quot;https://pvgames.itch.io/pvgames-sci-fi&quot;&gt;https://pvgames.itch.io/pvgames-sci-fi&lt;/a&gt; tile assets, but had trouble finding “compatible” pixel art. I ended up making a whole sprite sheet for a &lt;a href=&quot;https://feros32.itch.io/space-suit-sprite-sheet&quot;&gt;space suit&lt;/a&gt; using &lt;a href=&quot;https://www.aseprite.org/&quot;&gt;aseprite&lt;/a&gt; along with a bunch of other small tweaks.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/fatal_core_dump/rpg_pic.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2026/fatal_core_dump/rpg_pic_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;debugging-without-gdb-on-your-pc&quot;&gt;Debugging Without GDB on Your PC&lt;/h1&gt;

&lt;p&gt;One stretch goal was allowing the puzzle to be solved entirely in the browser. That required running GDB on the core dump in a web environment.&lt;/p&gt;

&lt;p&gt;I found &lt;a href=&quot;https://github.com/leaningtech/webvm&quot;&gt;https://github.com/leaningtech/webvm&lt;/a&gt; which let’s you emulate a full virtual machine in the browser. I forked it and modified a Dockerfile to include the core dump and install GDB: &lt;a href=&quot;https://github.com/axlan/webvm/blob/fatal_core_dump/dockerfiles/debian_mini&quot;&gt;https://github.com/axlan/webvm/blob/fatal_core_dump/dockerfiles/debian_mini&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I spent a bunch of time trying to get &lt;a href=&quot;https://github.com/pwndbg/pwndbg&quot;&gt;pwndbg&lt;/a&gt; working in the VM. Unfortunately, it ended up being too big to easily fit in the image.&lt;/p&gt;

&lt;p&gt;You can try it out here &lt;a href=&quot;https://axlan.github.io/webvm/&quot;&gt;https://axlan.github.io/webvm/&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;putting-it-all-together&quot;&gt;Putting It All Together&lt;/h1&gt;

&lt;p&gt;With the main artifacts done, I had to put it together into a playable puzzle.&lt;/p&gt;

&lt;p&gt;I initially tried to put the information together diegetically. I presented the information through things like emails or data sheets. Eventually, I ran out of steam and most of the evidence is simply presented as downloadable files.&lt;/p&gt;

&lt;p&gt;To be able to consistently generate the logs and core dump, I ended up wrapping the build and runtime scripts in docker containers. That way I could just run the &lt;a href=&quot;https://github.com/axlan/fatal_core_dump/tree/v0.1.2/scripts/docker_generate_site.sh&quot;&gt;https://github.com/axlan/fatal_core_dump/tree/v0.1.2/scripts/docker_generate_site.sh&lt;/a&gt; to generate all the programmatic clues for the project. I considered using a GitHub action, but stuck with just running the scripts locally.&lt;/p&gt;

&lt;p&gt;I ended up writing a lot of filler to act as red herrings. I’m not sure I made enough though, since pretty much all the logs are relevant to the murder. It was hard to balance forcing the player to sift through a bunch of pointless filler and effectively hiding the evidence.&lt;/p&gt;

&lt;p&gt;One especially tricky page to design was the one used to validate whether the player had solved the puzzle. I wanted a series of questions that would demonstrate the player’s understanding of the technical mechanisms behind the murder. I implemented this as a set of fill-in-the-blank questions, populated via an autocomplete dictionary. My concern is that this approach may require players to phrase their answers in their minds too similarly to my own in order to fill in the blanks correctly. I’m hoping to get feedback on whether these questions are easy to complete once the puzzle has been solved.&lt;/p&gt;

&lt;p&gt;I’m not a frontend guy, so that’s probably the weakest part of this project. With more time I could probably improve the presentation of the clues and the solutions entry. If I manage to get sufficient interest in this, maybe I’ll go back and try to polish things up.&lt;/p&gt;
</description>
        <pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate>
        <link>/core-dump-game/</link>
        <guid isPermaLink="true">/core-dump-game/</guid>
        
        
        <category>Software</category>
        
        <category>Game Dev</category>
        
      </item>
    
      <item>
        <title>Traffic Costumes</title>
        <description>&lt;p&gt;For Halloween this year, my family went as traffic controls. In particular, I made a traffic light costume that changes color based on my daughter’s movement.&lt;/p&gt;

&lt;p&gt;Here’s the full family:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/Group%20Costume.png&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/Group%20Costume_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and here’s the traffic light in action:&lt;/p&gt;

&lt;iframe width=&quot;1000&quot; height=&quot;515&quot; src=&quot;https://www.youtube.com/embed/ELu_2i2dp1Y&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;All code for this project can be found at &lt;a href=&quot;https://github.com/axlan/traffic-light-costume&quot;&gt;https://github.com/axlan/traffic-light-costume&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the end, I basically made a low power and cost GPS position logger with a few costume specific features.&lt;/p&gt;

&lt;h1 id=&quot;making-the-stop-sign-costume&quot;&gt;Making the Stop Sign Costume&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;Cut up some cardboard boxes into half octagons&lt;/li&gt;
  &lt;li&gt;Taped them together&lt;/li&gt;
  &lt;li&gt;Painted them red&lt;/li&gt;
  &lt;li&gt;Printed and cut out the letters using the font “Highway Gothic Narrow”&lt;/li&gt;
  &lt;li&gt;Glued the letters on&lt;/li&gt;
  &lt;li&gt;Made a border with white tape&lt;/li&gt;
  &lt;li&gt;Attached straps using bungee cords&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/signs.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/signs_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/stop_costume.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/stop_costume_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;making-the-traffic-light-costume&quot;&gt;Making the Traffic Light Costume&lt;/h1&gt;

&lt;p&gt;My original idea was to use an accelerometer to determine when the lights should change. My hypothesis was that I could use the magnitude of the x, y, z acceleration as a rough proxy for movement. When walking there’s a lot of up and down movement that would probably be sufficient to discriminate between moving and standing still.&lt;/p&gt;

&lt;p&gt;I did some prototyping using an Arduino and an old IMU. I was disappointed that it didn’t just work and there was no response from the IMU. Rather than spend a bunch of time debugging the SPI interface, IMU driver, and the hardware, I decided to go with a backup approach.&lt;/p&gt;

&lt;h2 id=&quot;testing-the-gps-receiver&quot;&gt;Testing the GPS Receiver&lt;/h2&gt;

&lt;p&gt;I had gotten a u-blox GY-NEO6MV2 GPS receiver (or probably a clone) for a couple bucks a while back. These modules communicate using the &lt;a href=&quot;https://en.wikipedia.org/wiki/NMEA_0183&quot;&gt;NMEA protocol&lt;/a&gt; over UART, which makes it straightforward to read velocity. This also meant I could log position and generate a map of the trick-or-treat route. This does come at the cost of not working indoors, and not working well if there isn’t a clear view of the sky.&lt;/p&gt;

&lt;p&gt;The first thing I did was configure and test the GPS receiver by itself. I used a USB-to-TTL adapter to connect the receiver directly to my computer and the u-blox GUI &lt;a href=&quot;https://www.u-blox.com/en/product/u-center&quot;&gt;u-center&lt;/a&gt; to get status and configure the unit. I changed the UART baud rate and customized the messages the receiver would send.&lt;/p&gt;

&lt;p&gt;To test it “in the field”, I stuffed it into a box and used an Arduino as a power supply.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/gps_test.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/gps_test_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/gps_test_open.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/gps_test_open_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I took it for a walk to get a sense of how well it would work in trick-or-treat conditions. It performed reasonably well. Positions would jump if houses or trees blocked the sky, but the velocity was stable enough when averaged over a few seconds.&lt;/p&gt;

&lt;h2 id=&quot;building-the-costume-circuit&quot;&gt;Building the Costume Circuit&lt;/h2&gt;

&lt;p&gt;For the version that went in the costume, I wanted to use an Arduino Nano. They are small and low-power, and I had one on hand. I found some older boards had inconsistent support in current Arduino tools and documentation. I had trouble finding schematics and documentation on which pins were associated with the SPI interface.&lt;/p&gt;

&lt;p&gt;Getting the GPS talking with the Arduino was straightforward using a software serial port (there was only one hardware UART, which I used for debugging). I initially used the &lt;a href=&quot;https://github.com/neosarchizo/TinyGPS&quot;&gt;TinyGPS&lt;/a&gt; library, which made basic verification easy. The baud rate I used for PC testing, 115200, was far too fast for the Arduino’s SoftwareSerial port. It constantly dropped data, so I switched down to 9600 baud.&lt;/p&gt;

&lt;p&gt;Similarly, getting the SD card working was simple; the built-in SD card library worked out of the box.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/prototype.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/prototype_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While I originally considered making the costume from scratch, that wasn’t the part I was most interested in. Building something sturdy enough to wear is its own challenge (foreshadowing for later problems), so in the end I bought a costume for $30. The original costume had a control box for the lights with a connection for each light and a common ground. A little testing showed the box was just directly wired to the LEDs, and the LEDs drew low enough current that I could drive them with Arduino GPIO pins using a 500 ohm resistor in series for each LED.&lt;/p&gt;

&lt;p&gt;While getting each component working individually went smoothly, I spent a lot more time than expected integrating everything.&lt;/p&gt;

&lt;p&gt;The first issue was that the Arduino wasn’t fast enough to log the raw GPS NMEA data to the SD card. To improve efficiency, I cached position and speed (updated once per second) and performed bulk writes every 30 seconds.&lt;/p&gt;

&lt;p&gt;Even with reduced write frequency, I still saw unexpected crashes. My best guess was that memory usage between the GPS, software serial, and SD libraries was too much for the small processor. I wrote a minimal NMEA parser that only handled the one message I needed (RMC). With that, I was able to write firmware that handled the costume’s complete functionality.&lt;/p&gt;

&lt;p&gt;The final firmware is the PlatformIO project at &lt;a href=&quot;https://github.com/axlan/traffic-light-costume&quot;&gt;https://github.com/axlan/traffic-light-costume&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the hardware assembled, I put it all together:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/inside.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/inside_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I powered everything from a USB battery pack. I had a large one that reported nearly no drain after running for a couple of hours.&lt;/p&gt;

&lt;p&gt;Once assembled, I started noticing power-related issues. The SD card would often fail to be detected. After debugging, I realized the VIN pin on some Arduino Nano boards couldn’t supply enough current for the GPS and SD card. Something in the onboard power conditioning couldn’t handle the load. Powering the SD and GPS directly from the USB 5V line fixed the issue.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/power.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/power_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, I did have some durability issues with the costume. Some of the cabling between the Arduino and the GPS proved fragile and occasionally needed to be wiggled to restore the connection. In hindsight, I should have kept the GPS closer to the microcontroller rather than mounting the receiver up near the top for a better antenna vantage point. A shorter, more secure cable run or a sturdier connector would have been a better choice. Fortunately, it held together for the actual trick-or-treating run.&lt;/p&gt;

&lt;h2 id=&quot;processing-the-data&quot;&gt;Processing the Data&lt;/h2&gt;

&lt;p&gt;The data is logged if a FAT32 formatted SD card is in the costume when it boots. It creates filenames like “log000.bin”, “log001.bin”, etc. each time it powers up. Each binary file contains latitude, longitude, and velocity as four-byte floating-point values.&lt;/p&gt;

&lt;p&gt;I created a Jupyter notebook (&lt;a href=&quot;https://github.com/axlan/traffic-light-costume/blob/master/python/analysis.ipynb&quot;&gt;https://github.com/axlan/traffic-light-costume/blob/master/python/analysis.ipynb&lt;/a&gt;) to load the data and generate plots and maps.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/map.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/traffic_light/map_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 11 Nov 2025 00:00:00 +0000</pubDate>
        <link>/traffic-light-costume/</link>
        <guid isPermaLink="true">/traffic-light-costume/</guid>
        
        
        <category>Hardware</category>
        
        <category>Electronic Art</category>
        
        <category>Software</category>
        
        <category>Costumes</category>
        
      </item>
    
      <item>
        <title>Eye Chart With Hidden Message</title>
        <description>&lt;p&gt;A wedding gift for my brother. I wanted to make something that didn’t rely on electronics, but was still an original idea. So I made an eye chart that folded into a secret message.&lt;/p&gt;

&lt;h1 id=&quot;brainstorming&quot;&gt;Brainstorming&lt;/h1&gt;

&lt;p&gt;Since my brother is an eye doctor, I immediately thought about different sorts of optical illusions. I wanted to make something that would contain a “secret” message. Some mechanisms I considered were:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ishihara_test&quot;&gt;Ishihara test&lt;/a&gt;
&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/Ishihara_9.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.instructables.com/Writing-Secret-Messages-in-Color/&quot;&gt;Hidden Color Decoder Glasses&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Shadow Sculptures&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/il_1140xN.6705559756_hl4q.jpg&quot; /&gt;
&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/00-Larry-Kagan-Animation-Steel-Wire-Master-of-Shadows-Sculptures-www-designstack-co.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hidden QR code&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/9-qr-code-artjpg_800_49.webp&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the end, I decided to go with the iconic &lt;a href=&quot;https://en.wikipedia.org/wiki/Snellen_chart&quot;&gt;Snellen Eye Chart&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/Snellen_chart.svg&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;designing-the-chart&quot;&gt;Designing the Chart&lt;/h1&gt;

&lt;p&gt;While I could simply make the letters in the chart contain a message, I had the idea that the chart could be a &lt;a href=&quot;https://en.wikipedia.org/wiki/Triptych&quot;&gt;Triptych&lt;/a&gt; (a three-panel artwork) showing the message when the sides fold shut. I’d do this by having the letters be cut through the design and have the letters seem random when seen from the front, and make the message when they flip over. My familiarity with laser cutter design is why I decided to go with this.&lt;/p&gt;

&lt;p&gt;This meant that I had to design the letters so that they would spell the message when flipped horizontally. I used a few different techniques to get the letters I wanted when the Triptych was folded shut. I could use letters with vertical line symmetry directly (H, I, O, etc.). Some letters looked a little like others when flipped (Z→S, q→p). But for other letters, I needed a way to add and subtract lines. To do this, I made the front and back use two different colors. That way I could draw the lines to add on the back, and overlap with the lines I wanted to remove. See below:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/Fold explain.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I considered a few different quotes and messages to put into the chart, mostly from movies or songs the couple shared. I ended up choosing one partly because the letters were relatively easy to flip.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What do you expect? To live happily ever after?
Yes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;The Parent Trap 1998&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that I had my work cut out for me, I wanted to automate the design layout as much as possible. I considered adding scripting to Inkscape, but decided the easiest approach would be to use the SVG manipulation library &lt;a href=&quot;https://github.com/cduck/drawsvg&quot;&gt;https://github.com/cduck/drawsvg&lt;/a&gt; and make a Python Jupyter notebook.&lt;/p&gt;

&lt;p&gt;You can see what I ended up with here:
&lt;a href=&quot;https://github.com/axlan/word_triptych/blob/master/draw.ipynb&quot;&gt;https://github.com/axlan/word_triptych/blob/master/draw.ipynb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originally, I planned to fill the entire chart with letters and control the overlapping by subtly offsetting the letters. Once I started experimenting, I decided to make my life easier by doing a layout with large gaps, and drawing an image through the center that would create the desired overlaps.&lt;/p&gt;

&lt;p&gt;Another decision I made to simplify things was to use a monospaced font. This made calculating the spacing a lot easier. Another requirement for the font was that the letters could be cut out. For letters with internal shapes (like A, B, P, etc.) the font would need bridges to look right. Initially, I considered a bunch of stencil fonts. However, these tended not to be as clear at the various sizes. In the end, I started with “Ubuntu Mono” and edited it with a program called FontForge. I followed this tutorial &lt;a href=&quot;https://www.youtube.com/watch?v=ch8KuiABczo&quot;&gt;https://www.youtube.com/watch?v=ch8KuiABczo&lt;/a&gt;. While the changes I wanted were pretty basic, I found the process a bit finicky. I also found that Inkscape was very inconsistent about reloading the font after I made changes and reinstalled it &lt;a href=&quot;https://gitlab.com/inkscape/inbox/-/issues/12513&quot;&gt;https://gitlab.com/inkscape/inbox/-/issues/12513&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since it’s an eye chart, I wanted to include the vision acuity values for each row. I started from &lt;a href=&quot;https://www.teachengineering.org/content/cub_/activities/cub_human/cub_human_lesson06_activity1_eyechart.pdf&quot;&gt;these eye chart values&lt;/a&gt; and came up with values between 20/162 and 20/54 when I measured the sizes the letters scaled to on the final design.&lt;/p&gt;

&lt;p&gt;After a few iterations of arranging the letters, I ended up with the following “simulation”. When making a design for a laser cutter, each color represents a different sort of cut. I used black for things that should be cut out, and red for lines that should be engraved.&lt;/p&gt;

&lt;p&gt;Cut SVG:
&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/notebook_open.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Fold Simulation:
&lt;img class=&quot;center&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/notebook_closed.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While trying to export the SVG for this write-up I hit a weird SVG issue. I originally wanted to post the actual SVGs, but to have it look right it would need to have my custom font available. I tried to host the file on this blog and have the SVG import it, but I hit a series of issues. First, viewing it locally was giving &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot;&gt;CORS&lt;/a&gt; errors. When I fixed that, the SVG would look OK when viewed on its own, but when it was embedded on this blog page, the custom font didn’t work. Rather than continuing to fight this, I’m just using raster images.&lt;/p&gt;

&lt;p&gt;From these generated files, I still needed to do some manual steps. I used Inkscape to draw a flower over the regions that would need overlaps. To avoid any potential issues with the font, I also converted the text to shapes.&lt;/p&gt;

&lt;h1 id=&quot;building-the-chart&quot;&gt;Building the Chart&lt;/h1&gt;

&lt;p&gt;While I have a laser cutter, this would be a bit too large for my device. Initially, I wanted to use a local maker space, but after doing some research I found a local shop that could cut all sorts of materials for less than the monthly membership. I ended up going with 1/8in MDF which cost $60. Initially, I was worried that the MDF might swell at the edges when I painted it, but it turned out fine in the end.&lt;/p&gt;

&lt;p&gt;After a couple days, I got the cut back:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/logic/open new.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/open new_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/logic/closed new.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/closed new_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was only at this point that I planned out the rest of the steps to paint and finish the design. I got some primer (Kilz original), some house paint samples, and a clear coat for the finish. I also got some hooks for hanging, and some small hinges. I painted the background coats with a small paint roller, but realized that it was going to be a pretty tedious process to paint the engraved letters and the flower in the middle. In retrospect, I should have done a raster engrave for these shapes instead of the vector outline engraving. Painting by hand would have been easier, and I could have even tried a powder coat paint &lt;a href=&quot;https://www.youtube.com/watch?v=5slQcAI2WSw&quot;&gt;https://www.youtube.com/watch?v=5slQcAI2WSw&lt;/a&gt;. I ended up needing to do three or more coats and even then it wasn’t particularly even.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/logic/plant.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/plant_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a flourish, I used gold leaf for the bride and groom names on the front. This turned out to be a bit of a pain since the leaf stuck a bit to the paint and didn’t come off cleanly. I managed to get a system of using a razor and painter’s tape to more cleanly lift off the excess.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/logic/gold leaf.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/gold leaf_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the portions being added to the flipped letters, I used painter’s tape to mask on the extra lines.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/logic/masking.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/masking_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After some touch ups, I put on the clear coat and added the hinges.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/logic/open.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/open_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/logic/closed.jpg&quot;&gt;&lt;img class=&quot;center&quot; height=&quot;50%&quot; width=&quot;50%&quot; src=&quot;https://www.robopenguins.com/assets/wp-content/uploads/2025/eye_chart/closed_thumb.webp&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end, while it came out pretty well, the “subtractive” part of the design isn’t as strong an effect as I would have liked. It works when looked at closely, but from further away, the shadow of the closed panel partly obscures the color matching.&lt;/p&gt;

&lt;iframe width=&quot;1000&quot; height=&quot;515&quot; src=&quot;https://www.youtube.com/embed/H2LF937d4Aw&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
</description>
        <pubDate>Thu, 02 Oct 2025 00:00:00 +0000</pubDate>
        <link>/eye-chart-hidden-message/</link>
        <guid isPermaLink="true">/eye-chart-hidden-message/</guid>
        
        
        <category>Personal</category>
        
      </item>
    
  </channel>
</rss>
