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 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 from RS232 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 are often used require an 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 fixure). 


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



Thursday, December 29, 2022

ESP8266 PWM LED Control - AnalogWrite 255 Low Output

Problem:

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);
        delay(fadeSpeed);
    }
}

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

void loop(){
    TurnOn();
    delay(4000);
    TurnOff();
    delay(4000);
}




Solution:

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. 


Reference

https://arduino-esp8266.readthedocs.io/en/latest/reference.html#analog-output

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!


Me: 

Provide a code review for this: <pasted the code for Animator.cpp (https://gist.github.com/mcorrigan/cd95230c568503f3917a57c66ef73b55)>


chatGPT:

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.


Me:

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


chatGPT:

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.


Me:

Is there an better way of handling pointers?


chatGPT:

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!

(Warning: This is a fairly satirical post)

Well, it's happening. Computers are writing code. I mean 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 in about hour total.

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


Me: 
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)
    .fill()
    .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(`${player.name} 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) {
            console.log(
                `${player.name} landed on a chute and falls to position ${CHUTES[player.position]}`
            );
            player.position = CHUTES[player.position];
        } else if (player.position in LADDERS) {
            console.log(
                `${player.name} 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(`${player.name} wins!`);
            process.exit();
        }
    }
}

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.


Me:
:O


gg. Game over. It's been fun. 

Tuesday, November 15, 2022

Non-blocking Arduino/OLED SSD1306 Animation Manager

Problem:

I'm working on a project that involves a bit of screen usage and I need to organize things in a way that they will work without blocking my event loop. (I plan to share this project once I'm about finished with it. - And it's sure to make you parent of the year!)

While I have done a bit with Arduino and programming in other languages, I don't have a lot of experience in C/C++, so if anything looks wrong (uh hem, like pointers/ref usage...), please help me understand so I can improve the code and myself :). 


Solution:

To really be able to handle playback of animations on the OLED screen, I decided I would code up an Animator class. You register sequences with it (and get a seq ID back), and then call-up and play any stored sequence, looping or not. In addition to play(), pause(), and stop(),  I also wanted to manage the FPS of playback so that if the event loop called too often, the redraws would only occur when necessary, or in the case of fast FPS, would skip frames in an effort to keep up. 

I think there are a lot of cool things that could still be done with this, but for the time being this is where it is at. 


Here is a quick demo using the Animator class (trust me, it's non-blocking) and some example code: 

https://gist.github.com/mcorrigan/cd95230c568503f3917a57c66ef73b55 


Bug Note: There is currently an issue where if you don't Serial->println() the _currentFrameDuration, the framerate won't update properly. This could be a timing issue.


Be sure to check-out the chatGPT code review here!



Monday, November 7, 2022

Addressable LED Strip Flickers with Arduino | Weird Behavior

Problem: 

While working with Arduino and addressable LED strips (a few times now), I tend to wire up everything (with external power since the LEDs can draw a lot of current) and go to test it. The LEDs almost seem like they are working, but then they flicker, are varying brightness, and erratic. 


(The LED strips I have used don't have a second GND)

Solution:

Quite simply this is just me forgetting to tie the ground from the power adapter to the ground of the Arduino so they share the same basis. Once grounded, things seem to work just fine. It turns out the LED strip above was already trying to hint at how to solve the problem... 

If your LED strip doesn't have 2 GND connections, just connect the G from the Arduino directly to the GND rail connected to by the LED DC power supply.






Tuesday, November 1, 2022

Raspberry Pi Camera - Color ASCII Real-time Preview for terminal

Problem:

I'm working on a project with my son that uses a Raspberry Pi camera to detect people, identify them, and then shoot them (with a NERF bullet via a turret) if they are not "authorized". 

I'm using an older RPI 3 B+, and like many PIs it has it's limits. To save on resource usage, I decided I would forgo the desktop. After a bit, I realized that there wasn't a great way (I could figure out) to preview my PI camera footage for the purpose of taking pictures of faces to train a CV model. 


Solution:

In the past, I had seen some ASCII art, and so I thought, "why not build a live camera preview rendering out the frames as ASCII?" shortly after with "and in color!"

This was my first time working with curses, which prove to have it's own little nuances, but isn't terrible. 

Feel free to comment if you have any improvements. The colors are interesting and could probably use some love. Also, I'm sure there are some optimizations that could be done to improve overall performance. 

https://gist.github.com/mcorrigan/faf55cd8b0d183e0aaab5c40db6ffd92 

To improve render performance, you can set use_color = False, but you might have a harder time seeing the image. 


Demos:

Compare ASCII color preview with capture

Testing out ASCII color w/ change to night vision



Wednesday, September 7, 2022

ESP8266 FastLED Pin Assignment Confusion

Problem:

While trying to use an ESP8266 D1 mini Arduino board to control some addressable WS8211 LEDs, I found that it didn't seem to work.


Solution:

After some reading, I found that the pin numbering didn't line up the way I thought it would. I'm not sure if this is a bug in FastLED or the result of using a D1 clone, but once I had this information everything started working perfectly. (Note, my board layout is a bit different, but this still applied.) -- easiest solution is to use D2 label for GPIO4.



Source: https://github.com/FastLED/FastLED/issues/542#issuecomment-355667857


Here is the working test sketch: 

#include <FastLED.h>
#define DATA_PIN 4 // but plug into pin 2 or use D4
#define LED_BRIGHTNESS 50 // global brightness setting (might change for HSV)
#define LED_COUNT 50 // lights per pin
CRGB leds[LED_COUNT];
void setup() {
  Serial.begin(9600);
  delay(1000);
  FastLED.setBrightness(LED_BRIGHTNESS);
  FastLED.addLeds<WS2811, DATA_PIN>(leds, LED_COUNT);
  fill_solid(leds, LED_COUNT, CRGB::Black);
  FastLED.show();
}
void loop() {
  cd77_colorwipe_dot(CRGB::Red, 10);
}
void cd77_colorwipe_dot(CRGB color, uint16_t wait) {
  for (byte led = 0; led < LED_COUNT; led++) {
    leds[led] = color;
    FastLED.delay(wait);
    leds[led] = CRGB::Black;
    FastLED.show();
  }
}

Thursday, July 28, 2022

Symon (a.k.a. Simon) -- that old toy that tests your memory...

A rapid coding challenge I decided to do sometime ago was for a Simon replication game that was fully user interactive. I've made the code and assets available for anyone interested -- just don't judge me...

Play the game!

https://mcorrigan.github.io/psymon/psymon.html


Source Code: 

https://github.com/mcorrigan/psymon

Tuesday, July 26, 2022

Start-Up Roadmap - Digi-Key Maker.IO

While looking over some components looking to source a pot for an amp I'm fixing, I found this cool little outline of taking a product from concept to the masses. It's a good thing to remember when we only want to do steps, 1, 4 and 5. 😏

To make it easier for printing and concise to fit on one page, I went a head and created a PDF of it. 

Keep in mind all the logos and images are their copyright, not mine and I'm more than happy to remove files, etc. if Digi-Key prefers. 

It's not super optimized for size, but I'm sure you can manage :).


https://drive.google.com/file/d/102NW6ZvsILn0R6I8wRY2f8B3O7kdoJ4P/view?usp=sharing

Chutes and Ladders is totally random, just let the computer play it...

My kids like to play Chutes and Ladders as a family and I have no idea why. Even though the game is pretty much entirely random (pro spinner flickers aside), they still feel bummed when they lose. As a quick exercise, I decided to code up the game having the computer play all the turns until a winner is found. This was meant to take me 30 minutes, but I guess including my son's 30 minutes to test it, we could say it took about an hour. It's not meant to be clean or any kind of representation of proper coding, syntax, etc. so keep your expectations low...

I do not have this hosted at the moment, but the code is available on GitHub: 

https://gist.github.com/mcorrigan/086ff9b5f4de18be1a68420aca876612

P.S. If you have your console open, you can see all the moves the winner made on their way to win the game. 

Friday, June 10, 2022

Laravel / Google Maps -- Get Locations in Bounds

Problem: 

While working on a project using Laravel back-end and JavaScript front-end. I had a situation where I needed to get all the locations for the map with given bounds. First, I tried just doing a bounding box check, which worked but only sometimes. 


Solution:

In this problem, I was not alone. After reading and trying some various approaches, this one by FatMonk on SO did the trick (https://stackoverflow.com/a/35944747). 

// Google Maps API map.getBounds()

$north = $lat1_ne || 90;
$east = $lng1_ne;
$south = $lat2_sw || -90;
$west = $lng2_sw;

$locations = Location::whereBetween('lat', [$south, $north])
    ->where(function($query) use ($west, $east){
        if ($west < $east){
            $query->whereBetween('lon', [$west, $east]);
        }else{
            $query->whereBetween('lon', [$west, 180])
                ->orWhereBetween('lon', [-180, $east]);
        }
})
->get();

Thursday, June 9, 2022

BlackMagic Ursa Mini G2 - Iso to gain dBs translation

Recently I have needed to get this information and couldn't quickly find it, so I'm shamelessly placing it here for next time :). 

db ISO
-12=100
-6=200
0=400
+6=800
+12=1600
+18=3200
+24=6400
+30=12800
+36=25600
Natives are 0db and +18db

ISO 100 = -12db. ISO doubles every 6db and the highest ISO is 25600 @ 36db.



Source: https://forum.blackmagicdesign.com/viewtopic.php?t=154758&p=822669

Friday, May 27, 2022

Python: valueerror too many values to unpack (expected 2) stackoverflow - dict to tuples

Admittedly, I haven't spent a lot of time in Python lately and find myself hitting my head on the wall trying to figure out some fairly simple things again. This is one of those such things.

Problem: 

I am using the requests library to interact with a server. This library has some great methods to prepare requests and then be able to send them at a later time. In one of these instances, I was building and preparing the Request with some data (also wrapping with the session to preserve cookie info):

request = session.prepare_request(Request('GET', "https://example.com/search", params=rdata))

The rdata object looks like a simple dict with key/value pairs. However, when running the code I got the error: 

ValueError: too many values to unpack (expected 2)


Solution:

After printing out the object and comparing it with a clean object, I found the issue:

rdata = {'key': 1, 'value': 2},

The comma at the end implied to Python that my structure was a tuple (pseudo: type(rdata) == <class 'tuple'>). Also, keep in mind my variable has a lot more data in it running it off the screen and I am not using word-wrap... so out of site, out of mind I guess. 

After removing the comma, rdata was seen as a dict again and could be converted to a list of tuples by requests prepare function.