<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Alice Rhodes - PDA</title>
    <description><![CDATA[Alice Rhodes, aka c0debabe]]></description>
    <lastBuildDate>2026-03-02T16:18:04+00:00</lastBuildDate>
    <link href="/pda/" rel="self" type="application/rss+xml" />
    <link href="/pda/" rel="alternate" type="text/html" />
    <item>
      <guid>https://alicerhodes.com/pda/docker-compose/</guid>
      <title>Docker Compose</title>
      <pubDate>2026-03-02T00:00:00+00:00</pubDate>
      <link href="https://alicerhodes.com/pda/docker-compose/" rel="alternate" type="text/html" />
      <description><![CDATA[<p>I found a great tutorial, but it was missing a step.</p>
<!-- excerpt -->
<h3 id="great-start">Great start</h3>
<p>I absolutely love this walk through for getting set up for Rust on ESP32</p>
<p><a href="https://blog.billvanleeuwen.ca/crafting-a-hello-world-in-rust-for-the-esp-32-a-step-by-step-guide" rel="noopener noreferrer">https://blog.billvanleeuwen.ca/crafting-a-hello-world-in-rust-for-the-esp-32-a-step-by-step-guide</a></p>
<h3 id="con">Con</h3>
<p>Using Docker like that is going to create non-reusable container. That Docker command will create a new container every time you run it.</p>
<p>This means you’re gonna fill your hard drive up with a lot of builds if you compile as often as I do. Also, every new container means cargo is going to download all the libraries every time. So you’re using up space and bandwidth.</p>
<h3 id="pro-tactics">Pro-Tactics</h3>
<p>Many thanks to <a href="https://deninet.com/" rel="noopener noreferrer">SocketWench</a> for coaching in Docker basics a few years ago. I remembered I could setup reusable containers using <a href="https://docs.docker.com/compose/" rel="noopener noreferrer">Docker Compose</a>.</p>
<p>My recall was rough and I would describe the experience as someone trying a bicycle for the first time in years in falling over a few times before finally making their way down the road.</p>
<p>However, I got up and running with some help from <a href="https://www.composerize.com/" rel="noopener noreferrer">composerize</a> which you can paste someone’s docker run command into and get back the start of a docker compose file. </p>
<h3 id="composer-yml">composer.yml</h3>
<pre><code>name: lilygo-tdeck-pro-rs
services:
    idf-rust:
        stdin_open: true
        tty: true
        volumes:
            - $PWD:/home/esp/project
        image: espressif/idf-rust:esp32s3_1.90.0.0
        command: /bin/bash</code></pre>
<p>With this file you can run <code>docker compose up -d</code> to start the container. The -d flag is to say run it detached, running it in the background. The to connect to the container you can run <code>docker-compose exec idf-rust /bin/bash</code> which will drop you into <code>/home/esp</code> and you can <code>cd</code> into your project directory to compile.</p>]]></description>
    </item>
    <item>
      <guid>https://alicerhodes.com/pda/testing-1-2-3/</guid>
      <title>Testing 1 2 3 </title>
      <pubDate>2026-02-24T00:00:00+00:00</pubDate>
      <link href="https://alicerhodes.com/pda/testing-1-2-3/" rel="alternate" type="text/html" />
      <description><![CDATA[<p>It occurred to me as I was trying to clean up my code structure that it would behove me to not just clean up the code but to restructure the project to support running tests.</p>
<!-- excerpt -->
<h3 id="front-and-back">Front and Back</h3>
<p>There are parts of this project that will not have anything to do with the hardware it's running on. I'm calling that part the application and the front-end of the project.</p>
<p>Anything involving the hardware the project is running is going to be denoted as firmware and the back-end of the project. </p>
<h3 id="learning-to-test">Learning to Test</h3>
<p>I have not had the opportunity to work on any projects professional that have a formal testing process set-up. A staggering amount of web projects have not testing what so ever.</p>
<p>I learn best by doing. Show me working examples that I can run myself and tease apart and play with. Peach Pit Press has a set of books branded “Visual QuickStart Guides” and I adore those. They are perfect for how I learn best.</p>
<p>I understand at a high level why you want to test but I’ve no idea how to start it myself on my own project.</p>
<h3 id="always-be-noobin">Always be noobin’!</h3>
<p>A mutual on fedi, @federicomena@mstdn.mx, looked through what code I’ve published so far and gave me some great ideas on how to start adding in testing.</p>
<p>“You can start by deciding what would benefit the most from adding tests – code that breaks often during changes, or code that you want to refactor but not break, that sort of thing.” – Frederico</p>
<h3 id="where-i-am">Where I am</h3>
<p>I do not have too much to show for February because I am in the process of setting the up firmware code as a separate sections from the application code. I can run the firmware test from onboard the device(s) and test the application behavior and logic from my desktop because it will not depend on hardware specifics.</p>
<h3 id="where-i-m-going">Where I’m Going</h3>
<p>When it’s done have it set up to run in a test framework, then I will post the code and tests up on the repo. Hopefully the March update will be longer and have more to show. I’m moving in a couple of weeks so let’s see how much of next month gets eaten by that. Bye!</p>]]></description>
    </item>
    <item>
      <guid>https://alicerhodes.com/pda/fluconf/</guid>
      <title>FluConf</title>
      <pubDate>2026-01-31T00:00:00+00:00</pubDate>
      <link href="https://alicerhodes.com/pda/fluconf/" rel="alternate" type="text/html" />
      <description><![CDATA[<p>My "talk" for <a href="https://2026.fluconf.online/contributions/a-palm-pilot-shaped-whole-in-my-heart/" rel="noopener noreferrer">FluConf 2026</a></p>
<p>Here's my summary write up and I made a small demo video at the bottom of this page. Thank you for checking out my project.</p>
<!-- excerpt -->
<p><br></p>
<h2 id="a-palm-pilot-shaped-hole-in-my-heart">A Palm Pilot Shaped Hole In My Heart</h2>
<hr>
<h3 id="who-am-i">Who Am I?</h3>
<p>You can call me c0debabe.</p>
<p>I'm a developer, maker, and artist who needs assistive technology to counter their ADHD, whether that's pencil and paper or digital tools. I grew up using PDA style technology and I want to return to that style of digital assistance.</p>
<hr>
<h3 id="prior-art">Prior Art</h3>
<p>I am attempting to make a <a href="https://en.wikipedia.org/wiki/Personal_digital_assistant" rel="noopener noreferrer">personal digital assistant (PDA)</a> device. Before smartphones, they were the go-to type of device for personal information management (PIM). Popular devices in this category included:</p>
<div class="duo">
<div>
<h4>Palm Pilot style devices</h4>
<img src="/img/handspring-visor.jpg" alt="Handspring Visor running Palm OS; the case is translucent orange and translucent white">
</div>
<div>
<h4>Palm Treo style devices</h4>
<img src="/img/Palm-Treo-755p.jpg" alt="a burgandy and silver phone with Keyboard and color screen showing an early version of Google Maps">
</div>
</div>
<div class="duo">
<div>
<h4>Sony CLIÉ</h4>
<img src="/img/sony-clie.jpg" alt="a silver and black PDA with a color screen">
</div>
<div>
<h4>Window Mobile on Pocket PC devices</h4>
<img src="/img/pocket-pc.jpg" alt="Dell, Compaq, and HP pocket pc PDAs">
</div>
</div>
<p>And then the fire nation attacked. I mean the iPhone happened.</p>
<hr>
<h3 id="hardware-i-am-using">Hardware I am using</h3>
<div class="tri">
<div>
M5Stack Paper
<img src="/img/m5paper.webp" alt="M5 Stack Paper" class="blog-image">
</div>
<div>
M5Stack CardKB
<img src="/img/cardkb.webp" alt="M5 Stack Card Keyboard" class="blog-image">
</div>
<div>
LilyGo T-Deck Pro
<img src="/img/lilygo-tdeck-pro.webp" alt="the lilygo t-deck pro" class="blog-image">
</div>
</div>
<p>Paper Links: <a href="https://shop.m5stack.com/products/m5paper-esp32-development-kit-v1-1-960x540-4-7-eink-display-235-ppi" rel="noopener noreferrer">shop link</a> and <a href="https://docs.m5stack.com/en/core/m5paper" rel="noopener noreferrer">docs link</a></p>
<p>CardKB Links: <a href="https://shop.m5stack.com/products/cardkb-mini-keyboard-programmable-unit-v1-1-mega8a" rel="noopener noreferrer">shop link</a> and <a href="https://docs.m5stack.com/en/unit/cardkb_1.1" rel="noopener noreferrer">docs link</a> </p>
<p>T-Deck Pro Links: <a href="https://lilygo.cc/en-us/products/t-deck-pro" rel="noopener noreferrer">shop link</a> and <a href="https://github.com/Xinyuan-LilyGO/T-Deck-Pro" rel="noopener noreferrer">repo link</a></p>
<hr>
<h3 id="but-why">But Why?</h3>
<p>PDA devices were digital, but wireless networking was no where nearly as omnipresent as it is now. These devices were offline-first software (this used to be the default) that would sync to your personal computer over specialty USB connectors. </p>
<p>It has not been a full technology detox, but the last several years I've been using less of the latest and greatest. I've put my mental health first. Speaking of mental health, I got diagnosed with ADHD recently and having that additional context has helped me immensely.</p>
<p>I need that extra bit of help with remembering stuff. It can be a paper notebook or smart phone, but I want the PDA experience back. (see my <a href="https://alicerhodes.com/pda/introduction/">first PDA post</a> for more ranting)</p>
<hr>
<h3 id="challenges">Challenges</h3>
<p>As of FluCon 2026, I'm three months into this project. I have learned so much and cursed just as much.</p>
<p>Challenges in the project for me have been:</p>
<ul>
<li>this is my first embedded project</li>
<li>Megabytes and kilobytes only; you get giga-nothing</li>
<li>I have not used C/C++ since college in the 2000's</li>
<li>e-ink screens do not let you use usual UI tactics</li>
<li>it's surprisingly easily to end up in a crash and reboot loop</li>
<li>mergers and acquisitions are bad for documentation</li>
<li>Just because a library is popular doesn't mean it's easy to get it to work in your project</li>
</ul>
<p>So there has been a lot of f.a.f.o.</p>
<hr>
<h3 id="solutions-and-lessons">Solutions and Lessons</h3>
<ul>
<li>Thinking of it as a paper flip-book has made working with the UI easier</li>
<li>Starting over fine, but don't delete past attempts</li>
<li>If something is smooth and pretty it's because of iteration from clunky</li>
<li>Catching exceptions is important</li>
<li>Typography matters on e-ink</li>
<li>When working with just text you don't need much space</li>
<li>Learned how to setup callback functions</li>
</ul>
<hr>
<h3 id="where-i-am-and-what-s-next">Where I am and What's Next</h3>
<h4 id="working">Working</h4>
<ul>
<li>boots, yay</li>
<li>keeps running, double yay</li>
<li>can sync time with SNTP</li>
<li>read and write to SD card</li>
<li>data files are plain text and JSON</li>
<li>command line style interface</li>
</ul>
<p>The device "runs" now. So next is the PIM stuff.</p>
<h4 id="to-do">To-Do</h4>
<ul>
<li>Open and edit notes</li>
<li>Calendaring</li>
<li>Contacts</li>
<li>Tagging</li>
</ul>
<h4 id="nice-to-have">Nice to Have</h4>
<p>Probably much futher down the road</p>
<ul>
<li>Advanced productivity activities like<ul>
<li>setting routines</li>
<li>reminder to keep in touch</li>
<li>habit tracking</li>
</ul>
</li>
<li>GPS logging</li>
<li>On the LilyGo, which is a LORA device, add in LORA messaging </li>
</ul>
<hr>
<h3 id="diy">DIY</h3>
<p>Project Status: Under active development. </p>
<p>Future versions of this talk (and the content on my website) will have better instructions, eventually.</p>
<ul>
<li>Buy hardware</li>
<li>Find manufacturer examples</li>
<li>Clobber examples in working hello world</li>
<li>Iterate</li>
</ul>
<p>No, really though my repo is on codeberg.org:</p>
<p><a href="https://codeberg.org/c0debabe/pawb-pda" rel="noopener noreferrer">https://codeberg.org/c0debabe/pawb-pda</a></p>
<p>This is mostly for transparency. I am not ready to accept patches or requests. </p>
<p>I did want to share my base working code so others can have their own adventures. </p>
<hr>
<h3>Video</h3>
<div style="width: 100%; max-width: 400px; margin: auto;">

<div style="position: relative; padding-top: 177.78%;"><iframe title="PAWB Demo Jan 2026" width="100%" height="100%" src="https://video.infiniteloop.tv/videos/embed/iL6eHeThmC9aLPChFpJRHh?warningTitle=0" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" style="position: absolute; inset: 0px;"></iframe></div>

</div>]]></description>
    </item>
    <item>
      <guid>https://alicerhodes.com/pda/no-no-even-less/</guid>
      <title>No, no. Even less.</title>
      <pubDate>2026-01-30T00:00:00+00:00</pubDate>
      <link href="https://alicerhodes.com/pda/no-no-even-less/" rel="alternate" type="text/html" />
      <description><![CDATA[<p>I feel like every time I've shared an update here or on fedi that the UI has been overhauled. </p>
<p>It's been one of those projects.</p>
<!-- excerpt -->
<h3 id="focus">Focus</h3>
<p>I spent some time braining storming more about how I want to use this daily. I realized I wanted to be able quickly record something for my inbox. The first thing that came to mind was a command prompt. So I took that and ran with it. I decided between that and supporting multiple devices, I figured a command-line style UI would work just fine.</p>
<img src="/img/IMG_3094.jpg" alt="On the screen you can see me processing items in my inbox." class="blog-image">
<h3 id="less">Less</h3>
<p>Moving to a text-based UI also solves some of the limitations I was bumping into. Every time I would try to make the GUI look pretty, I would run out of memory and crash. I'm sure there are things I could do better to make the pretty UI work, however, I'm kicking that down the project roadmap for now. </p>
<p>Almost every time I've had to back track on something, I've had to tell myself "No, no. Less."</p>
<img src="/img/IMG_3100.jpg" alt="here's what it looks like freshly booted as of this writing" class="blog-image">
<img src="/img/IMG_3094.jpg" alt="and here's the additional hardware: cables, CardKB in a 3D printed case, my laptop" class="blog-image">
<h3 id="working-with-e-paper">Working with E-Paper</h3>
<p>With e-paper display, you are drawing on to a screen in grayscale. You draw on top of what you just drew. The effect is similar to a flip-book animation. To make this look smoother, you can build out what you want to draw in memory using the canvas-sprite in M5GFX. That way in a single smooth motion everything can drawn onto the screen in one go. </p>
<p>So if you're accepting user input from the keyboard and they hit the backspace, how do you erase the last character? You draw on top of what you just drew. </p>
<pre><code>input_buffer.back().pop_back();   // from the last character from the input being collected
MoveCursor(-1,0);                 // Move the cursor backwards 1 character width
PanelPrint( " " );                // Draw a blank space over that character (think whiteout on paper)
MoveCursor(-1,0);                 // Bring the cursor back and then keep going</code></pre>
<h3 id="fonts">Fonts</h3>
<p>I was so excited to use my favorite font, MonoLisa, but I discovered that the utilities that convert TTF and OTF fonts into VLW (the embedded format supported by the device's graphics library) does not preserve kerning (whitespace around characters). This breaks the easy-math method for handling those backspaces I was just talking about. A fixed-width font means the distance for any move the cursor makes is goign to be a fixed number. If I was using a variable width font, I'd have to pay more attention and I have ADHD.</p>
<p>Here is how I'm sizing the interface based on the device's screen and the font that is loaded.</p>
<pre><code>// Test Sprite to Measure Font Size
panel.createSprite(100,100);    // create a test sprite to draw on 
panel.setFont( AppFont );       // change the default font
panel.setCursor(0,0);           // for sanity's sake, let's put the cursor at 0,0
panel.print( "P" );             // Draw a letter
panel.print( "\nW");            // Carriage return and then a second letter
char_w = panel.getCursorX();    // Get the cursor's x and y position now
char_h = panel.getCursorY();    // based on that we know character width and line/character height
panel.deleteSprite();           // trash the sprite, we'll make the real one next</code></pre>
<h3 id="pointers">Pointers</h3>
<p>I have used pointers before, but I had not used a function pointer before this project. Not overtly and on purpose at least, because clearly by this point I have used a callback before. I just have never built a callback.</p>
<p>I'm using a function pointer to chain together functions as they get called from the main loop.</p>
<h3 id="application-structure">Application Structure</h3>
<p>Arduino projects all have two key parts: setup and loop. First everything you put in setup runs to initialize hardware and software components. Then loop runs until there's a reason to not run anymore. If you exit the loop, the device will soft restart and take you back to setup again and then loop again. </p>
<p>What calls a function from loop for something to happen is up to you. It could be a touch screen event, keyboard in put, checking a sensor for a value, or a call out to another API. Right now because I'm focusing on command-line style interaction, I'm mostly concerned with checking for keyboard input and processing that. </p>
<p>Let's walk through a small example program.</p>
<h4 id="includes-and-definitions">Includes and Definitions</h4>
<p>This project is a combination of the ESP32 libraries, Arduino framework, and the M5Stack frameworks.</p>
<pre><code>// From Arduino
#include &lt;SD.h&gt;
#include &lt;sd_defines.h&gt;
#include &lt;sd_diskio.h&gt;
#include &lt;Wire.h&gt;

// From M5STack
#include &lt;M5GFX.h&gt;
#include &lt;M5Unified.h&gt;

// A library I found to enable python-like string manipulation
#include &lt;pystring.h&gt;

static const int CARDKB_ADDR = 0x5F; // I'm using the CardKB</code></pre>
<h4 id="setup">Setup</h4>
<p>This is a basic setup function. I initialize the frameworks and the hardware.</p>
<pre><code>void setup()
{
  // put your setup code here, to run once:
  M5.begin(); // M5Unified init function
  Serial.begin(115200); // Start the serial connection for debugging
  Wire.begin(25, 32); // Init connection to M5 CardKB
  // init the SD card
  while( !SD.begin(4, SPI, 25000000) )
  {
    Serial.println( "SD Card not found." );
    // depending how much info you have on the card
    // this could be a big issue
  }
  // Init whatever you are going to use
  Serial.println( "=== setup complete ===" ); // some helpful debugging info
}</code></pre>
<h4 id="loop">Loop</h4>
<p>How many times per second loop runs depends on the processor. Fun experiment, create a variable called loop index and incriment it every loop. <a href="/img/IMG_3091.jpg">Watch how quickly is grows</a>.</p>
<p>Here's the example loop:</p>
<pre><code>void loop() {
  // put your main code here, to run repeatedly:
  M5.update(); // M5 Unified function to update stuff in the background
  if( M5.Touch.getCount() == 1 ) // check if there is a single tap event
  {
    // how you want to handle it here
  }
  Wire.requestFrom(CARDKB_ADDR, 1);
  while (Wire.available())
  {
    char c = Wire.read();
    if( c &gt; 0  ) // Characters are also number
    {
      // Handle C  :: input_buffer.back() += c;
      if( c &gt; 0 )
      {
        HandleNewCharacter( c ); // figure out how you want to hand that new character
      }
    }
  }
  // continues until it crashes or something
}</code></pre>
<p>Getting commands from the user is collecting each letter typed in until "enter" and then running what was requested. If information was requested, I can print that out and then return right back the prompt. If the command is a multi-step process though, I need a way to chain everything together. That's where the function pointer comes in. </p>
<p><code>NextAction</code> is the function pointer that I use. If it's null, I assume what has been submitted is a new command from the prompt that needs to be interpreted. If it's set to something, I call what <code>NextAction</code> is pointing at to continue the multiple process. At each step, I declare what the next one should be. </p>
<p>A great snippet to show this would be the clause for the "collect" command.</p>
<pre><code>else if ( command == "collect" )
{
  PanelPrintLn("input: ");   // Prompt the user to type in what's on their mind
  input_on = true;           // this is a flag I'm using to denote not to interrupt the user
  multiline = true;          // This prompt will allow for multi-line input
  NextAction = SaveNewItem;  // Set the NextAction pointer: save input to file
}</code></pre>
<p>Where that pointer gets used is when the user hits the submit key. I've chosen the keyboard combination of function key plus the enter key for "submit."</p>
<pre><code>else if ( letter == 0xA3 ) // fn+enter: is always the submit input command
{
  Serial.println("fn+enter");
  string joined = pystring::join( "\n", input_buffer ); // join in the input with line returns
  input_history.push_back(joined); // I'm keeping track of recent input to later enable undo
  input_buffer.clear(); // clear the buffer
  input_buffer.push_back( "" ); // set up the buffer to use again
  PanelPrintLn(" &lt;- "); // this is the symbol I use to denote end of input 
  if( NextAction == NULL ) // If there is no next action:
  {
    ReadCommand(); // treat the submitted input as a prompt command
  }
  else
  {
    NextAction(); // If there is callback action, do that now
  }
}</code></pre>
<p>The menu command shows the list of available actions. For collect I input the word cheese and it gets save to a file. Then I ask for a device status report which tells me I have 3 inbox items, 3 note items, and the battery is at 100%; here's a photo of that:</p>
<img src="/img/IMG_3102.jpg" alt="my device with the described output" class="blog-image">
<h3 id="bye">Bye</h3>
<p>Thank you for reading. I'm just noob hoping to share my adventures with other potential noobs.</p>
<p>In other exciting news, I am getting <em>new hardware</em>. I'm sure this will involve a lot of cursing. However, I'm very grateful to my fellow hackers.town townie for shipping me a LilyGo T-Deck Pro. I should have in the next few days. I will be writing about that in the update post for February.</p>
<p><a href="/pda">Back to PDA Blog</a></p>]]></description>
    </item>
    <item>
      <guid>https://alicerhodes.com/pda/palm-pilot-shaped-hole/</guid>
      <title>Palm Pilot Shaped Hole in My Heart</title>
      <pubDate>2025-12-29T00:00:00+00:00</pubDate>
      <link href="https://alicerhodes.com/pda/palm-pilot-shaped-hole/" rel="alternate" type="text/html" />
      <description><![CDATA[<p>A friend asked me what I was making with my M5 Paper and my response was “Something to fill the Palm Pilot shaped hole in my heart.”</p>
<p>This project is beating all the bad memory usage habits out of me. </p>
<!-- excerpt -->
<h3 id="training-wheels">Training Wheels</h3>
<p>I initially started this project using M5’s UIFlow 2 development tool. It’s a Blockly interface that helps you build software for your devices using the MicroPython libraries. The MicroPython is just wrappers around their C/C++ SDK. The thought was that I had not touched C or C++ since college so I should start out with something easier like Python.</p>
<p>I was wrong. I know way more than I did in college about software development and quickly ran into limitations of in both Blockly programming and using MicroPython. Both of these are set up really well for entry level programmers to tinker. However, I found the documentation and lack of parity with the C libraries to be frustrating. I think the Python around the C is doable but if you have a robust project idea, you need to be using C/C++.</p>
<p>Aside: There is developer making their take on a PDA with an M5 Paper S3. The S3 is a the slightly beefier model with more features. This reddit user has not posted in a bit but you catch their videos <a href="https://www.reddit.com/user/pivo_sokol/" rel="noopener noreferrer">on their profile</a>.</p>
<p>The order I learned my languages* is: HTML, CSS, JavaScript, C, PHP, C<ins>, Java, Bash, Python, Rust. Going back to C/C</ins> has been easier than I expected. My university grades may have been mediocre because of health issues but I definitely learned the material.</p>
<p>*No, I do not want to debate what constitutes a language.</p>
<h3 id="lessons">Lessons</h3>
<h4 id="setup-and-loop">Setup and Loop</h4>
<p>M5Stack extends existing Arduino and Espressif libraries. If you’re familiar with either of those, getting started is pretty easy. <code>setup()</code> gets called first and then <code>loop()</code> runs until told otherwise, or an unrecoverable exception.</p>
<h4 id="canvases">Canvases</h4>
<p>One of the big challenges was learning how to use the canvases. The canvas class helps you pre-render a set of graphics in memory and then quickly push them to the display all at once. The naming is a little confusing and how it works is minimally demonstrated.</p>
<p>The canvas is an object that spawns sprites: buttons, and whatever else from the M5GFX library you want to render. It handles one sprite creation at a time but onto the same canvas. So build the entire scene you want to create and then display it when you’re ready.</p>
<p>There is not stack or queue with the canvases in the sense that when you’re done with what’s on screen you request canvas.hide(). You can keep drawing over yourself. Here’s an example Arduino sketch and the output it generates:</p>
<table>
<tr>
<td style="padding: 1.5rem;">
<pre>
#include &lt;M5GFX.h&gt;
#include &lt;M5Unified.h&gt;

void setup() {
  M5.begin();

  M5Canvas fancyStuff = M5Canvas(&amp;M5.Display);
  fancyStuff.createSprite( 480, 100 );
  fancyStuff.fillSprite( 0xfcfcfc );
  fancyStuff.setTextColor( TFT_BLACK );
  fancyStuff.setFont( &amp;fonts::FreeMonoBold24pt7b );
  fancyStuff.drawString("Hello World",30,30);
  fancyStuff.pushSprite(30,30);
}

void loop() {
  M5.update();
  delay(500);
}
</pre>
</td>
<td style="padding: 1.5rem;">
<img src="/img/palm-shaped-hole-01.png" alt="My M5 Paper next to my laptop. The paper has a header that says hello world." style="display: block; width: 100%;">
</td>
</tr>
</table>
<p>You don’t have to make a new canvas for everything you want to display. The canvas is reusable. However, please note that you can queue up a bunch of sprites and push them together. If you do them in series, they will draw in series.</p>
<table>
<tr>
<td style="padding: 1.5rem;">
<pre>
...
  M5Canvas fancyStuff = M5Canvas(&amp;M5.Display);
  fancyStuff.createSprite( 480, 100 );
  fancyStuff.fillSprite( 0xfcfcfc );
  fancyStuff.setTextColor( TFT_BLACK );
  fancyStuff.setFont( &amp;fonts::FreeMonoBold24pt7b );
  fancyStuff.drawString("Hello World",30,30);
  fancyStuff.pushSprite(30,30);

  fancyStuff.createSprite(64,64);
  fancyStuff.fillSprite( TFT_BLACK );
  fancyStuff.setTextColor( TFT_WHITE );
  fancyStuff.setFont( &amp;fonts::FreeMonoBold18pt7b );
  fancyStuff.drawString("?!",13,16);
  fancyStuff.pushSprite(430,50);
...
</pre>
</td>
<td style="padding: 1.5rem;">
<img src="/img/palm-shaped-hole-02.gif" alt="My M5 Paper shown drawing the header and then the icon." style="display: block; width: 100%;">
</td>
</tr>
</table>
<h4 id="e-ink-mechanics">E-ink Mechanics</h4>
<p>Another thing that find important to note is that screen degrades with each partial redraw. Part of the way the M5 Paper draws is with lines that run the length of the screen. If you do a lot of partial redraws its becomes more clear where these are over time. Depending on your use case, this might not matter that much because you’re doing full draws of the screen often enough.</p>
<p>Here is a comparison of just the hello world header drawn versus the hello world header and overlapping boxes. I drew sequentially 100 black boxes down the side of the screen. The only editing on this images is cropping.</p>
<table>
<tr>
<td style="padding: 1.5rem;">
<img src="/img/palm-shaped-hole-03.jpg" alt="M5 Paper displaying the hello world header again" style="display: block; width: 100%;">
</td>
<td style="padding: 1.5rem;">
<img src="/img/palm-shaped-hole-04.jpg" alt="The same header again with an line of boxes down one side of the screen. This causes streaking and fuzziness to accumulate on the screen." style="display: block; width: 100%;">
</td>
</tr>
</table>
<p>A lot of the color defaults for the SDK are white foreground on a black background and I wonder if that is to hide some of this.</p>
<table>
<tr>
<td style="padding: 1.5rem;">
<img src="/img/palm-shaped-hole-05.png" alt="a screen shot of the color pallet on UI Flow 2" style="display: block; width: 100%;">
</td>
<td style="padding: 1.5rem;">
<p>16 colors? Yeah, that's just each number 0-15 in hex.</p>
</td>
</tr>
</table>
<h4 id="arduino-jetbrains-and-platform-io">Arduino, JetBrains, and Platform.io</h4>
<p>The IDE from Arduino is a great entry level IDE. It’s enough to get things done and makes board and device support relatively easy. That said, I did also try JetBrains’ C-Lion with Platform.io and that is really slick. I’ve always been of fan of JetBrains’ different IDEs and that combo is no exception. That’s the full featured IDE experience I’m used to as a professional developer.</p>
<p>Platform.io does not have full support for the M5 Paper and I had to use the profile of a board with similar specs, the LilyGo T-Display. That device does not have an SD card slot so I was blocked from getting too far.</p>
<p>I open a ticket requesting device support though, which you can read <a href="https://github.com/platformio/platform-espressif32/issues/1689" rel="noopener noreferrer">on GitHub</a>. If you would also like to see support for the M5 Paper, please star or comment on my ticket. Depending how they impliment it there may need to be a separate request for the M5 Paper S3.</p>
<h4 id="fun-with-m5gfx">Fun with M5GFX</h4>
<p>A lot of the documentation <em>is</em> the example code. So unless you go through all the examples and click through all the API pages, you might not catch it all.</p>
<ul>
<li>
<p>Fonts: There are more fonts than UI Flow 2 lets on. You can find the <a href="https://docs.m5stack.com/en/arduino/m5gfx/m5gfx_appendix#font%20list" rel="noopener noreferrer">full font list</a> available on the library’s appendix page.</p>
</li>
<li>
<p>Colors: There are defined constants for common colors you can use but these are <a href="https://docs.m5stack.com/en/arduino/m5gfx/m5gfx_appendix#common%20color%20list" rel="noopener noreferrer">not all the colors</a>. Depending on the capabilities of your display, you can also just enter the hex code for the color.</p>
</li>
<li>
<p>Bookmark this page: <a href="https://docs.m5stack.com/en/arduino/m5gfx/m5gfx_functions" rel="noopener noreferrer">M5GFX API Catalog</a>, which lists all the canvas/display related functionality. Pay attention as a lot of function have multiple definitions.</p>
</li>
<li>
<p>Gotcha: If you rotate the screen from UI Flow 2, it will rotate only display. You have to rotate your canvases separately. It also does not rotate the coordinates for touch events.</p>
</li>
<li>
<p>Gotcha: UI Flow 2 does not have any buttons, but the C/C++ SDK does. In C/C++, you can write <code>(this psuedo code) button.contains( touch.x, touch.y )</code> and it will let you know if hit the button.</p>
</li>
</ul>
<h3 id="where-am-i">Where am I?</h3>
<p>During my Python adventures, I wrote a class to handle data in hashmaps. I realized that I won’t be making up my mind anytime soon on what data to store so I may as well just have entries be different types of maps. I have started porting it to C/C++.</p>
<p>Currently I am working on a class to help me do time related functionality. I have the device, when it’s starting up, join my wifi network and sync with an NTP server. Now I’m trying to get the current date and time in my preferred formats. If I don’t bored with the time library, I’ll also try to get some time math working. I’d like to be able to questions like when is one week from now or when was 4 days ago.</p>
<table>
<tr>
<td style="padding: 1.5rem; width: 50%;">
Right now, on boot, the app pauses at a splash screen and doesn’t continue until you hit start. I made some mistakes that would cause a crash and reboot cycle. So the pour thing wouldn’t get stuck doing that, I added the splash screen. Plus, it looks rad as fuck with this artwork from RevengeDay. 
</td>
<td style="padding: 1.5rem;">
<img src="/img/palm-shaped-hole-06.jpg" alt="grafiti style art saying hackers.town and a start button" style="display: block; width: 100%;">
</td>
</tr>
</table>
<h3 id="memory-limits">Memory Limits</h3>
<p>I knew going in that memory limitations were going to be a thing. However it has been an amusing challenge do less. No less than that. Keep going. Ha! Also, I have a tendency to take things literally so the process of over thought code being reduce down to "if it looks right that's enough."</p>
<h3 id="where-am-i-going">Where am I going?</h3>
<p>Another power related quality of life item I would like is to be able to know when the device puts itself to sleep. However, the M5 Paper does not have a PMIC (Power Management Integrated Circuit), so I think I just need to specify the interval myself, and then right before that time, display a “I’m sleeping” splash screen. Also, I need something similar for shutting down.</p>
<p>Speaking of the sleep/power screens, one idea a friend gave me was to leave notes for yourself on the screen. That might be a feature out of the notebook, where you could pin a page to the sleep screen for reference.</p>
<h3 id="bye">Bye!</h3>
<p>Thank you reading my post. If it felt like it was all over the place, it’s because I’m still bouncing all over trying to get my footing on the platform. I’m hoping now that I have some traction, I can make more purposeful strides forward.</p>]]></description>
    </item>
    <item>
      <guid>https://alicerhodes.com/pda/introduction/</guid>
      <title>Introduction</title>
      <pubDate>2025-11-29T00:00:00+00:00</pubDate>
      <link href="https://alicerhodes.com/pda/introduction/" rel="alternate" type="text/html" />
      <description><![CDATA[<p>My love for technology started early. The only place better than Toys R Us was Radio Shack or a bookstore. </p>
<p>I want that feeling back. </p>
<!-- excerpt -->
<p>I am going to build an e-ink PDA from an M5 Paper to bring back that feeling. This is my first project using a  development board or embedded class device. Wish me luck!</p>
<h2 id="early-devices">Early Devices</h2>
<p>My first PDA was a sky blue electronic diary from Radio Shack. It had the date, time, telephone directory, a calculator, a dice roller, a fortune telling game, and matchmaker. This was my best friend in middle school. </p>
<p>In high school, I used a Royal digital organizer. It had a calendar, a clock, alarms, phone directories, a memo notebook, and a calculator. The calculator could do current conversions. The clock could tell you all the timezones. </p>
<p>I went through Palm PDA's in college. I remember the Palm T|X most fondly as it was the first pocket device I could connect to the campus Wifi. It was the first PDA I had that had color instead of a gray-scale display. As I was finishing my degree, I got a Palm Treo and then a Palm Pre.</p>
<h2 id="focus-and-purpose">Focus and Purpose</h2>
<p>I loved PDAs because they helped me stay organized and on task. Sure, you could play games on them but they weren't super involved games. Usually it would be something to kill time while in the supermarket checkout line. </p>
<p>Smartphones were pandora's box for us. With the ability to write powerful software and have it in our pocket, we both increased and decreased productivity. We’ve improved banking and ruined personal free time.</p>
<h2 id="looking-back-and-moving-forward">Looking Back and Moving Forward</h2>
<p>When I saw the M5 Paper the first time my brain immediately thought, “e-ink PDA.” At the time, I was heavily focused on maintaining my web development career post-divorce. I did not have the time or energy to dive into device development.</p>
<p>This year my career came to a halt when I was laid off from my job. The job market has been tough and I have not landed a new job yet. I decided I need to use this time to expand and sharpen my skills. Now is the time for the PDA project.</p>
<h2 id="device-overview">Device Overview</h2>
<p>The M5 Paper is an ESP32 embedded development board. If you’re not familiar with electronics, this means that it the hardware shipped with minimal software. There is no operating system. I am using MicroPython (Python specifically for tiny computers) to write a PDA system for the Paper. </p>
<h3 id="paper-specifications">Paper Specifications</h3>
<p>It has a ESP32-D0WDQ6-V3 board inside a plastic shell. If you’re looking on Espressif’s website it is listed as NRND, not recommended for new designs. This phase comes before end-of-life and the manufacturer recommending you use the newer models. The e-ink display is built into the shell with the board (model number is ED047TC1 and it will show up as a LilyGo display depending on the tools you're using) and is 540 pixels by 960 pixels in 16 shades of gray. It weighs only 81.9g or 2.89 ounces. Smaller and lighter than most iPhones, the Paper is about the size of an index card or fieldnotes notebook: 118.6 x 67.0 x 10.0 mm or 4.67 x 2.63 x 0.39 inches. It has Wifi and Bluetooth, as well as three I2C grove ports and a microSD card slot. Like most embedded boards, the on-board storage is measly compared to smartphones, but the SD card slot can support up to 16GB. You can catch the full details at: <a href="https://docs.m5stack.com/en/core/m5paper_v1.1" rel="noopener noreferrer">https://docs.m5stack.com/en/core/m5paper_v1.1</a></p>
<h3 id="software-development">Software Development</h3>
<p>The python SDK M5 provides is called UI Flow 2. It’s a Blockly based web IDE for their MicroPython library. The core framework is written in C. Applications can be written in C but Python is more my style. It’s a personal preference more than anything else. Set up involved flashing their UI Flow 2 developer image to the device. Then you can load software and manage the device in Google Chrome over USB. It makes me sad that Chrome is the only browser supporting serial device management but that’s another blog post. </p>
<h3 id="file-management">File Management</h3>
<p>The firmware they have you flash to work with UI Flow 2 sets up a /system partition, a /flash partition, and you can also access a /sd partition if you have a microSD card in the device. UI Flow lets you manage the files in the /flash partition to files like additional python libraries, fonts, and image files.</p>
<p><strong>Warning!</strong> Adding files via the web IDE and then removing them from your project does not actually remove the files from your device. Make sure to manually remove them from the device or you'll run out of storage.</p>
<p>You can access the /system partition on the device with more robust developer tools. I was able to poke around by installing PyCharm and getting the MicroPython Tools plugin. Connecting to the device over serial with those tools shows the /flash and /system partitions. </p>
<p>I did the obvious thing and changed the image shown on boot:</p>
<img src="/img/img_2513_resized.1878347c369b8e4a0c97e3e80f5c3945.jpg" alt="an image of the M5 paper with my custom boot image of a raccoon saying Greetings" loading="lazy" decoding="async" width="384" height="384">
<p><br></p>
<h3 id="software-goals">Software Goals</h3>
<p>The device can be set to boot into main.py immediately. So my idea is to develop a python application to act as the launcher and bring in various other libraries to act as the features of the PDA. We will see how far I can get, but my dream line-up would include:</p>
<ul>
<li>calendar and schedule functionality</li>
<li>to-list functionality</li>
<li>journaling</li>
<li>habit tracking</li>
<li>weather forecast</li>
<li>contacts directory</li>
<li>keep-in-touch functionality that helps remind you who you haven’t talked to in a while</li>
<li>a calculator pad akin to Soulver for iPad, see <a href="https://soulver.app/" rel="noopener noreferrer">https://soulver.app/</a></li>
<li>notepad / notebook</li>
<li>password vault</li>
<li>e-book and document reader</li>
<li>web-page cacher (maybe something like Wallabag)</li>
</ul>
<p>Old school Palm fans will remember that caching web pages to read while on the go was a common workflow. </p>
<p>These are productivity tools we’ve all come to know and love, sans the ability lose oneself in pocket gaming or doomscrolling.</p>
<p>My initial focus is on the core PIM (personal information management) functionality of calendaring and contact management. I am currently reading up on the ability of the vcard and iCalendar file standards. I’m writing basic classes for handling these because I do not need the full feature set of the standards, which would be more of a “use an existing library” situation. I plan for data syncing to be file transfers on/off the SD card initially with the eventual goal of also backing up over wifi to a personal server. </p>
<h2 id="scope">Scope</h2>
<p>The scope of the project is “personal.” I do not intend to make and sell any devices nor do I plan on supporting the software an open source project. I will eventually share the code, but that’s it.</p>
<h2 id="bye">Bye!</h2>
<p>Thanks for reading my project introduction. I hope to have an update for everyone either over the winter holidays or shortly after with information on how the calendaring and contact management are progressing. </p>
<p><a href="/pda">Back to PDA Blog</a></p>]]></description>
    </item>
  </channel>
</rss>
