<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>poleguy.com</title><link href="https://poleguy.com/blog/" rel="alternate"></link><link href="https://poleguy.com/blog/feeds/all.atom.xml" rel="self"></link><id>https://poleguy.com/blog/</id><updated>2026-03-13T09:46:00-05:00</updated><entry><title>John Henry and the Steam Hammer</title><link href="https://poleguy.com/blog/john-henry-and-the-steam-hammer.html" rel="alternate"></link><published>2026-03-13T09:46:00-05:00</published><updated>2026-03-13T09:46:00-05:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2026-03-13:/blog/john-henry-and-the-steam-hammer.html</id><summary type="html">&lt;h1&gt;John Henry and the Steam Hammer.&lt;/h1&gt;
&lt;h2&gt;What does conventional FPGA development look like?&lt;/h2&gt;
&lt;p&gt;If you are working on an FPGA design and you are an expert, you already know roughly how to build it. You often just slap together some code and hit build, then look at the error messages …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;John Henry and the Steam Hammer.&lt;/h1&gt;
&lt;h2&gt;What does conventional FPGA development look like?&lt;/h2&gt;
&lt;p&gt;If you are working on an FPGA design and you are an expert, you already know roughly how to build it. You often just slap together some code and hit build, then look at the error messages and fix them. You find what broke and write up some tests to analyze it. You leave the test in place to make sure it can't happen again. You hit a blocker. You throw out the original code and try a different way, etc.&lt;/p&gt;
&lt;p&gt;You work in a loop like that until you get something that is roughly working. &lt;/p&gt;
&lt;p&gt;The development loop converges because there is an expert FPGA developer providing an &lt;em&gt;error signal&lt;/em&gt; to &lt;strong&gt;hammer&lt;/strong&gt; the loop into convergence.&lt;/p&gt;
&lt;p&gt;Then you polish if you want. Or you don't. These are smaller more focused polishing control loops: same story, lighter blows with the &lt;strong&gt;hammer&lt;/strong&gt; to force it into the right direction. You have to determine the direction.&lt;/p&gt;
&lt;p&gt;Then you declare it done and move on.&lt;/p&gt;
&lt;p&gt;But the whole time you really are just &lt;strong&gt;hammering&lt;/strong&gt; at it. &lt;/p&gt;
&lt;p&gt;Humans suck at writing elegant, syntactically correct and functional code the first time through. We only get it right with the help of a feedback loop. (And then we fix it by re-writing git history to make it look elegant. It's always a lie.)&lt;/p&gt;
&lt;h2&gt;What changes when you add an LLM.&lt;/h2&gt;
&lt;p&gt;Guess how you can &lt;strong&gt;hammer&lt;/strong&gt; faster? With an LLM.&lt;/p&gt;
&lt;p&gt;But don't think it's not just a &lt;strong&gt;hammer!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you get an LLM involved in the development loop &lt;em&gt;you&lt;/em&gt; can &lt;strong&gt;hammer&lt;/strong&gt; out things faster. Now you are not limited by your ability to figure out when to throw out the original code and try something else, but by when to &lt;em&gt;stop&lt;/em&gt; throwing out the original code and trying something else.&lt;/p&gt;
&lt;p&gt;You're also limited by how fast you are able to read the code the LLM produces and judge if it is better than the last iteration that was slopped together, or if it has hit a blocker.&lt;/p&gt;
&lt;p&gt;And as you get into the polishing stage, you need to be extra careful that you understand how everything works so you can start to limit the scope of the LLM's changes, because it can easily touch things that are outside of the scope you intended. (Simulated annealing comes to mind.)&lt;/p&gt;
&lt;p&gt;(You almost never will be correcting syntax errors any more, but to focus on that 'efficiency gain' seems pretty silly.)&lt;/p&gt;
&lt;p&gt;Does adding an LLM make development more efficient? It depends mostly on how often you lose the thread. A modern LLM can easily keep more context in its short term memory than you can! If you lose the thread, the development loop has broken open and &lt;em&gt;will&lt;/em&gt; diverge. &lt;/p&gt;
&lt;p&gt;If your development loop diverges, the LLM &lt;em&gt;cannot&lt;/em&gt; push the development loop back on its own, because it &lt;em&gt;cannot reason&lt;/em&gt; (it can only simulate text that looks like reasoning) and therefore it will only &lt;strong&gt;hammer&lt;/strong&gt; in the right direction if the training data has more examples of the right direction than the wrong, or if &lt;em&gt;you&lt;/em&gt; stop it from &lt;strong&gt;hammering&lt;/strong&gt; the wrong way. If you're in novel development territory, it will have no useful training data. Think about this and draw your own conclusion.&lt;/p&gt;
&lt;p&gt;So almost every time it diverges you'll have to first notice, then suddenly revert to &lt;em&gt;conventional&lt;/em&gt; &lt;strong&gt;hammering&lt;/strong&gt; at it. And if you let the LLM &lt;strong&gt;hammer&lt;/strong&gt; too much, you might have a lot of mental catching up to do to be able to see which direction to swing the &lt;strong&gt;hammer&lt;/strong&gt; to drive the loop to where you want it.&lt;/p&gt;
&lt;h2&gt;Let's Summarize&lt;/h2&gt;
&lt;p&gt;LLM's are just a more efficient &lt;strong&gt;hammer&lt;/strong&gt; this can go very well if you can keep the LLM &lt;strong&gt;hammering&lt;/strong&gt; in the right direction.&lt;/p&gt;
&lt;h2&gt;Hard Data&lt;/h2&gt;
&lt;p&gt;Some research that actually measured it shows that developers perceive about a 20% increase in productivity, and the hard metrics show about a &lt;a href="https://arxiv.org/abs/2507.09089"&gt;20% decrease.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(Regular Reminder:  Humans are subject to &lt;a href="https://en.wikipedia.org/wiki/Cognitive_bias"&gt;cognitive bias.&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;I suspect the likely &lt;a href="https://www.anthropic.com/research/estimating-productivity-gains"&gt;upper limit&lt;/a&gt; of productivity gains is shown in this paper, because the authors are highly motivated to predict a particular outcome.&lt;/p&gt;
&lt;p&gt;Others predict similar productivity gains and note that half of the "gains" are expected to be &lt;a href="https://www.nber.org/papers/w34836"&gt;due to layoffs.&lt;/a&gt;&lt;/p&gt;</content><category term="FPGA"></category><category term="Software"></category><category term="FPGA"></category><category term="Verilog"></category><category term="LLM"></category><category term="AI"></category></entry><entry><title>Compose Key</title><link href="https://poleguy.com/blog/compose-key.html" rel="alternate"></link><published>2026-02-15T21:25:00-06:00</published><updated>2026-02-15T21:25:00-06:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2026-02-15:/blog/compose-key.html</id><summary type="html">&lt;h1&gt;Compose Key&lt;/h1&gt;
&lt;p&gt;Today, was I inspried by seeing a character that I had never seen before. Can you believe it‽&lt;/p&gt;
&lt;p&gt;&lt;a href="https://infosec.exchange/@RnDanger/116071816467737505"&gt;https://infosec.exchange/@RnDanger/116071816467737505&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Months earlier I had played around with setting up the compose key on my keyboard for Spanish accents, etc. but got distracted and it didn't …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Compose Key&lt;/h1&gt;
&lt;p&gt;Today, was I inspried by seeing a character that I had never seen before. Can you believe it‽&lt;/p&gt;
&lt;p&gt;&lt;a href="https://infosec.exchange/@RnDanger/116071816467737505"&gt;https://infosec.exchange/@RnDanger/116071816467737505&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Months earlier I had played around with setting up the compose key on my keyboard for Spanish accents, etc. but got distracted and it didn't stick.&lt;/p&gt;
&lt;p&gt;Today I am trying to set it up again and see how well it works for me in the coming days and months.&lt;/p&gt;
&lt;p&gt;I also want to be able to easily type the "interrobang!"&lt;/p&gt;
&lt;p&gt;I figured the compose key would be able to do it. And although it's not on the lists of standard compose key cheat-sheets, it does work by hitting compose+!?&lt;/p&gt;
&lt;p&gt;I edited /etc/default/keyboard with this line to make it stick:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;XKBOPTIONS=&amp;quot;compose:caps&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then ran this command to make it immediate:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;setxkbmap -option compose:caps
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All done.&lt;/p&gt;
&lt;p&gt;¡Y ahora también puedo usar acentos en español!&lt;/p&gt;
&lt;h1&gt;Other resources consulted&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://duncanlock.net/blog/2013/05/03/how-to-set-your-compose-key-on-xfce-xubuntu-lxde-linux/"&gt;https://duncanlock.net/blog/2013/05/03/how-to-set-your-compose-key-on-xfce-xubuntu-lxde-linux/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://andyf.me/compose-key.html"&gt;https://andyf.me/compose-key.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/imasaru/25e0dbbca037ae6ab4c2e757b71c88be"&gt;https://gist.github.com/imasaru/25e0dbbca037ae6ab4c2e757b71c88be&lt;/a&gt;&lt;/p&gt;</content><category term="Linux"></category><category term="Linux"></category><category term="Software"></category></entry><entry><title>Rat Car</title><link href="https://poleguy.com/blog/rat-car.html" rel="alternate"></link><published>2025-07-22T05:38:00-05:00</published><updated>2025-07-22T05:38:00-05:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2025-07-22:/blog/rat-car.html</id><summary type="html">&lt;h1&gt;A call for help.&lt;/h1&gt;
&lt;p&gt;A mastodon user calls for help.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://social.tchncs.de/@Blort/114866484344816671"&gt;https://social.tchncs.de/@Blort/114866484344816671&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;How to interpret step 2:&lt;/h1&gt;
&lt;h2&gt;1. Arduino to the motorboard:&lt;/h2&gt;
&lt;p&gt;wire between &lt;/p&gt;
&lt;p&gt;(ENA) UNO.~D5 and L298N.ENA &lt;/p&gt;
&lt;p&gt;(ENB) UNO.~D6 and L298N.ENB&lt;/p&gt;
&lt;p&gt;(N4) UNO.D7 and L298N.IN4&lt;/p&gt;
&lt;p&gt;(N3) UNO.D8 and …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;A call for help.&lt;/h1&gt;
&lt;p&gt;A mastodon user calls for help.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://social.tchncs.de/@Blort/114866484344816671"&gt;https://social.tchncs.de/@Blort/114866484344816671&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;How to interpret step 2:&lt;/h1&gt;
&lt;h2&gt;1. Arduino to the motorboard:&lt;/h2&gt;
&lt;p&gt;wire between &lt;/p&gt;
&lt;p&gt;(ENA) UNO.~D5 and L298N.ENA &lt;/p&gt;
&lt;p&gt;(ENB) UNO.~D6 and L298N.ENB&lt;/p&gt;
&lt;p&gt;(N4) UNO.D7 and L298N.IN4&lt;/p&gt;
&lt;p&gt;(N3) UNO.D8 and L298N.IN3&lt;/p&gt;
&lt;p&gt;(N2) UNO.~D9 and L298N.IN2&lt;/p&gt;
&lt;p&gt;(N1) UNO.~D10 and L298N.IN1&lt;/p&gt;
&lt;h2&gt;2. Connect the batteries to both the Arduino and to the motorboard&lt;/h2&gt;
&lt;p&gt;UNO.VIN and battery+ (red)&lt;/p&gt;
&lt;p&gt;UNO.GND and battery- (black)&lt;/p&gt;
&lt;p&gt;L298N.+12V and battery+ (red)&lt;/p&gt;
&lt;p&gt;L298N.+5V and battery+ (red)&lt;/p&gt;
&lt;h2&gt;3. Connect the Arduino to the motorboard&lt;/h2&gt;
&lt;p&gt;(Done in step 1)&lt;/p&gt;
&lt;h2&gt;4. Mount three 10MOhm resistors to the breadboard&lt;/h2&gt;
&lt;p&gt;R1.1 to BB.GND&lt;/p&gt;
&lt;p&gt;R2.1 to BB.GND&lt;/p&gt;
&lt;p&gt;R3.1 to BB.GND&lt;/p&gt;
&lt;h2&gt;5. Connect the Arduino to the breadboard&lt;/h2&gt;
&lt;p&gt;UNO.A4 to R1.2&lt;/p&gt;
&lt;p&gt;UNO.A3 to R2.2&lt;/p&gt;
&lt;p&gt;UNO.A2 to R3.2&lt;/p&gt;
&lt;h2&gt;6. Connect three insulated wires (each a different color) to the breadboard. (Later these will be attached to the car body.)&lt;/h2&gt;
&lt;p&gt;R1.2 to BLUE (right)&lt;/p&gt;
&lt;p&gt;R2.2 to YELLOW (left)&lt;/p&gt;
&lt;p&gt;R3.2  to GREEN (forward)&lt;/p&gt;
&lt;h2&gt;7. Connect an insulated wire from the Arduinoâ€™s 5V pin (Later this will be attached to the metal base plate in the car)&lt;/h2&gt;
&lt;p&gt;UNO.5V to RED (base plate)&lt;/p&gt;
&lt;h1&gt;Other resources consulted&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://social.tchncs.de/@Blort/114866484344816671"&gt;https://social.tchncs.de/@Blort/114866484344816671&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.arduino.cc/resources/pinouts/A000005-full-pinout.pdf"&gt;https://docs.arduino.cc/resources/pinouts/A000005-full-pinout.pdf&lt;/a&gt;
&lt;a href="https://docs.arduino.cc/hardware/uno-rev3/"&gt;https://docs.arduino.cc/hardware/uno-rev3/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.arduino.cc/resources/pinouts/A000066-full-pinout.pdf"&gt;https://docs.arduino.cc/resources/pinouts/A000066-full-pinout.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lastminuteengineers.com/l298n-dc-stepper-driver-arduino-tutorial/"&gt;https://lastminuteengineers.com/l298n-dc-stepper-driver-arduino-tutorial/&lt;/a&gt;&lt;/p&gt;</content><category term="Hardware"></category><category term="Hardware"></category></entry><entry><title>neorv32</title><link href="https://poleguy.com/blog/neorv32.html" rel="alternate"></link><published>2025-06-02T07:43:00-05:00</published><updated>2025-06-02T07:43:00-05:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2025-06-02:/blog/neorv32.html</id><summary type="html">&lt;h1&gt;A call for help.&lt;/h1&gt;
&lt;p&gt;A mastodon user calls for help.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mastodon.social/@PaulaMaddox/114609318930864994"&gt;https://mastodon.social/@PaulaMaddox/114609318930864994&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;I accept&lt;/h1&gt;
&lt;p&gt;I ask for more details.&lt;/p&gt;
&lt;h1&gt;They reply&lt;/h1&gt;
&lt;p&gt;The details are clear, concise, and surprisingly self-aware. This is going great!&lt;/p&gt;
&lt;h1&gt;I help&lt;/h1&gt;
&lt;p&gt;I produce the requested file.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://poleguy.com/blog/neorv32/neorv32_raw_exe.bin"&gt;neov32_raw_exe.bin&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;How'd I do it?&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://poleguy.com/blog/neorv32/history.txt"&gt;a …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;h1&gt;A call for help.&lt;/h1&gt;
&lt;p&gt;A mastodon user calls for help.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mastodon.social/@PaulaMaddox/114609318930864994"&gt;https://mastodon.social/@PaulaMaddox/114609318930864994&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;I accept&lt;/h1&gt;
&lt;p&gt;I ask for more details.&lt;/p&gt;
&lt;h1&gt;They reply&lt;/h1&gt;
&lt;p&gt;The details are clear, concise, and surprisingly self-aware. This is going great!&lt;/p&gt;
&lt;h1&gt;I help&lt;/h1&gt;
&lt;p&gt;I produce the requested file.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://poleguy.com/blog/neorv32/neorv32_raw_exe.bin"&gt;neov32_raw_exe.bin&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;How'd I do it?&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://poleguy.com/blog/neorv32/history.txt"&gt;a very truthful history.txt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The key thing I needed to learn was that the tools needed to be installed by a tool called xpm. The documentation for this is actually pretty good and lists the exact steps and commands needed. However it's also very verbose. A hello-world style tutorial would be more appropriate as a true starting point.&lt;/p&gt;
&lt;p&gt;The gist of it:&lt;/p&gt;
&lt;p&gt;get the neorv32 repo&lt;/p&gt;
&lt;p&gt;install xpm&lt;/p&gt;
&lt;p&gt;install the toolchain using xpm&lt;/p&gt;
&lt;p&gt;initialize the neorv32 directory with xpm&lt;/p&gt;
&lt;p&gt;modify the path so the toolchain can be found&lt;/p&gt;
&lt;p&gt;change to the blink example directory.&lt;/p&gt;
&lt;p&gt;run make bin to produce the output&lt;/p&gt;
&lt;h1&gt;The truth&lt;/h1&gt;
&lt;p&gt;But that's not how I did it. I went about it the other way.&lt;/p&gt;
&lt;p&gt;I changed to the blink example directory.&lt;/p&gt;
&lt;p&gt;I saw a makefile so I ran make.&lt;/p&gt;
&lt;p&gt;I saw the makefile error was complaining about not finding riscv-none-elf-gcc so I downloaded that.&lt;/p&gt;
&lt;p&gt;I then looked at the documentation for that to see how to install it.&lt;/p&gt;
&lt;p&gt;That required xpm so I installed that.&lt;/p&gt;
&lt;p&gt;Fortunately the install instructions are good, and also listed that it required running an init command and modifying the path, so I did that as well.&lt;/p&gt;
&lt;p&gt;Then I went back and ran make and it worked.&lt;/p&gt;
&lt;h1&gt;How long did it take?&lt;/h1&gt;
&lt;p&gt;About 20 minutes, not counting writing the blog post.&lt;/p&gt;
&lt;h1&gt;How much would I charge.&lt;/h1&gt;
&lt;p&gt;Free of course! &lt;/p&gt;
&lt;p&gt;Alternatively, you could just round up my usual rate up to the nearest thousand:&lt;/p&gt;
&lt;p&gt;20 min * 1hr/60min * $1000/hr = $333.33&lt;/p&gt;
&lt;p&gt;That might cover health insurance costs in the US, lawyers, marketing, sales, tariffs, inflation, etc.&lt;/p&gt;
&lt;h1&gt;Other resources consulted&lt;/h1&gt;
&lt;p&gt;The initial links provided:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/stnolting/neorv32/tree/main/sw/example/demo_blink_led"&gt;https://github.com/stnolting/neorv32/tree/main/sw/example/demo_blink_led&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v14.2.0-3/xpack-riscv-none-elf-gcc-14.2.0-3-win32-x64.zip"&gt;https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v14.2.0-3/xpack-riscv-none-elf-gcc-14.2.0-3-win32-x64.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This second one was for windows, so I just used it as a starting point to find the linux equivalent.&lt;/p&gt;
&lt;p&gt;Additional web searches done:&lt;/p&gt;
&lt;p&gt;None! The initial links seemed to lead the way nicely.&lt;/p&gt;
&lt;p&gt;Other links followed:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/stnolting/neorv32/blob/main/sw/example/demo_blink_led/makefile"&gt;https://github.com/stnolting/neorv32/blob/main/sw/example/demo_blink_led/makefile&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/stnolting/neorv32/tree/main/sw/example/demo_blink_led"&gt;https://github.com/stnolting/neorv32/tree/main/sw/example/demo_blink_led&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/stnolting/neorv32"&gt;https://github.com/stnolting/neorv32&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/"&gt;https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://xpack.github.io/riscv-none-elf-gcc/releases/"&gt;https://xpack.github.io/riscv-none-elf-gcc/releases/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://xpack.github.io/docs/getting-started/"&gt;https://xpack.github.io/docs/getting-started/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://xpack-dev-tools.github.io/"&gt;https://xpack-dev-tools.github.io/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://xpack-dev-tools.github.io/riscv-none-elf-gcc-xpack/"&gt;https://xpack-dev-tools.github.io/riscv-none-elf-gcc-xpack/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://xpack-dev-tools.github.io/riscv-none-elf-gcc-xpack/docs/getting-started/"&gt;https://xpack-dev-tools.github.io/riscv-none-elf-gcc-xpack/docs/getting-started/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://xpack-dev-tools.github.io/riscv-none-elf-gcc-xpack/docs/install/"&gt;https://xpack-dev-tools.github.io/riscv-none-elf-gcc-xpack/docs/install/&lt;/a&gt;&lt;/p&gt;</content><category term="Software"></category><category term="Software"></category></entry><entry><title>Declarative Magic</title><link href="https://poleguy.com/blog/declarative-magic.html" rel="alternate"></link><published>2025-01-21T06:21:00-06:00</published><updated>2025-01-21T06:21:00-06:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2025-01-21:/blog/declarative-magic.html</id><summary type="html">&lt;h1&gt;Declarative Magic&lt;/h1&gt;
&lt;p&gt;A colleague suggested that we should add to our compile.txt flow an ability for the tool
to automatically identify any folder path in the compile.txt file that contains the text /sim_lib/ as a simulation library path and do some under-the-hood handling (e.g. copying modelsim.ini …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Declarative Magic&lt;/h1&gt;
&lt;p&gt;A colleague suggested that we should add to our compile.txt flow an ability for the tool
to automatically identify any folder path in the compile.txt file that contains the text /sim_lib/ as a simulation library path and do some under-the-hood handling (e.g. copying modelsim.ini) in order to make it work.&lt;/p&gt;
&lt;p&gt;This immediately set off my "hmm that seems to magic for me" sensor. &lt;/p&gt;
&lt;p&gt;However, I couldn't express why it seems to grate on me. So I decided to compose a post to think about it.&lt;/p&gt;
&lt;p&gt;So, do I dislike this, or not?&lt;/p&gt;
&lt;p&gt;The first thing I did was google "declarative vs magic" and read an AI Slop definition of declarative programming:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Declarative programming is a programming paradigm that uses "magic" code to achieve a desired 
state, rather than defining the exact steps to get there. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I guess I like that idea okay. I don't like this definition one bit though. The AI Slop generator went on to add another definition:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In declarative programming, the programmer describes what they want to achieve, rather than how 
to achieve it. The system then figures out how to get there. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The funny thing is, my question is not about programming really. We're doing the programming imperatively under the hood. So this is maybe about "declarative configuration?"&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;P.S. the extreme of declarative programming is to invent new domain specific languages (DSL)
https://stackoverflow.com/questions/1784664/what-is-the-difference-between-declarative-and-imperative-paradigm-in-programmin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But I actually might be okay with creating a domain specific language. We're not quite doing that 
either.&lt;/p&gt;
&lt;p&gt;I keep having the word "discoverability" jump into my head. It seems to me that having our code 
look for /sim_lib/ in the compile.txt file is not something anyone is going to be able to discover.&lt;/p&gt;
&lt;p&gt;That's the magic that rubs me the wrong way, I think. But why is that?&lt;/p&gt;
&lt;p&gt;I think a more concrete example might be in order:&lt;/p&gt;
&lt;p&gt;Let's look at what this compile.txt can do right now, and what has changed?&lt;/p&gt;
&lt;p&gt;One thing right off the bat is that the compile.txt file used to only contain files. Now it contains paths as well. It used to be that having a path that is not a file would raise an error. Now it won't. That's a big change.&lt;/p&gt;
&lt;p&gt;The original idea of the compile.txt was to explicitly specify the files to be compiled and their order. This was such that we didn't have to depend on any under the hood magic of modelsim, ISE, Vivado, etc. in determining dependencies.&lt;/p&gt;
&lt;p&gt;But then we added a bunch of pragma style commands started with a backtick ("`"). E.g. "if sim","end_default_library","end","xil_sim_lib_for_msim", "default_library"&lt;/p&gt;
&lt;p&gt;Clearly these are not discoverable, because I didn't even know we had default_library and 
end_default_library in there. &lt;/p&gt;
&lt;p&gt;Also, these backtick commands are essentially the definition of a DSL, aren't they? Is that cool? Is that the best solution?&lt;/p&gt;
&lt;p&gt;I think that's a separate problem, and touches on the need for good documentation if you're trying 
to implement a new DSL. Not only do you need good documentation, you also need good discoverability 
of your documentation.&lt;/p&gt;
&lt;p&gt;Next, thought: the overview of this PR says what we are changing in the PR, not why we are doing it.&lt;/p&gt;
&lt;p&gt;One thing we are doing is removing the old `xil_sim_lib_for_msim backtick command. What exactly was wrong with this command? What were it's benefits? Why is it a problem?&lt;/p&gt;
&lt;p&gt;The old behavior hid some magic under the hood. The 'xil_sim_lib_for_msim accepted a relative path 
for the library folder. Under the hood it would know to check both /opt/sim_lib and /misc/sim_lib 
as the base for these relative paths.&lt;/p&gt;
&lt;p&gt;I think the idea there was that we could add additional magic if the location changed or if new 
tools required other special handling. But in the end it maybe just made it harder to debug when 
the files didn't exist and things failed.&lt;/p&gt;
&lt;p&gt;But why not just change it to support (or require) an absolute path for `xil_sim_lib_for_msim? I mean, isn't it modelsim-library-only magic anyway? Other types of paths aren't supported anyway. Right?&lt;/p&gt;
&lt;p&gt;Now, the DSL no longer has an explicit command `xil_sim_lib_for_msim but instead infers it from an element in the path. But it treats it effectively the same way it used to. &lt;/p&gt;
&lt;p&gt;Is that what bothers me about this? I prefer explicit magic? I don't like implicit magic?&lt;/p&gt;
&lt;p&gt;I'm totally okay with this process doing magic things behind the hood. The magic doing these things is imperatively programmed, and the source is there to inspect. So it's not really magic at all. You see the `backtick command you grep the code to find this backtick, you can see what it does. (Documentation and discoverability notwithstanding.)&lt;/p&gt;
&lt;p&gt;But if the code magically calls this functionality based on string matching in the compile.txt file, then it's no longer clear that magic is going on. Anywhere in the code I could accidentally use a path that matches the magic string and suddenly it will change the behavior. It's not explicit, it's implicit. e.g.&lt;/p&gt;
&lt;p&gt;The old way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;`xil_sim_lib_for_msim Xilinx/sim_library_1234/
relative/adder.vhd
relative/comparator.vhd
relative/mux.v
other.v
top.vhd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The new way &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/misc/sim_lib/Xilinx/sim_library_1234/
relative/adder.vhd
relative/comparator.vhd
relative/mux.v
other.v
top.vhd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ah, wait! This makes clear another issue that might rub me the wrong way: relative paths. Essentially the `xil_sim_lib_for_msim is standing in for an environment variable that sets the correct base path, e.g. in a bash style:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;XIL_SIM_LIB_FOR_MSIM=/misc/sim_lib
echo $XIL_SIM_LIB_FOR_MSIM/Xilinx/sim_library_1234/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The old explicit `xil_sim_lib_for_msim allowed the library to handle the possibility of different install locations on different OS's, different machines, or different tools. And it made it evident that some magic was happening for this special case, and why (the string msim is pretty clearly calling out a modelsim specific line of magic).&lt;/p&gt;
&lt;p&gt;But the new way is now locked down to a specific path. That prevents flexibility in the future. But maybe changing paths is just a hypothetical concern?&lt;/p&gt;
&lt;p&gt;So why is it bad to have an absolute path in a file that is by-default relative? Why does this rub me the wrong way? Is it simply not elegant? &lt;/p&gt;
&lt;p&gt;How should it be done?&lt;/p&gt;
&lt;p&gt;Maybe split the difference? Maybe: &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;`xil_sim_lib_for_msim /misc/some_lib/Xilinx/sim_library_1234/
relative/adder.vhd
relative/comparator.vhd
relative/mux.v
other.v
top.vhd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This indicates yet another two oddities:&lt;/p&gt;
&lt;p&gt;First, I put in some_lib instead of sim_lib, but it should handle this fine. It's explicit now, which is good, as there is no magic matching on the phrase sim_lib, and thus no artificial requirement for the location of the path. That's an improvement, I think, as it is more universal.&lt;/p&gt;
&lt;p&gt;Second, it concerns me that if we have to move the installed library in the future, e.g. to support multiple incompatible versions, that this specific line will become problematic, and building an old project will fail and will be difficult to debug.&lt;/p&gt;
&lt;p&gt;Third, it makes me question what the behavior of a relative path. What should it do in this case?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;`xil_sim_lib_for_msim Xilinx/sim_library_1234/
relative/adder.vhd
relative/comparator.vhd
relative/mux.v
other.v
top.vhd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It should then look in the current directory, right? That's probably sane, and could handle nicely the case of a legacy library that has been archived with the project.&lt;/p&gt;
&lt;p&gt;Shouldn't the framework, the environment, and the tools handle the location of the simulation library for the user? Why should the user need to know the exact path of the simulation libraries? Why is this in this file at all? Most synthesis/simulation tools configure this separately. &lt;/p&gt;</content><category term="Software"></category><category term="Software"></category></entry><entry><title>Port Knocking</title><link href="https://poleguy.com/blog/port-knocking.html" rel="alternate"></link><published>2025-01-15T02:39:00-06:00</published><updated>2025-01-15T02:39:00-06:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2025-01-15:/blog/port-knocking.html</id><content type="html">&lt;h1&gt;Port Knocking&lt;/h1&gt;
&lt;p&gt;This was link rotted on &lt;a href="https://en.wikipedia.org/wiki/Port_knocking"&gt;wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This was hidden behind a 'paywall'.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://poleguy.com/blog/Port_Knocking_in_C.pdf"&gt;Implementing a Port Knocking System In C&lt;/a&gt;&lt;/p&gt;</content><category term="Software"></category><category term="Software"></category></entry><entry><title>Contact Info</title><link href="https://poleguy.com/blog/contact-info.html" rel="alternate"></link><published>2024-03-05T18:28:00-06:00</published><updated>2024-03-05T18:28:00-06:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2024-03-05:/blog/contact-info.html</id><summary type="html">&lt;h1&gt;Contact Info&lt;/h1&gt;
&lt;p&gt;poleguy.com is the personal website of&lt;/p&gt;
&lt;p&gt;Nicholas Dietz&lt;/p&gt;
&lt;p&gt;b. 10-31-1977&lt;/p&gt;
&lt;h2&gt;cellular&lt;/h2&gt;
&lt;p&gt;630-460-1424&lt;/p&gt;
&lt;h2&gt;home&lt;/h2&gt;
&lt;p&gt;708-848-3835&lt;/p&gt;
&lt;h2&gt;address&lt;/h2&gt;
&lt;p&gt;244 S Wesley Ave&lt;/p&gt;
&lt;p&gt;Oak Park, IL 60302&lt;/p&gt;
&lt;h1&gt;rules&lt;/h1&gt;
&lt;p&gt;If you are a commercial entity, please put the above phone numbers and address on your do not call list.&lt;/p&gt;
&lt;p&gt;Otherwise you are …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Contact Info&lt;/h1&gt;
&lt;p&gt;poleguy.com is the personal website of&lt;/p&gt;
&lt;p&gt;Nicholas Dietz&lt;/p&gt;
&lt;p&gt;b. 10-31-1977&lt;/p&gt;
&lt;h2&gt;cellular&lt;/h2&gt;
&lt;p&gt;630-460-1424&lt;/p&gt;
&lt;h2&gt;home&lt;/h2&gt;
&lt;p&gt;708-848-3835&lt;/p&gt;
&lt;h2&gt;address&lt;/h2&gt;
&lt;p&gt;244 S Wesley Ave&lt;/p&gt;
&lt;p&gt;Oak Park, IL 60302&lt;/p&gt;
&lt;h1&gt;rules&lt;/h1&gt;
&lt;p&gt;If you are a commercial entity, please put the above phone numbers and address on your do not call list.&lt;/p&gt;
&lt;p&gt;Otherwise you are my friend and I ask that you please call between 9am-5pm CST.&lt;/p&gt;</content><category term="Contact"></category></entry><entry><title>ppprs may 2023 rebuild</title><link href="https://poleguy.com/blog/ppprs-may-2023-rebuild.html" rel="alternate"></link><published>2023-04-12T22:12:00-05:00</published><updated>2023-04-12T22:12:00-05:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2023-04-12:/blog/ppprs-may-2023-rebuild.html</id><summary type="html">&lt;p&gt;I have a nominally working simulation of a PI controller for the quadrature current in my scratch designed #fpga motor controller. Simulated in #ghdl and #cocotb. And the #xilinx ISE build fits! &lt;/p&gt;
&lt;p&gt;So I'm back to looking at the blown up hardware. Just pulled the scratch designed motor controller out …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have a nominally working simulation of a PI controller for the quadrature current in my scratch designed #fpga motor controller. Simulated in #ghdl and #cocotb. And the #xilinx ISE build fits! &lt;/p&gt;
&lt;p&gt;So I'm back to looking at the blown up hardware. Just pulled the scratch designed motor controller out of the Ice Cream Truck... I don't see a blown FET yet, but I saw a flash and pop the last time I worked on it, so I know it's in there somewhere. &lt;/p&gt;
&lt;p&gt;Race is on May 20th in #chicago Come out and help me!
&lt;a href="http://powerracingseries.org/"&gt;http://powerracingseries.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And an extra picture of the belt drive:&lt;/p&gt;
&lt;p&gt;&lt;img alt="ict sim" src="https://poleguy.com/blog/ict_sim.png"&gt;
Traces from a gtkwave view of a ghdl sim showing a feedback waveform starting low and back high again and a pwm_level output of an open-loop PI controller that looks like it should drive the error to zero correctly.&lt;/p&gt;
&lt;p&gt;&lt;img alt="three phases" src="https://poleguy.com/blog/three_phases.jpeg"&gt;
Side view of one motor controller PCB showing three phase legs. Lots of wires flying around. FETs are mounted under PCBs so you can't inspect them without disassembly.&lt;/p&gt;
&lt;p&gt;&lt;img alt="motor out" src="https://poleguy.com/blog/motor_out.jpeg"&gt;
Two scratch built motor controllers mounted to a heat sink mounted to a plywood box enclosure. Out of the kart and sitting on the concrete floor. Three phase wires hang out from each side. Lots of ribbon cables and colorful dupont wires in a messy configuration with velcro ties.&lt;/p&gt;</content><category term="PPPRS"></category><category term="PPPRS"></category><category term="Software"></category><category term="Hardware"></category><category term="FPGA"></category></entry><entry><title>Career Growth</title><link href="https://poleguy.com/blog/career-growth.html" rel="alternate"></link><published>2023-03-17T09:16:00-05:00</published><updated>2023-03-17T09:16:00-05:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2023-03-17:/blog/career-growth.html</id><summary type="html">&lt;h1&gt;Career Growth&lt;/h1&gt;
&lt;p&gt;It's "APG" time at my company.&lt;/p&gt;
&lt;p&gt;I find myself clicking into this fa-eqbx-saasfaprod1.fa.ocs.oraclecloud.com app, and I see the words "career growth"? Hmm.. what does that bring to mind?&lt;/p&gt;
&lt;p&gt;I have one title 'click' above me to hit "principal engineer." Is that the end of …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Career Growth&lt;/h1&gt;
&lt;p&gt;It's "APG" time at my company.&lt;/p&gt;
&lt;p&gt;I find myself clicking into this fa-eqbx-saasfaprod1.fa.ocs.oraclecloud.com app, and I see the words "career growth"? Hmm.. what does that bring to mind?&lt;/p&gt;
&lt;p&gt;I have one title 'click' above me to hit "principal engineer." Is that the end of the line? &lt;/p&gt;
&lt;p&gt;Or I can move to management. Yuck. I could probably do it, but that's not the type of work I've trained for in the last 45 years. Am I more valuable to Corporate if I fill out a bunch of APG's and go to a bunch of meetings? Will they pay me more?&lt;/p&gt;
&lt;p&gt;I want to make sure my pay stays lower than what Corporate thinks my value is. Is there any way I can increase my value to Corporate? What's the limit of what they might pay me? It's a hardware company that hasn't figured out how to sell software licenses. Hardware doesn't scale. And Corporate's software models don't scale either. Therefore Corporate will never pay me an obscene salary. That's fine. It promotes stability in my career, which I value. I'm not a software engineer and didn't go into that career for a reason. I wanted to build real things.&lt;/p&gt;
&lt;p&gt;I could go to the high frequency trading firms downtown doing FPGA work and I understand the salaries are very lucrative. But what maybe 2x tops? And at what cost? All the hours of my day? Seeing my family? My soul?&lt;/p&gt;
&lt;p&gt;In hind sight I should have been less conservative with my career and money starting back in 1999. I should have started my own side hustle early in my career and built my own stuff and maybe by now I wouldn't have to be working for the few very rich guys at the top such that they become a bit richer.&lt;/p&gt;
&lt;p&gt;My last pay raise was one of the biggest in my life and it didn't keep up with inflation. I started my career in 1999. &lt;a href="https://www.inflationtool.com/us-dollar/1999-to-present-value?amount=110000&amp;amp;year2=2023&amp;amp;frequency=yearly"&gt;$200k today is only $110k in 1999 dollars&lt;/a&gt;. I made significantly more in the 2001-2003 time frame than I make today after adjustment. It's crazy that I haven't beat those first few years of income after 24 years. &lt;/p&gt;
&lt;p&gt;Hockey is getting expensive, college is coming up in a few years. Oak Park taxes are a bit spendy. I'm driving two beat up old cars from 2006 that leak oil.&lt;/p&gt;
&lt;p&gt;I've never asked for a pay raise in my life, and I'm not asking for one now. But maybe I can change something to suddenly have Corporate decide I'm worth a lot more after the change? Any ideas? Besides having people report to me, I shure can't think of anything.&lt;/p&gt;</content><category term="Career"></category><category term="Career"></category></entry><entry><title>Pelican</title><link href="https://poleguy.com/blog/pelican.html" rel="alternate"></link><published>2023-01-16T15:28:00-06:00</published><updated>2023-01-16T15:28:00-06:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2023-01-16:/blog/pelican.html</id><summary type="html">&lt;p&gt;todo: write up starting to use pelican&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/getpelican/pelican/tree/master/pelican/themes/notmyidea"&gt;https://github.com/getpelican/pelican/tree/master/pelican/themes/notmyidea&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;question was: how to start from notmyidea template and modify it?&lt;/p&gt;
&lt;p&gt;answer:
first tried google, but downloading just one theme requires a clone on github... no download zip option.
so I figured it's …&lt;/p&gt;</summary><content type="html">&lt;p&gt;todo: write up starting to use pelican&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/getpelican/pelican/tree/master/pelican/themes/notmyidea"&gt;https://github.com/getpelican/pelican/tree/master/pelican/themes/notmyidea&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;question was: how to start from notmyidea template and modify it?&lt;/p&gt;
&lt;p&gt;answer:
first tried google, but downloading just one theme requires a clone on github... no download zip option.
so I figured it's already in my cenv:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;find | grep notmy
cp -r cenv/lib/python3.8/site-packages/pelican/themes/notmyidea/ theme
cd theme/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Software"></category><category term="Software"></category></entry><entry><title>Mock Neopixels on Raspberry Pi controlled by calendar</title><link href="https://poleguy.com/blog/mock-neopixels-on-raspberry-pi-controlled-by-calendar.html" rel="alternate"></link><published>2023-01-08T14:58:00-06:00</published><updated>2023-01-08T14:58:00-06:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2023-01-08:/blog/mock-neopixels-on-raspberry-pi-controlled-by-calendar.html</id><summary type="html">&lt;h1&gt;Addressable LEDs&lt;/h1&gt;
&lt;p&gt;I wanted to make my engineering lab space look more like a hacker lair and less like a hoarder situation. So I decided to buy some addressable LEDs this year. &lt;/p&gt;
&lt;p&gt;So I contacted the guy who did &lt;a href="https://www.youtube.com/watch?v=eeN_GEldXOY"&gt;this christmas light show&lt;/a&gt;, because I work with him and it …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Addressable LEDs&lt;/h1&gt;
&lt;p&gt;I wanted to make my engineering lab space look more like a hacker lair and less like a hoarder situation. So I decided to buy some addressable LEDs this year. &lt;/p&gt;
&lt;p&gt;So I contacted the guy who did &lt;a href="https://www.youtube.com/watch?v=eeN_GEldXOY"&gt;this christmas light show&lt;/a&gt;, because I work with him and it seems he has some experience. I asked him:&lt;/p&gt;
&lt;p&gt;"I want to light my lab space this year. I'd like to make it look like a hacker space from a movie, and maybe have it do different colors depending on the status of teams, builds, emails and other work related stuff. I'd like to do it all DIY style with no cloud service dependencies. I can use a raspberry pi, arduino, desktop linux box, etc. as the controller, and I'm happy to write the code in python/etc. I'm okay with wifi/bluetooth/zigbee/wired etc. but there are so many choices, I don't know where to start. I have a USB controlled power switch and some colored LED bulbs I've used in the past, but I'd like to find a system that works smoothly and reliably and is easy to repair/replace/upgrade. I'd like to start with some colored lighting to shine on some walls. What can you recommend to start?"&lt;/p&gt;
&lt;p&gt;He replied:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://kno.wled.ge"&gt;https://kno.wled.ge&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;"I have used WLED with ESP8266 dev boards and pixel strips. I had them controlling the lights outside, and then later brought them inside to use as lights under the kitchen cabinets. pixels come in 2 forms - strips and bullet nodes. the strips have adhesive backing and are great in places where you want the lights in the straight line (like under kitchen cabinets). strips are difficult to cut into custom lengths and still keep them waterproof so I don't use them outside any more. bullet nodes are what I use outside. WLED supports MQTT. that means you can control it with automation software like OpenHAB or Home Assistant (HA). something like this will work for you:"&lt;/p&gt;
&lt;p&gt;"the Christmas lights outside use &lt;a href="https://github.com/FalconChristmas/fpp"&gt;FPP&lt;/a&gt; on a Pi and BB as the main controllers, and then use xLights on a Mac to create the pixel control data. that's easier to use for elaborate setups like mine with thousands of pixels and light/audio sync. I use OpenHAB/MQTT to monitor and control the devices"&lt;/p&gt;
&lt;p&gt;&lt;img alt="LED pixels connected to WLED on ESP8266 connected to switch connected to Pi/Linux running HA or OpenHAB" src="https://poleguy.com/blog/Jones.png"&gt;&lt;/p&gt;
&lt;p&gt;I had a Raspberry Pi 4 from an old project, and some arduinos, but in the end I wanted this to be controlled by a wired ethernet device as the brain, so I opted for the Pi. &lt;/p&gt;
&lt;h1&gt;Connecting Hardware on Vacation&lt;/h1&gt;
&lt;p&gt;I was heading on vacation so I started putting everything I thought I needed for this project in a box. When I got to the pi4 I realized I should set up all the software before I left. &lt;/p&gt;
&lt;p&gt;I was surprised that NOOBs was no longer a thing since the last time I used the pi. The installer on linux is now very nice. I googled "raspberry pi without monitor" because I didn't want to have to find a monitor keybeard and mouse, but would have my laptop and my phone hotspot with me.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.tomshardware.com/reviews/raspberry-pi-headless-setup-how-to,6028.html"&gt;https://www.tomshardware.com/reviews/raspberry-pi-headless-setup-how-to,6028.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tom's Hardware did me well with this tutorial, except that the image shows it installing a 32-bit OS, and the raspberry Pi imager did me wrong by also making that the default. I have a Pi 4, and Tom's guide says you "can" use the 64-bit version. It really might be better to say you "should" use the 64-bit version, as I eventually had to reinstall the 64-bit version to get OpenCV to run. On the other hand, I guess it's good that they opt for the highest compatibilty OS as their default in the installer, because it gives the lowest risk for a new user. It installs quickly, no big deal.&lt;/p&gt;
&lt;p&gt;The pi imager is really nice in adding a settings button that can put an ssh key on the ssd and also a wifi password. It makes it supre easy to give it the key of the current user on my laptop. That's brilliant. &lt;/p&gt;
&lt;p&gt;It also let me enter my phone's hotspot password and the device showed up immediately under the .local domain. That's smooth like butter. Big improvement over having a monitor and mouse!&lt;/p&gt;
&lt;p&gt;I headed to Cleveland.&lt;/p&gt;
&lt;p&gt;I googled and found my first step should be to hook up the LEDs and light a single LED. Walk before run, right? &lt;/p&gt;
&lt;p&gt;I started with this tutorial, using the simplest wiring diagram, because I had carefully selected a 5V string of LEDs. &lt;/p&gt;
&lt;p&gt;&lt;a href="https://learn.adafruit.com/neopixels-on-raspberry-pi?view=all"&gt;https://learn.adafruit.com/neopixels-on-raspberry-pi?view=all&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;board&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;neopixel&lt;/span&gt;
&lt;span class="n"&gt;pixels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;neopixel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeoPixel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's pretty simple. I like to start with something like that.&lt;/p&gt;
&lt;p&gt;I powered them from a phone charger and an old USB cable that I cut the wire off of and stripped with a screwdriver. I used some screw down terminals to hold them in place. The data and ground pin I connected to GPIO18 and ground on the PI by releasing the pins from the three pin connectors using the pointy tip of a multimeter probe. (I was on vacation, so I didn't have all my proper tools. I soldered it all up nicely when I got home.)&lt;/p&gt;
&lt;p&gt;It was only a few minutes of copy and paste to get that going. I then wrote a quick LED light chaser loop and showed my kids. "Cool" they said, but clearly weren't too impressed.&lt;/p&gt;
&lt;h1&gt;Creating a Mock to test without Hardware&lt;/h1&gt;
&lt;p&gt;When I got home I had the pi in a box and wanted to keep working on the software side. I decided it would be great to use an emulator. I found &lt;a href="https://raspberrypi.stackexchange.com/questions/117496/writing-software-for-the-rpi-without-hardware-mocking-stubbing"&gt;this stack overflow question asking about mocking the adafruit-circuitpython-neopixel library&lt;/a&gt;, and thought that would be neat. It wasn't answered, but I had also seen a couple &lt;a href="https://hackaday.io/project/179916-neopill"&gt;hackaday&lt;/a&gt; projects(link to another?) that would display stuff on the PC. &lt;/p&gt;
&lt;p&gt;I set off to make an emulator that fakes out the adafruit-circuitpython-neopixel for use on linux. I don't think people normally do mocking, but I think it's a good idea. &lt;/p&gt;
&lt;p&gt;Unfortunately the neopill project only works with a hardware serial port capture box (the blue pill). I decided to use only the back end of it. It didn't take long to get a &lt;a href="https://github.com/poleguy/fire_led/blob/master/mock_neopixel.py"&gt;mock&lt;/a&gt; working. First I found the adafruit neopixel python source code and made a copy. I then modified the output functions to print to the screen rather than write to GPIO.&lt;/p&gt;
&lt;p&gt;The next step was to get the LED's displayed on the screen. I first set up the hackaday.io project and got the LED string configured and showing on the PC. This meant modifying this project to accept data from the adafruit library, rather than from the serial port.&lt;/p&gt;
&lt;p&gt;If you run &lt;code&gt;python test_mock_neopixel.py&lt;/code&gt; on the PC it'll display example LED sequences in a little window.&lt;/p&gt;
&lt;p&gt;Also if you run &lt;code&gt;python fire_led.py --mock&lt;/code&gt; on the PC, it'll display the LEDs of the actual raspberry pi code in a little window. This can be used for software debugging if you can't actually see the LEDs, or don't have the pi available.&lt;/p&gt;
&lt;h1&gt;Visual Art should be created Visually.&lt;/h1&gt;
&lt;p&gt;Krita&lt;/p&gt;
&lt;p&gt;OpenCV&lt;/p&gt;
&lt;h1&gt;Stuff Usually Glossed Over&lt;/h1&gt;
&lt;h2&gt;Run as Root at Boot&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://learn.sparkfun.com/tutorials/how-to-run-a-raspberry-pi-program-on-startup#method-3-systemd"&gt;https://learn.sparkfun.com/tutorials/how-to-run-a-raspberry-pi-program-on-startup#method-3-systemd&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://serverfault.com/questions/806617/configuring-systemd-service-to-run-with-root-access"&gt;https://serverfault.com/questions/806617/configuring-systemd-service-to-run-with-root-access&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The raspberry pi needs to run this stuff at boot. There are several ways of doing this, and I tried several. But this application requires the script to run as root. The simplest solution was to use a systemd process.&lt;/p&gt;
&lt;h2&gt;messaging between server and raspberry pi.&lt;/h2&gt;
&lt;p&gt;I wanted my desktop machine to control this, so I needed to message with the PI. I wanted this to be secure, so I decided to use SSH for messaging. &lt;/p&gt;
&lt;p&gt;I also decided to use just ssh and the filesystem to pass messages, rather than some other fancy protocol.&lt;/p&gt;
&lt;h2&gt;Save your SD card.&lt;/h2&gt;
&lt;p&gt;I know that writing to disk repeatedly will kill an SD card, so I decided to write to a ram disk. Googling this solution
didn't give great answers. They said to put stuff in /run/user/1000/ but that stuff was getting deleted because that user is
not a system user and not logged in.&lt;/p&gt;
&lt;p&gt;So I moved it to /var/shm/ and found I was having the exact same problem.&lt;/p&gt;
&lt;p&gt;I'd write the file there, but the LED's wouldn't light up the right color because the file wasn't there. Debugging this was no fun, because the program was running as a systemd process. I temporarily stopped the process and ran it via ssh to debug it. I added output messages in the cases to determine what state it was in. It was seeing the files that were written to SD did not exist.&lt;/p&gt;
&lt;p&gt;Something was deleting them. &lt;/p&gt;
&lt;h2&gt;Systemd deleting stuff&lt;/h2&gt;
&lt;p&gt;I needed to edit this file TBD to prevent systemd from trying to "clean up" and deleting my files.&lt;/p&gt;
&lt;h2&gt;systemd restarting too fast.&lt;/h2&gt;
&lt;p&gt;It wasn't clear why this was happening at first. I rate limited to prevent it at startup.&lt;/p&gt;
&lt;p&gt;todo: add link to stackoverflow&lt;/p&gt;
&lt;h2&gt;Watchdog&lt;/h2&gt;
&lt;p&gt;If you don't feed the watchdog by touching a file via ssh, the LED's will go into a special flashing mode indicating that there is no valid input.&lt;/p&gt;
&lt;h2&gt;tmux&lt;/h2&gt;
&lt;p&gt;I'm currently running the update process under tmux so it doesn't die when I shut down my laptop. This is easier to do than setting up another systemd process on my desktop. Eventually I should, but it makes it easier to debug just running in tmux.&lt;/p&gt;
&lt;h2&gt;wget in python can be done ten wrong ways that seem to work&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/35115513/python-bad-request-in-get-but-wget-and-curl-work"&gt;https://stackoverflow.com/questions/35115513/python-bad-request-in-get-but-wget-and-curl-work&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It's still not clear to me why I can't use requests to replace wget. The trouble with wget is that it works in the sunny day case, but when something goes wrong it can hang forever. I need something that will timeout gracefully.&lt;/p&gt;
&lt;p&gt;I ended up using:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/poleguy/fire_led/blob/master/check_calendar/check_calendar.py"&gt;https://github.com/poleguy/fire_led/blob/master/check_calendar/check_calendar.py&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# a `bytes` object&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;working with dates&lt;/h2&gt;
&lt;p&gt;working with dates in python can be tricky.&lt;/p&gt;
&lt;p&gt;TypeError: can't compare offset-naive and offset-aware datetimes&lt;/p&gt;
&lt;h2&gt;don't upload secrets to github&lt;/h2&gt;
&lt;p&gt;I suppose the url to my .ics file is not exactly a secret, but I don't want everyone to read it and get it blocked by microsoft or something dumb. But since I wanted it saved with my script, and I wanted a working script I had a bit of a problem.&lt;/p&gt;
&lt;p&gt;Once you put it in the git repo it's not impossible to remove it. There are scripts to clean up your repo. But I had just started, so instead, I ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rm -rf ./git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then started over with &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Calendar integration&lt;/h1&gt;
&lt;p&gt;Now controlling LED's is no fun if they aren't actually doing something meaningful. So besides lighting up my garage lab space to try to look like a movie hacker lair, I thought they should also warn me if I'm about to miss a meeting.&lt;/p&gt;
&lt;p&gt;At first I was planning to scrape my status info from teams, but that got complicated. Specifically, I couldn't figure out how to easily intercept the calls that periodically read the calendar data. I think I'd have to develop something more advanced that &lt;a href="https://github.com/poleguy/teams_green"&gt;Teams Green&lt;/a&gt; because I think I'd need a dev tools extension, not a regular chrome extension in order to intercept and read the teams data. Maybe another day.&lt;/p&gt;
&lt;p&gt;But I determined that from outlook I can share a busy/free calendar to any email address as a link. This link lets you download a .ics file. &lt;/p&gt;
&lt;p&gt;I then spent a bunch of time trying to figure out how to read the .ics file to determine if I'm busy or not. You'd think this would be easy, but no. The libraries for reading .ics in python are pleanty, but they are pretty naive. I went down a number of paths that produced incorrect results because they don't handle repeating events corectly.&lt;/p&gt;
&lt;p&gt;The final solution works great though.&lt;/p&gt;
&lt;h2&gt;Parsing .ics files&lt;/h2&gt;
&lt;p&gt;https://stackoverflow.com/questions/3408097/parsing-files-ics-icalendar-using-python&lt;/p&gt;
&lt;p&gt;This shouldn't be as hard as it is. The You really need to just use the &lt;a href="https://pypi.org/project/recurring-ical-events/"&gt;recurring-ical-events package&lt;/a&gt;. The base icalendar package doesn't handle recurring events for you. &lt;/p&gt;
&lt;p&gt;Unfortunately there aren't any good complete examples for recurring-ical-events. I always like to start from a complete working example, so to find a good example I had to search through their codebase. This is why FOSS software is great. I found what I wanted here.&lt;/p&gt;
&lt;p&gt;The ics package, the vobject package, the icalevents package were dead ends neither provided an easy way to see if a meeting was about to start.&lt;/p&gt;
&lt;p&gt;todo: add links to all the stackoverflow entries I used to get my solution working.&lt;/p&gt;
&lt;p&gt;Now my LED's flash red and white two minutes before every meeting.&lt;/p&gt;
&lt;h1&gt;Final Result&lt;/h1&gt;
&lt;p&gt;Here's my repo with it all, including installation instructions:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/poleguy/fire_led"&gt;https://github.com/poleguy/fire_led&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Footnotes:&lt;/p&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/rogerdahl/ws2812b-neopixel-emulator"&gt;https://github.com/rogerdahl/ws2812b-neopixel-emulator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fine for arduino. In cpp. Not great for python/raspberry pi.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="nv"&gt;@github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;having11&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;NeoPixel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Emulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.hackster.io/gatoninja236/neopixel-emulator-with-python-f233c3"&gt;https://www.hackster.io/gatoninja236/neopixel-emulator-with-python-f233c3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;works okay. needs small change for pyglet 2.0&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hackaday.io/project/179916-neopill"&gt;https://hackaday.io/project/179916-neopill&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;hardware based emulator.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;4&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/marcmerlin/ArduinoOnPc-FastLED-GFX-LEDMatrix"&gt;https://github.com/marcmerlin/ArduinoOnPc-FastLED-GFX-LEDMatrix&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This seems to be a full mock for many different arduino backends. But not for Raspberry Pi.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;5&lt;/p&gt;
&lt;p&gt;https://www.makeuseof.com/tag/emulate-raspberry-pi-pc/&lt;/p&gt;
&lt;p&gt;This is a full "rpi on pc" emulation using QEMU. But does it do the hardware GPIO... uh... I think not.&lt;/p&gt;</content><category term="Hardware"></category><category term="Hardware"></category><category term="Software"></category></entry><entry><title>notes on fixing old photoswipe bug</title><link href="https://poleguy.com/blog/notes-on-fixing-old-photoswipe-bug.html" rel="alternate"></link><published>2022-12-21T18:55:00-06:00</published><updated>2022-12-21T18:55:00-06:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2022-12-21:/blog/notes-on-fixing-old-photoswipe-bug.html</id><summary type="html">&lt;p&gt;Test
&lt;meta charset="utf-8" /&gt;
&lt;title&gt;notes on fixing old photoswipe bug&lt;/title&gt;&lt;/p&gt;
&lt;p&gt;My website was no longer rendering correctly on android... I tarcked it down today to a
  bug in PhotoSwipe 3.0.5 that I've been using on Android since way back when.&lt;/p&gt;
&lt;p&gt;This led me here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://photoswipe.com/"&gt;https://photoswipe.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But updating seemed like …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Test
&lt;meta charset="utf-8" /&gt;
&lt;title&gt;notes on fixing old photoswipe bug&lt;/title&gt;&lt;/p&gt;
&lt;p&gt;My website was no longer rendering correctly on android... I tarcked it down today to a
  bug in PhotoSwipe 3.0.5 that I've been using on Android since way back when.&lt;/p&gt;
&lt;p&gt;This led me here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://photoswipe.com/"&gt;https://photoswipe.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But updating seemed like a pain. Lots of new features I didn't need.&lt;/p&gt;
&lt;p&gt;So I looked into mobile debugging (again):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/22753960/javascript-alert-box-not-displaying-on-android"&gt;https://stackoverflow.com/questions/22753960/javascript-alert-box-not-displaying-on-android&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I added a way to fake out console.log() on mobile.&lt;/p&gt;
&lt;p&gt;Then I added a try around the code that was erroring out and a console.log(error.stack) printout the stack.&lt;/p&gt;
&lt;p&gt;That led to a line with this regex:&lt;/p&gt;
&lt;p&gt;/Android (\d+.\d+)/&lt;/p&gt;
&lt;p&gt;Which I tested on:
  &lt;a href="https://regex101.com/"&gt;https://regex101.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With this:
  Mozilla/5.0 (Linux; Android 10; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.128 Mobile Safari/537.36&lt;/p&gt;
&lt;p&gt;from here:
    &lt;a href="https://www.whatismybrowser.com/guides/the-latest-user-agent/chrome"&gt;https://www.whatismybrowser.com/guides/the-latest-user-agent/chrome&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I changed the line to this:
  /Android (\d+.?\d+)/&lt;/p&gt;
&lt;p&gt;It was not matching correctly for version 10, because version 10 has no decimal point in it.&lt;/p&gt;
&lt;p&gt;And the bug was fixed.&lt;/p&gt;
&lt;p&gt;This led me to creating a page, which reminds me why html sucks...&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/10634494/how-can-i-display-the-href-as-the-text-too"&gt;https://stackoverflow.com/questions/10634494/how-can-i-display-the-href-as-the-text-too&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe I'll use pandoc... yeah..&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pandoc photoswipe_bug.md -o photoswipe_bug.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But that produces busted apostrophe's with euro and TM characters showing...&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/21224741/special-characters-not-showing-in-pandoc-html-output"&gt;https://stackoverflow.com/questions/21224741/special-characters-not-showing-in-pandoc-html-output&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But that breaks the title... so I added this to the top... hackity, hack, hack!&lt;/p&gt;
&lt;p&gt;\&amp;lt;meta charset="utf-8" /&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://poleguy.com"&gt;https://poleguy.com&lt;/a&gt; works on android again!&lt;/p&gt;
&lt;p&gt;boom, done.&lt;/p&gt;</content><category term="Software"></category><category term="Bugfix"></category><category term="Software"></category></entry><entry><title>ppprs</title><link href="https://poleguy.com/blog/ppprs.html" rel="alternate"></link><published>2022-03-16T10:27:00-05:00</published><updated>2022-03-16T10:27:00-05:00</updated><author><name>Nicholas Dietz</name></author><id>tag:poleguy.com,2022-03-16:/blog/ppprs.html</id><summary type="html">&lt;p&gt;Info in support of a build curriculum:&lt;/p&gt;
&lt;p&gt;Sign up here for the private group:
&lt;a href="https://www.facebook.com/groups/powerwheelsracersforadults/"&gt;https://www.facebook.com/groups/powerwheelsracersforadults/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Contact Team Lazy Gecko about this build:
&lt;a href="http://forum.teamlazygecko.com/viewtopic.php?f=16&amp;amp;t=8"&gt;http://forum.teamlazygecko.com/viewtopic.php?f=16&amp;amp;t=8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Jim Burke: 
&lt;a href="http://powerracingseries.org/"&gt;http://powerracingseries.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pete Prodoehl:
&lt;a href="http://ppprs.2xlnetworks.org/start"&gt;http://ppprs.2xlnetworks.org/start&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ppprs.2xlnetworks.org/builds/ict"&gt;http …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Info in support of a build curriculum:&lt;/p&gt;
&lt;p&gt;Sign up here for the private group:
&lt;a href="https://www.facebook.com/groups/powerwheelsracersforadults/"&gt;https://www.facebook.com/groups/powerwheelsracersforadults/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Contact Team Lazy Gecko about this build:
&lt;a href="http://forum.teamlazygecko.com/viewtopic.php?f=16&amp;amp;t=8"&gt;http://forum.teamlazygecko.com/viewtopic.php?f=16&amp;amp;t=8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Jim Burke: 
&lt;a href="http://powerracingseries.org/"&gt;http://powerracingseries.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pete Prodoehl:
&lt;a href="http://ppprs.2xlnetworks.org/start"&gt;http://ppprs.2xlnetworks.org/start&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ppprs.2xlnetworks.org/builds/ict"&gt;http://ppprs.2xlnetworks.org/builds/ict&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Jon Halverson and Nick Dietz:
&lt;a href="https://phantompowerracing.com/"&gt;https://phantompowerracing.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://milwaukee.makerfaire.com/maker/entry/7988/"&gt;https://milwaukee.makerfaire.com/maker/entry/7988/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://milwaukee.makerfaire.com/maker/entry/7987/"&gt;https://milwaukee.makerfaire.com/maker/entry/7987/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.musclecarszone.com/pow-pow-power-wheels-innovative-technology/"&gt;https://www.musclecarszone.com/pow-pow-power-wheels-innovative-technology/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.motortrend.com/news/pow-power-wheels-hot-rod-anything"&gt;https://www.motortrend.com/news/pow-power-wheels-hot-rod-anything&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.facebook.com/powerracingseries/"&gt;https://www.facebook.com/powerracingseries/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nick Anaya makes himself very accessible:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lindblomeagles.org/apps/pages/index.jsp?uREC_ID=796725&amp;amp;type=u"&gt;https://lindblomeagles.org/apps/pages/index.jsp?uREC_ID=796725&amp;amp;type=u&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And an extra picture of the belt drive:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Belt Drive ICT" src="https://poleguy.com/blog/ppprs/ICT_belt.jpg"&gt;&lt;/p&gt;</content><category term="PPPRS"></category><category term="PPPRS"></category><category term="FPGA"></category><category term="Hardware"></category><category term="Software"></category></entry></feed>