Friday, December 30, 2022

Process Monitor - A neat tool for program inspection!

Recently, I found myself trying to debug an issue where a program would make a single request on start-up and I needed to find out what endpoint it was calling. The trouble was, every time it would start-up, it had a different PID, and then the request was made soon thereafter.

My first thought was using Wireshark, except it's difficult to find a way to filter traffic by PID (at least I'm not sure how, reinforced by my Google Foo). 

After that, I thought about writing a script that would watch for the process by name, collect PIDs and then watch network traffic for the processes. This could potentially work, but would also be hit and miss. 

Finally, I found a program available by Microsoft called Process Monitor which provides a very in depth look at what a program is doing. At first glance, I found that it can tell you which DLLs are being loaded, which files on the system are being queried / read / written / removed, registry interactions, and network interactions.  

In addition, the filters are great and use include and exclude to help narrow things down. You can also generate summaries on various general activities. 

Fat-Crush (fat-client crush) End

Connecting up a generic FTDI USB-DMX cable

Many sellers on Amazon sell cables that connect a DMX light to a computer via USB. Generally, these sellers are using a popular FTDI chip to convert USB serial data to RS485, the standard implemented with DMX.

If you are looking into using one of these USB converter cables to control data (often in a single universe), here is what you should know first. 

The FTDI chips often used require the installation of additional drivers. Make sure you match your cable IC chip to the drivers you download. These drivers can be found on the FTDI website - if you are on Windows, the easiest solution is to download the setup executable to install the drivers for you (look to the right of the operation system on the download page).

Once you have the drivers installed, you can use DMX control software (like FreeStyler) to add the fixture and send specific DMX channel data to it's address. 

I encourage you to watch a YouTube video on setting up FreeStyler as it may not be very intuitive for those getting started (Define a fixture, add the fixture, control the fixture). 

Read about using this cable with Art-Net and QLC+

Thursday, December 29, 2022

ESP8266 PWM LED Control - AnalogWrite 255 Low Output


While working on a project to create light panels rendering LED values via DMX over ARTNET, I found that the LEDs would only ever get so bright, falling quite short of their max capacity brightness. Testing the pin output with a DMM, I found that the output was about .8v. To my understanding, there is going to be a slight drop over the transistor, but not this much. I am using a Darlington TIP120 

Test Code:

#define LEDS D4
int brightness = 255;
int fadeSpeed = 10;

void setup() {
    pinMode(LEDS, OUTPUT);
void TurnOn(){
    for (int i = 0; i <= brightness; i++){
        analogWrite(LEDS, i);

void TurnOff(){
    for (int i = brightness; i >= 0; i--){
        analogWrite(LEDS, i);

void loop(){


The manufacturer of the board had changed the max value from 1023 to 255 in new versions, my board was is not a newer board but I assumed it was. 


Wednesday, December 21, 2022

Code Review with chatGPT!

To test the abilities of the OpenAI chatGPT, I decided to have it provide me with some feedback for some C++ code I recently wrote (I'm not well experienced with C++). The results are pretty cool!


Provide a code review for this: <pasted the code for Animator.cpp (>


Overall, this looks like a well-structured and well-documented class for animating a display on an Arduino. Here are some specific suggestions for improvement:

  1. In the begin() method, consider adding a null check for the display argument to ensure that it is not null before assigning it to _display. This can help avoid runtime errors.
  2. In the addAnimation() method, consider adding a check to ensure that the arr argument is not null before adding it to the _sequences array. This can help avoid runtime errors.
  3. In the removeAnimation() method, consider adding a check to ensure that the animation with the specified sequence number exists before attempting to remove it. This can help avoid runtime errors.
  4. In the playSequence() method, consider adding a check to ensure that the specified sequence number is valid before attempting to play it. This can help avoid runtime errors.
  5. In the update() method, consider adding a check to ensure that _currentAnimation is not null before attempting to draw it to the display. This can help avoid runtime errors.
  6. In the update() method, consider adding a check to ensure that _seqfps[_currentSeq] is not zero before dividing by it. Division by zero is undefined and can cause runtime errors.
  7. In the update() method, consider using elapsed_time % _currentFrameDuration instead of elapsed_time / _currentFrameDuration to determine the number of frames to jump. This will ensure that the animation stays in sync with the desired frame rate, even if the elapsed time is much larger than the frame duration.
  8. In the update() method, consider using a signed integer type (e.g. int or long) for the _currentAnimationFrame variable to allow for negative values. This can make it easier to implement features such as reverse playback or frame skipping.
  9. Consider adding a method to pause and resume the animation, as well as a method to set the frame rate and looping behavior of the current animation.
  10. Consider adding support for animations with different sizes than the display. This could be implemented by adding a _currentAnimationX and _currentAnimationY member to the Animator class and using these values in the call to drawBitmap() instead of always using 0 for the x and y arguments.
  11. Consider adding support for multiple layers or transparent colors in the animations. This could be implemented by using a 2D array of colors for each frame and using a separate drawPixel() call for each pixel in the animation.
  12. Consider adding a method to get the current status of the animator (e.g. playing, paused, stopped) and the current frame and sequence number. This can be useful for implementing more advanced animation control.

I hope these suggestions are helpful! Let me know if you have any questions.


Why does "_stream->println(_currentFrameDuration);" affect the timing calculations?


It is not clear why printing the value of _currentFrameDuration would affect the timing calculations in the update() method.

One possibility is that the act of printing to the serial port is taking a significant amount of time and causing the elapsed time between frames to be larger than expected. This could cause the animation to appear slower than expected, as more time would elapse between each frame.

To confirm this, you could try commenting out the line that prints the value of _currentFrameDuration and see if the animation behaves as expected. If the issue is indeed caused by the serial print statement, you could try optimizing the serial output (e.g. by using a smaller baud rate or buffering the output) to reduce the impact on the animation timing.

It is also possible that there is some other factor at play that is affecting the timing calculations. Without more context, it is difficult to say for certain what the root cause might be.


Is there an better way of handling pointers?


There are a few ways you could potentially improve the handling of pointers in the code you provided:

  1. Consider using smart pointers instead of raw pointers. Smart pointers are a type of object that behaves like a pointer but automatically manages the memory it points to. In particular, the std::unique_ptr and std::shared_ptr types in C++ provide automatic memory management and can make it easier to avoid memory leaks and other issues that can arise when using raw pointers.
  2. Consider adding null checks for pointers before dereferencing them. For example, you could add a null check for _display before calling any methods on it in the begin(), update(), and stop() methods. This can help avoid runtime errors if the pointer is null.
  3. Consider adding documentation to explain the purpose and ownership of each pointer member in the class. This can help other programmers understand how the pointers are intended to be used and whether they are responsible for deleting the memory they point to.
  4. Consider using reference variables instead of pointers when appropriate. In some cases, using a reference variable can make the code easier to read and understand because it is clear that the object being referred to will not be deleted or changed.

I hope these suggestions are helpful! Let me know if you have any questions.

Friday, December 9, 2022

Computers have replaced me and taken my job!

(Notice: This is a fairly satirical post. I find the services like chatGPT will actually speed up programming/solution building.)

Well, it's happening. Computers are writing code. I mean fairly complex code, not the simple control loops and conditionals we've seen in the past. 

A bit ago, I wrote the game Chutes and Ladders, except that the computer plays all the roles (because the game is pretty much entirely random). It was a exercise I did for fun and it took about hour total.

Today I just asked a chatGPT to write the same program, and it did it in about 30 seconds... 

Use Javascript to write the game Chutes and Ladders

OpenAI ChatGPT:

Here is an example of how you could write a JavaScript program to implement the game Chutes and Ladders:

// define the board size and the number of players
const BOARD_SIZE = 100;
const NUM_PLAYERS = 2;
// define the positions of the chutes and ladders on the board
const CHUTES = {
    98: 78,
    95: 75,
    92: 88,
    47: 26,
    25: 7
const LADDERS = {
    1: 38,
    4: 14,
    9: 31,
    21: 42,
    28: 84
// create an array of players and place each player at the starting position (1)
const players = Array(NUM_PLAYERS)
    .map((_, i) => ({ name: `Player ${i + 1}`, position: 1 }));
// play the game until one of the players reaches the end of the board
while (true) {
    for (const player of players) {
        // roll the dice and move the player's piece
        const roll = Math.floor(Math.random() * 6) + 1;
        player.position += roll;
        console.log(`${} rolls a ${roll} and moves to position ${player.position}`);
        // if the player lands on a chute or ladder, move them to the new position
        if (player.position in CHUTES) {
                `${} landed on a chute and falls to position ${CHUTES[player.position]}`
            player.position = CHUTES[player.position];
        } else if (player.position in LADDERS) {
                `${} climbed a ladder and moves to position ${LADDERS[player.position]}`
            player.position = LADDERS[player.position];
        // if the player reaches the end of the board, announce the winner and end the game
        if (player.position >= BOARD_SIZE) {
            console.log(`${} wins!`);

This code will simulate a game of Chutes and Ladders for two players. Each player will take turns rolling a die and moving their piece on the board according to the roll. If a player lands on a chute or ladder, they will be moved to the corresponding position. The game will continue until one of the players reaches the end of the board and wins the game.

You can adjust the parameters of the game, such as the board size, the number of players, and the positions of the chutes and ladders, to change the behavior of the game. You can also add additional features, such as a graphical user interface or support for more players, to make the game more interactive and fun.


gg. Game over. It's been fun.