From 492d7f70a9ff7e5446f2bce79be4acb18e6ea367 Mon Sep 17 00:00:00 2001 From: Patrick Balsiger Date: Fri, 29 Jun 2018 22:33:36 +0200 Subject: [PATCH] illucat and basic button --- platformio.ini | 14 +- src/examples/button/Button.h | 45 +++++ src/examples/button/config.h | 25 +++ src/examples/button/main.cpp | 20 ++ src/examples/illucat/Illucat.h | 45 +++++ src/examples/illucat/NeoPattern.h | 304 ++++++++++++++++++++++++++++++ src/examples/illucat/config.h | 29 +++ src/examples/illucat/main.cpp | 21 +++ 8 files changed, 501 insertions(+), 2 deletions(-) create mode 100644 src/examples/button/Button.h create mode 100644 src/examples/button/config.h create mode 100644 src/examples/button/main.cpp create mode 100644 src/examples/illucat/Illucat.h create mode 100644 src/examples/illucat/NeoPattern.h create mode 100644 src/examples/illucat/config.h create mode 100644 src/examples/illucat/main.cpp diff --git a/platformio.ini b/platformio.ini index ce57477..bb8fa86 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; http://docs.platformio.org/page/projectconf.html [platformio] -env_default = build +env_default = illucat [common] framework = arduino @@ -66,4 +66,14 @@ upload_speed = ${common.upload_speed} monitor_baud = ${common.monitor_baud} framework = ${common.framework} lib_deps = ${common.lib_deps} - PubSubClient \ No newline at end of file + PubSubClient + +[env:illucat] +src_filter = +<*> - - + +platform = ${common.platform} +board = ${common.board} +upload_speed = ${common.upload_speed} +monitor_baud = ${common.monitor_baud} +framework = ${common.framework} +lib_deps = ${common.lib_deps} + Adafruit NeoPixel \ No newline at end of file diff --git a/src/examples/button/Button.h b/src/examples/button/Button.h new file mode 100644 index 0000000..a8fa611 --- /dev/null +++ b/src/examples/button/Button.h @@ -0,0 +1,45 @@ + #ifndef __MESH_APP__ +#define __MESH_APP__ + +#include +#include +#include + +using namespace std; +using namespace std::placeholders; + +class Button : public Sprocket { + public: + Task btnTask; + MeshNet* net; + int pin; + MeshApp(SprocketConfig cfg) : Sprocket(cfg) {} + Sprocket* activate(Scheduler* scheduler, Network* network) { + pinMode(D2, INPUT_PULLUP); + net = static_cast(network); + net->mesh.onReceive(bind(&MeshApp::receivedCallback,this, _1, _2)); + someTask.set(TASK_MILLISECOND * 50, TASK_FOREVER, + bind(&MeshApp::readPin, this, net)); + scheduler->addTask(btnTask); + btnTask.enable(); + } using Sprocket::activate; + + void readPin(MeshNet* network){ + if(digitalRead(pin)){ + network->broadcast("{ \"pressed \": 1 }"); + } + } + + void receivedCallback( uint32_t from, String &msg ) { + Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str()); + // respond in receive callback can cause an endless loop when all nodes run the same firmware + //String foo = String("cheerz back to ") + String(from); + //net->broadcast(foo); + } + void loop() { + net->update(); + scheduler.execute(); + } +}; + +#endif \ No newline at end of file diff --git a/src/examples/button/config.h b/src/examples/button/config.h new file mode 100644 index 0000000..c27cb09 --- /dev/null +++ b/src/examples/button/config.h @@ -0,0 +1,25 @@ +#ifndef __MESH_CONFIG__ +#define __MESH_CONFIG__ + +// Scheduler config +#define _TASK_SLEEP_ON_IDLE_RUN +#define _TASK_STD_FUNCTION + +// Chip config +#define SERIAL_BAUD_RATE 115200 +#define STARTUP_DELAY 3000 + +// Mesh config +#define STATION_MODE 0 +#define WIFI_CHANNEL 11 +#define MESH_PORT 5555 +#define MESH_PREFIX "whateverYouLike" +#define MESH_PASSWORD "somethingSneaky" +#define STATION_SSID "Th1ngs4P" +#define STATION_PASSWORD "th3r31sn0sp00n" +#define HOSTNAME "mesh-node" +#define MESH_DEBUG_TYPES ERROR | STARTUP | CONNECTION + +#define BUTTON_PIN D2 + +#endif \ No newline at end of file diff --git a/src/examples/button/main.cpp b/src/examples/button/main.cpp new file mode 100644 index 0000000..655fbbd --- /dev/null +++ b/src/examples/button/main.cpp @@ -0,0 +1,20 @@ +#include "config.h" +#include "MeshNet.h" +#include "MeshApp.h" + +MeshNet net({ + STATION_MODE, WIFI_CHANNEL, + MESH_PORT, MESH_PREFIX, MESH_PASSWORD, + STATION_SSID, STATION_PASSWORD, HOSTNAME, + MESH_DEBUG_TYPES +}); +MeshApp sprocket({ STARTUP_DELAY, SERIAL_BAUD_RATE }); + +void setup() { + sprocket.join(net); +} + +void loop() { + sprocket.loop(); + yield(); +} \ No newline at end of file diff --git a/src/examples/illucat/Illucat.h b/src/examples/illucat/Illucat.h new file mode 100644 index 0000000..0991f6c --- /dev/null +++ b/src/examples/illucat/Illucat.h @@ -0,0 +1,45 @@ +#ifndef __MESH_APP__ +#define __MESH_APP__ + +#include +#include +#include +#include "NeoPattern.h" + +using namespace std; +using namespace std::placeholders; + +struct NeoPixelConfig { + int pin; + int length; +}; + +class Illucat : public Sprocket { + public: + MeshNet* net; + NeoPattern* pixels; + Illucat(SprocketConfig cfg, NeoPixelConfig pixelCfg) : Sprocket(cfg) { + pixels = new NeoPattern(pixelCfg.length, pixelCfg.pin, NEO_GRB + NEO_KHZ800, [](int pixels){}); + } + Sprocket* activate(Scheduler* scheduler, Network* network) { + net = static_cast(network); + net->mesh.onReceive(bind(&Illucat::messageReceived,this, _1, _2)); + // TODO default rainbow task + } using Sprocket::activate; + + void messageReceived( uint32_t from, String &msg ) { + Serial.printf("illucat: received from %u msg=%s\n", from, msg.c_str()); + setHexColor(msg.c_str()); + } + void setHexColor(const char *hex){ + int r, g, b; + sscanf(hex, "%02x%02x%02x", &r, &g, &b); + pixels->ColorSet(pixels->Color(r,g,b)); + } + void loop() { + net->update(); + scheduler.execute(); + } +}; + +#endif \ No newline at end of file diff --git a/src/examples/illucat/NeoPattern.h b/src/examples/illucat/NeoPattern.h new file mode 100644 index 0000000..f2b1a58 --- /dev/null +++ b/src/examples/illucat/NeoPattern.h @@ -0,0 +1,304 @@ +#ifndef __NeoPattern_H_INCLUDED__ +#define __NeoPattern_H_INCLUDED__ + +#include + +/** + * NeoPattern by Bill Earl + * https://learn.adafruit.com/multi-tasking-the-arduino-part-3/overview + */ + +// Pattern types supported: +enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE }; +// Patern directions supported: +enum direction { FORWARD, REVERSE }; + +// NeoPattern Class - derived from the Adafruit_NeoPixel class +class NeoPattern : public Adafruit_NeoPixel +{ + public: + + // Member Variables: + pattern ActivePattern; // which pattern is running + direction Direction; // direction to run the pattern + + unsigned long Interval; // milliseconds between updates + unsigned long lastUpdate; // last update of position + + uint32_t Color1, Color2; // What colors are in use + uint16_t TotalSteps; // total number of steps in the pattern + uint16_t Index; // current step within the pattern + uint16_t completed = 0; + + void (*OnComplete)(int); // Callback on completion of pattern + + // Constructor - calls base-class constructor to initialize strip + NeoPattern(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)(int)) + :Adafruit_NeoPixel(pixels, pin, type) + { + OnComplete = callback; + } + + // Update the pattern + void Update() + { + if((millis() - lastUpdate) > Interval) // time to update + { + lastUpdate = millis(); + switch(ActivePattern) + { + case RAINBOW_CYCLE: + RainbowCycleUpdate(); + break; + case THEATER_CHASE: + TheaterChaseUpdate(); + break; + case COLOR_WIPE: + ColorWipeUpdate(); + break; + case SCANNER: + ScannerUpdate(); + break; + case FADE: + FadeUpdate(); + break; + default: + break; + } + } + } + + // Increment the Index and reset at the end + void Increment() + { + completed = 0; + if (Direction == FORWARD) + { + Index++; + if (Index >= TotalSteps) + { + Index = 0; + if (OnComplete != NULL) + { + completed = 1; + OnComplete(numPixels()); // call the comlpetion callback + } + } + } + else // Direction == REVERSE + { + --Index; + if (Index <= 0) + { + Index = TotalSteps-1; + if (OnComplete != NULL) + { + completed = 1; + OnComplete(numPixels()); // call the comlpetion callback + } + } + } + } + + // Reverse pattern direction + void Reverse() + { + if (Direction == FORWARD) + { + Direction = REVERSE; + Index = TotalSteps-1; + } + else + { + Direction = FORWARD; + Index = 0; + } + } + + // Initialize for a RainbowCycle + void RainbowCycle(uint8_t interval, direction dir = FORWARD) + { + ActivePattern = RAINBOW_CYCLE; + Interval = interval; + TotalSteps = 255; + Index = 0; + Direction = dir; + } + + // Update the Rainbow Cycle Pattern + void RainbowCycleUpdate() + { + for(int i=0; i< numPixels(); i++) + { + setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255)); + } + show(); + Increment(); + } + + // Initialize for a Theater Chase + void TheaterChase(uint32_t color1, uint32_t color2, uint16_t interval, direction dir = FORWARD) + { + ActivePattern = THEATER_CHASE; + Interval = interval; + TotalSteps = numPixels(); + Color1 = color1; + Color2 = color2; + Index = 0; + Direction = dir; + } + + // Update the Theater Chase Pattern + void TheaterChaseUpdate() + { + for(int i=0; i< numPixels(); i++) + { + if ((i + Index) % 3 == 0) + { + setPixelColor(i, Color1); + } + else + { + setPixelColor(i, Color2); + } + } + show(); + Increment(); + } + + // Initialize for a ColorWipe + void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD) + { + ActivePattern = COLOR_WIPE; + Interval = interval; + TotalSteps = numPixels(); + Color1 = color; + Index = 0; + Direction = dir; + } + + // Update the Color Wipe Pattern + void ColorWipeUpdate() + { + setPixelColor(Index, Color1); + show(); + Increment(); + } + + // Initialize for a SCANNNER + void Scanner(uint32_t color1, uint8_t interval) + { + ActivePattern = SCANNER; + Interval = interval; + TotalSteps = (numPixels() - 1) * 2; + Color1 = color1; + Index = 0; + } + + // Update the Scanner Pattern + void ScannerUpdate() + { + for (int i = 0; i < numPixels(); i++) + { + if (i == Index) // Scan Pixel to the right + { + setPixelColor(i, Color1); + } + else if (i == TotalSteps - Index) // Scan Pixel to the left + { + setPixelColor(i, Color1); + } + else // Fading tail + { + setPixelColor(i, DimColor(getPixelColor(i))); + } + } + show(); + Increment(); + } + + // Initialize for a Fade + void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD) + { + ActivePattern = FADE; + Interval = interval; + TotalSteps = steps; + Color1 = color1; + Color2 = color2; + Index = 0; + Direction = dir; + } + + // Update the Fade Pattern + void FadeUpdate() + { + // Calculate linear interpolation between Color1 and Color2 + // Optimise order of operations to minimize truncation error + uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps; + uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps; + uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps; + + ColorSet(Color(red, green, blue)); + show(); + Increment(); + } + + // Calculate 50% dimmed version of a color (used by ScannerUpdate) + uint32_t DimColor(uint32_t color) + { + // Shift R, G and B components one bit to the right + uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1); + return dimColor; + } + + // Set all pixels to a color (synchronously) + void ColorSet(uint32_t color) + { + for (int i = 0; i < numPixels(); i++) + { + setPixelColor(i, color); + } + show(); + } + + // Returns the Red component of a 32-bit color + uint8_t Red(uint32_t color) + { + return (color >> 16) & 0xFF; + } + + // Returns the Green component of a 32-bit color + uint8_t Green(uint32_t color) + { + return (color >> 8) & 0xFF; + } + + // Returns the Blue component of a 32-bit color + uint8_t Blue(uint32_t color) + { + return color & 0xFF; + } + + // Input a value 0 to 255 to get a color value. + // The colours are a transition r - g - b - back to r. + uint32_t Wheel(byte WheelPos) + { + WheelPos = 255 - WheelPos; + if(WheelPos < 85) + { + return Color(255 - WheelPos * 3, 0, WheelPos * 3); + } + else if(WheelPos < 170) + { + WheelPos -= 85; + return Color(0, WheelPos * 3, 255 - WheelPos * 3); + } + else + { + WheelPos -= 170; + return Color(WheelPos * 3, 255 - WheelPos * 3, 0); + } + } +}; + +#endif \ No newline at end of file diff --git a/src/examples/illucat/config.h b/src/examples/illucat/config.h new file mode 100644 index 0000000..f099c01 --- /dev/null +++ b/src/examples/illucat/config.h @@ -0,0 +1,29 @@ +#ifndef __MESH_CONFIG__ +#define __MESH_CONFIG__ + +// Scheduler config +#define _TASK_SLEEP_ON_IDLE_RUN +#define _TASK_STD_FUNCTION + +// Chip config +#define SERIAL_BAUD_RATE 115200 +#define STARTUP_DELAY 3000 + +// Mesh config +#define STATION_MODE 0 +#define WIFI_CHANNEL 11 +#define MESH_PORT 5555 +#define MESH_PREFIX "whateverYouLike" +#define MESH_PASSWORD "somethingSneaky" +#define STATION_SSID "Th1ngs4P" +#define STATION_PASSWORD "th3r31sn0sp00n" +#define HOSTNAME "mesh-node" +#define MESH_DEBUG_TYPES ERROR | STARTUP | CONNECTION + +// illucat +#define LED_STRIP_PIN D2 +#define LED_STRIP_LENGTH 8 +#define LED_STRIP_BRIGHTNESS 32 + + +#endif \ No newline at end of file diff --git a/src/examples/illucat/main.cpp b/src/examples/illucat/main.cpp new file mode 100644 index 0000000..9c12dbf --- /dev/null +++ b/src/examples/illucat/main.cpp @@ -0,0 +1,21 @@ +#include "config.h" +#include "MeshNet.h" +#include "Illucat.h" + +MeshNet net({ + STATION_MODE, WIFI_CHANNEL, + MESH_PORT, MESH_PREFIX, MESH_PASSWORD, + STATION_SSID, STATION_PASSWORD, HOSTNAME, + MESH_DEBUG_TYPES +}); +Illucat sprocket({ STARTUP_DELAY, SERIAL_BAUD_RATE }, + { LED_STRIP_PIN, LED_STRIP_LENGTH }); + +void setup() { + sprocket.join(net); +} + +void loop() { + sprocket.loop(); + yield(); +} \ No newline at end of file