Thanks for taking a look at this, and for the detailed notes on the various issues you hit on the way!
You are welcome.
I've never used the standard Arduino .ino approach, so I wasn't even aware that it needs everything in a single directory. Hmm, I'll have a look at other libraries and see how they handle this.
The main issue is the polarDist_240*.cpp, disp_240*.cpp, and polarAngle_240.cpp files aren't built, so I had to move them into the top level directory so they would be built automatically. I was thinking this morning that another way to do it is to have config.h include those files. Then the linker code that deletes unused global data/functions will just delete the unused arrays.
I also had to change the paths in config.h from being
#include "graphics/240x240/cat.h" to
#include "eyes/graphics/240x240/cat.h" because I had the .ino file at the top level file, and it included
"eyes/main.cpp". Now, I could put the .ino file in that directory, but a quirk of Arduino is the .ino file has to be named the same as the directory. I.e. in this case I called it 'Test-eyes'. But with the long term goal of moving this stuff into a library, that means it is less than an issue.
You might be better off just renaming main.cpp to main.ino, and modifying it as required. Think of this file more of an example program showing the usage of the eyes "library" (I know, it's not quite a real library yet!). Ultimately something like main.cpp/main.ino will likely just live in an "examples" directory to help get people started, rather than as the real app/bootstrapping it currently is.
Yes, but initially I wanted to make as few changes as possible.
This is my eventual plan too. I'd like to get it to the point where it is trivial for anyone to add to their project, e.g. via the Arduino Library Manager or PlatformIO Library Registry. Before I attempt that though I first want to get the code and API feature-complete and (relatively) stable. It is currently still a while away from that point however, especially since I have much less free time to work on this these days. As you'll see from the commits, I am still chipping away at it though!
I can appreciate that. In fact I haven't been able to contemplate doing computer stuff for fun until about two weeks ago since I needed to get the basic changes we need for the future posted before the cut-off of the stage1 builds.
One quite big change I made was to try and abstract away the display hardware code, so it will be much easier to add support for different display types. Have a look at Display.h (and the corresponding GC9A01A_Display implementation) for my first attempt at this. Unfortunately I think this might be responsible for cutting performance in half (down to around 22fps per eye) due to extra indirection in drawPixel(). I'm hoping to find some time to investigate and improve this over the weekend ahead. I don't have any ST7789 displays (or 128x128 for that matter) to test with, but maybe I'll order a couple. Also happy to work with you on 128x128 support. I tried to keep most of the code resolution independent (up to 255x255 at least, beyond that will be tricky!) so I'm hoping 128x128 won't be too tricky to get working.
Yep. I have in front of me one Teensy 4.1 with 2 square 240x240 displays, one Teensy 4.1 with 2 round 240x240 displays, a Teensy 3.2 with 128x128 TFT displays and a Teensy 3.5 with 128x128 OLED displays. At the moment, since the 128x128 stuff usual the original special optimizations that only run on Teensy 3.x systems, the two 128x128 displays are frozen to use the original code. Unfortunately, the 128x128 TFT displays are rather ancient, and it is nearly hard to see them. But with your code, the 240x240 displays now have more options.
The two Teensy 4.1's are set up to have an audio shield (one has a prototype board with a parallel 14x2 set of headers for the audio shield since that Teensy just has normal male pins) while the other Teensy 4.1 has stacking headers, and I can mount the audio shield directly on it. Both boards have wiring to support I2C, neopixel level shifter, a momentary push button and 1-2 potentiometers.
Just change EYE_DURATION_MS in main.cpp. Alternatively, update the code at the top of loop() to call nextEye() whenever you like (on a button press for example).
Thanks. I figured it would be simple, I just hadn't delved into it yet. But with the long term goal of moving it to a library, you want there to be a way to easily alter this.
While I don't think neopixel (or sound) code belongs directly in a library like this, it should still play nicely and be easy to support these sorts of use cases. As my code currently stands, each [loop() call renders a single frame (i.e. updates a single eye on a single screen). Whether that's quick enough to also allow LEDs and audio to be kept updated from loop() I'm not sure. If it's not, maybe some sort of callback support could be added per scan line (i.e. 240 times per loop() call), or maybe LEDs and audio would need to be handled via interrupts instead?
I agree, neither neopixel or sound stuff goes in these files. The issue that I have with the current code is the
loop function won't return until an entire eye cycle is done. And so if you add a second loop function to do the neopixels, and the main loop function calls the eyes loop function and then neopixel loop function, you will see one sequence of the neopixel be drawn, and then it will pause while the next eye cycle is done. Similarly for playing sound, it can't start the new sound until the eye cycle is done.
Now there are two ways to 'solve' this. The way the current Adafruit code does it, there is a user function called from the display code at times. Another way is to re-organize the display code so it just does the stuff in smaller pieces and then returns. While I tend to prefer the second method, the first method is simpler.
For FPS just uncomment the #define SHOW_FPS in Display.h. I had a bunch of other data being displayed at one point too but took it out. Drawing text yourself is currently a bit messy; you'd have to keep hold of your DisplayDefinition object and call left.display->drawText(100, 150, ...). This shouldn't be too hard for me to improve.
Note, in my stuff, I just print the FPS stuff to the USB serial monitor. I don't actually paint the screen (though I once did that).
Yes I want to get this working nicely with sound, though no sure baking in audio playback + SD support is the right way to go. I'd rather a more general solution that allowed arbitrary sound code to get the CPU cycles it needed (rather than e.g. just baking in .wav playback support).