commit cd5dca843ec3d6a4c34e07c180f62cfd6da8947d Author: Bradley Bickford Date: Fri Mar 27 10:10:47 2026 -0400 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/diagram.json b/diagram.json new file mode 100644 index 0000000..e607840 --- /dev/null +++ b/diagram.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { + "id": "uno", + "type": "wokwi-arduino-uno", + "top": 45, + "left": 375 + }, + { + "id": "neopixels", + "type": "wokwi-neopixel-canvas", + "top": 0, + "left": 0, + "attrs": { + "rows": "1", + "cols": "42", + "matrixBrightness": "10" + } + } + ], + "connections": [ + ["uno:GND.1", "neopixels:VSS", "black", ["v0", "*", "v16"]], + ["uno:6", "neopixels:DIN", "green", ["v-16", "*", "v8"]], + ["uno:5V", "neopixels:VDD", "red", ["v20", "h-95", "*", "v8"]] + ] +} diff --git a/include/Alternate.h b/include/Alternate.h new file mode 100644 index 0000000..39542d6 --- /dev/null +++ b/include/Alternate.h @@ -0,0 +1,38 @@ +#ifndef ALTERNATE +#define ALTERNATE + +#include "Animation.h" +#include "GlobalSettings.h" +#include "Utilities.h" +#include + +class Alternate : public Animation { + public: + Alternate(long _updateTime, uint16_t _alternateSize, CRGB* _colors, uint8_t _numColors) : + Animation(_updateTime, 10 * _numColors), numColors(_numColors), colors(new CRGB[_numColors]), + alternateInt(0), alternateSize(_alternateSize) { + for(uint8_t i = 0; i < _numColors; i++) { + colors[i] = _colors[i]; + } + } + + void initialize(CRGB* leds) { + alternateInt = 0; + resetTimer(); + + Utilities::setAll(leds, NUMLEDS, CRGB::Black); + } + + void execute(CRGB* leds); + private: + uint16_t + alternateInt, + alternateSize; + CRGB* + colors; + uint8_t + numColors; + +}; + +#endif \ No newline at end of file diff --git a/include/Animation.h b/include/Animation.h new file mode 100644 index 0000000..6927a53 --- /dev/null +++ b/include/Animation.h @@ -0,0 +1,78 @@ +#ifndef ANIMATION +#define ANIMATION + +#include +#include +#include "Utilities.h" + +class Animation { + public: + Animation(long _updateTime, uint16_t _finishedAfterCycles) : updateTime(_updateTime), + finishedAfterCycles(_finishedAfterCycles), cycles(0), enabled(false), + initialized(false), timer(0) {} + + virtual void initialize(CRGB* leds) { + + } + virtual void execute(CRGB* leds) {} + virtual bool isFinished() { + return cycles > finishedAfterCycles; + } + + void update(CRGB* leds) { + if(enabled) { + if(timer >= updateTime) { + if(!initialized) { + initialize(leds); + cycles = 0; + initialized = true; + } + + if(!isFinished()) { + execute(leds); + } + + resetTimer(); + } + } + } + + void enable() { + enabled = true; + } + + void disable() { + enabled = false; + } + + void reinitialize() { + initialized = false; + } + + bool isEnabled() { + return enabled; + } + + protected: + void resetTimer() { + timer = 0; + } + + void cycleCompleted() { + cycles = cycles += 1; + } + + private: + long + updateTime; + uint16_t + cycles, + finishedAfterCycles; + bool + enabled, + initialized; + elapsedMillis + timer; +}; + +#endif \ No newline at end of file diff --git a/include/Collision.h b/include/Collision.h new file mode 100644 index 0000000..92d3a90 --- /dev/null +++ b/include/Collision.h @@ -0,0 +1,28 @@ +#ifndef COLLISION_H +#define COLLISION_H + +#include "Animation.h" +#include "Utilities.h" +#include "GlobalSettings.h" + +class Collision : public Animation { + public: + Collision(long _updateTime, CRGB _color1, CRGB _color2) : + Animation(_updateTime, 10), color1(_color1), color2(_color2) {} + + void initialize(CRGB* leds) { + collisionInt = 0; + resetTimer(); + } + + void execute(CRGB* leds); + + private: + uint16_t + collisionInt; + CRGB + color1, + color2; +}; + +#endif \ No newline at end of file diff --git a/include/CycleLight.h b/include/CycleLight.h new file mode 100644 index 0000000..5a5bb8a --- /dev/null +++ b/include/CycleLight.h @@ -0,0 +1,36 @@ +#ifndef CYCLELIGHT_H +#define CYCLELIGHT_H + +#include "Animation.h" +#include "GlobalSettings.h" +#include "Utilities.h" + +class CycleLight : public Animation { + public: + CycleLight(long _updateTime, CRGB* _colors, uint8_t _numColors) : + Animation(_updateTime, 3 * _numColors), colors(new CRGB[_numColors]), + numColors(_numColors), cycleLightInt(0), cycleLightColor(0) { + for(uint8_t i = 0; i < _numColors; i++) { + colors[i] = _colors[i]; + } + } + + void initialize(CRGB* leds) { + cycleLightInt = 0; + cycleLightColor = 0; + + resetTimer(); + } + + void execute(CRGB* leds); + private: + uint16_t + cycleLightInt, + cycleLightColor; + CRGB* + colors; + uint8_t + numColors; +}; + +#endif \ No newline at end of file diff --git a/include/FluidColor.h b/include/FluidColor.h new file mode 100644 index 0000000..c625714 --- /dev/null +++ b/include/FluidColor.h @@ -0,0 +1,32 @@ +#ifndef FLUIDCOLOR_H +#define FLUIDCOLOR_H + +#include "Animation.h" +#include "GlobalSettings.h" +#include "Utilities.h" + +class FluidColor : public Animation { + public: + FluidColor(long _updateTime) : Animation(_updateTime, 15), + colorShifter(0), colors(new CRGB[256]) { + for(uint16_t i = 0; i < 256; i++) { + colors[i] = CRGB(CHSV(i, 255, 255)); + } + + } + + void initialize(CRGB* leds) { + colorShifter = 0; + resetTimer(); + } + + void execute(CRGB* leds); + private: + uint16_t + colorShifter; + CRGB* + colors; + +}; + +#endif \ No newline at end of file diff --git a/include/GlobalSettings.h b/include/GlobalSettings.h new file mode 100644 index 0000000..44f8af3 --- /dev/null +++ b/include/GlobalSettings.h @@ -0,0 +1,2 @@ +#define OUTPUT_PIN 6 +#define NUMLEDS 42 \ No newline at end of file diff --git a/include/README b/include/README new file mode 100644 index 0000000..49819c0 --- /dev/null +++ b/include/README @@ -0,0 +1,37 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the convention is to give header files names that end with `.h'. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/include/Utilities.h b/include/Utilities.h new file mode 100644 index 0000000..e64a56c --- /dev/null +++ b/include/Utilities.h @@ -0,0 +1,20 @@ +#ifndef UTILITIES +#define UTILITIES + +#include +#include + +class Utilities { + public: + static void setRange(CRGB* leds, uint16_t start, uint16_t end, CRGB color) { + for(uint16_t i = start; i < end; i++) { + leds[i] = color; + } + } + + static void setAll(CRGB* leds, uint16_t numLEDs, CRGB color) { + setRange(leds, 0, numLEDs, color); + } +}; + +#endif \ No newline at end of file diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..9379397 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into the executable file. + +The source code of each library should be placed in a separate directory +("lib/your_library_name/[Code]"). + +For example, see the structure of the following example libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +Example contents of `src/main.c` using Foo and Bar: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +The PlatformIO Library Dependency Finder will find automatically dependent +libraries by scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..07afac7 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,17 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:uno] +platform = atmelavr +board = uno +framework = arduino +lib_deps = + fastled/FastLED@^3.10.3 + pfeerick/elapsedMillis@^1.0.6 diff --git a/src/Alternate.cpp b/src/Alternate.cpp new file mode 100644 index 0000000..f0ca304 --- /dev/null +++ b/src/Alternate.cpp @@ -0,0 +1,10 @@ +#include "Alternate.h" + +void Alternate::execute(CRGB* leds) { + for(uint16_t i = 0; i < NUMLEDS; i += alternateSize) { + Utilities::setRange(leds, i, min(i + alternateSize, NUMLEDS), colors[((i / alternateSize) + alternateInt) % numColors]); + } + + alternateInt++; + cycleCompleted(); +} \ No newline at end of file diff --git a/src/Collision.cpp b/src/Collision.cpp new file mode 100644 index 0000000..ca1f431 --- /dev/null +++ b/src/Collision.cpp @@ -0,0 +1,17 @@ +#include "Collision.h" + +void Collision::execute(CRGB* leds) { + if(collisionInt == 0) { + Utilities::setAll(leds, NUMLEDS, CRGB::Black); + } + + leds[collisionInt] = color1; + leds[NUMLEDS - collisionInt - 1] = color2; + + collisionInt++; + + if(collisionInt >= NUMLEDS) { + collisionInt = 0; + cycleCompleted(); + } +} \ No newline at end of file diff --git a/src/CycleLight.cpp b/src/CycleLight.cpp new file mode 100644 index 0000000..13acf3f --- /dev/null +++ b/src/CycleLight.cpp @@ -0,0 +1,20 @@ +#include "CycleLight.h" + +void CycleLight::execute(CRGB* leds) { + if(cycleLightInt == 0) { + Utilities::setAll(leds, NUMLEDS, CRGB::Black); + } + + leds[cycleLightInt] = colors[cycleLightColor % numColors]; + + cycleLightInt++; + + if(cycleLightInt >= NUMLEDS) { + cycleLightInt = 0; + cycleLightColor++; + + if(cycleLightColor % numColors == 0) { + cycleCompleted(); + } + } +} \ No newline at end of file diff --git a/src/FluidColor.cpp b/src/FluidColor.cpp new file mode 100644 index 0000000..021e6fe --- /dev/null +++ b/src/FluidColor.cpp @@ -0,0 +1,13 @@ +#include "FluidColor.h" + +void FluidColor::execute(CRGB* leds) { + for(uint16_t i = 0; i < NUMLEDS; i++) { + leds[i] = colors[(i + colorShifter) % 256]; + } + + colorShifter++; + + if(colorShifter % 256 == 0) { + cycleCompleted(); + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..df04179 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,84 @@ +#include +#include +#include "GlobalSettings.h" +#include "Alternate.h" +#include "Collision.h" +#include "FluidColor.h" +#include "CycleLight.h" + +#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) + // Required for Serial on Zero based boards + #define Serial SERIAL_PORT_USBVIRTUAL +#endif + +void clearAll(); + +CRGB leds[NUMLEDS]; + +CRGB teamColors[] = {CRGB::Orange, CRGB::Green}; + +uint8_t currentMode = 0; + +Alternate alternateTeamColors(200, 2, teamColors, 2); +Collision collisionTeamColors(100, CRGB::Orange, CRGB::Green); +FluidColor fluidColor(30); +CycleLight cycleLightTeamColors(150, teamColors, 2); + +void setup() { + Serial.begin(9600); + while(!Serial) { delay(1); } + + Serial.println(F("HELLO!")); + FastLED.setMaxPowerInMilliWatts(400); + + FastLED.addLeds(leds, NUMLEDS); + + alternateTeamColors.enable(); + collisionTeamColors.enable(); + fluidColor.enable(); + cycleLightTeamColors.enable(); +} + +void loop() { + cycleLightTeamColors.update(leds); + + FastLED.show(); + + delayMicroseconds(500); +} + +/*void loop() { + if(currentMode == 0) { + alternateTeamColors.update(leds); + + if(alternateTeamColors.isFinished()) { + currentMode++; + collisionTeamColors.reinitialize(); + } + } else if(currentMode == 1) { + collisionTeamColors.update(leds); + + if(collisionTeamColors.isFinished()) { + currentMode = 2; + fluidColor.reinitialize(); + } + } else if(currentMode == 2) { + fluidColor.update(leds); + + if(fluidColor.isFinished()) { + currentMode = 3; + cycleLightTeamColors.reinitialize(); + } + } else if(currentMode == 3) { + cycleLightTeamColors.update(leds); + + if(cycleLightTeamColors.isFinished()) { + currentMode = 0; + alternateTeamColors.reinitialize(); + } + } + + FastLED.show(); + delayMicroseconds(500); +}*/ + diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/wokwi.toml b/wokwi.toml new file mode 100644 index 0000000..8368011 --- /dev/null +++ b/wokwi.toml @@ -0,0 +1,4 @@ +[wokwi] +version = 1 +firmware = '.pio/build/uno/firmware.hex' +elf = '.pio/build/uno/firmware.elf' \ No newline at end of file