diff --git a/src/neopixel.cpp b/src/neopixel.cpp
new file mode 100644
index 0000000..453840b
--- /dev/null
+++ b/src/neopixel.cpp
@@ -0,0 +1,1361 @@
+/*-------------------------------------------------------------------------
+ Particle Core, Particle Photon, P1, Electron, Argon, Boron, Xenon and
+ RedBear Duo library to control WS2811/WS2812/WS2813 based RGB LED
+ devices such as Adafruit NeoPixel strips.
+
+ Supports:
+ - 800 KHz WS2812, WS2812B, WS2813 and 400kHz bitstream and WS2811
+ - 800 KHz bitstream SK6812RGBW (NeoPixel RGBW pixel strips)
+ (use 'SK6812RGBW' as PIXEL_TYPE)
+
+ Also supports:
+ - Radio Shack Tri-Color Strip with TM1803 controller 400kHz bitstream.
+ - TM1829 pixels
+
+ PLEASE NOTE that the NeoPixels require 5V level inputs
+ and the supported microcontrollers only have 3.3V level outputs. Level
+ shifting is necessary, but will require a fast device such as one of
+ the following:
+
+ [SN74HCT125N]
+ http://www.digikey.com/product-detail/en/SN74HCT125N/296-8386-5-ND/376860
+
+ [SN74HCT245N]
+ http://www.digikey.com/product-detail/en/SN74HCT245N/296-1612-5-ND/277258
+
+ Written by Phil Burgess / Paint Your Dragon for Adafruit Industries.
+ Modified to work with Particle devices by Technobly.
+ Contributions by PJRC and other members of the open source community.
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing products
+ from Adafruit!
+ --------------------------------------------------------------------*/
+
+/* ======================= neopixel.cpp ======================= */
+/*-------------------------------------------------------------------------
+ This file is part of the Adafruit NeoPixel library.
+
+ NeoPixel is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ NeoPixel is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with NeoPixel. If not, see
+ .
+ -------------------------------------------------------------------------*/
+
+#include "neopixel.h"
+
+#if PLATFORM_ID == 0 // Core (0)
+ #define pinLO(_pin) (PIN_MAP[_pin].gpio_peripheral->BRR = PIN_MAP[_pin].gpio_pin)
+ #define pinHI(_pin) (PIN_MAP[_pin].gpio_peripheral->BSRR = PIN_MAP[_pin].gpio_pin)
+#elif (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ STM32_Pin_Info* PIN_MAP2 = HAL_Pin_Map(); // Pointer required for highest access speed
+ #define pinLO(_pin) (PIN_MAP2[_pin].gpio_peripheral->BSRRH = PIN_MAP2[_pin].gpio_pin)
+ #define pinHI(_pin) (PIN_MAP2[_pin].gpio_peripheral->BSRRL = PIN_MAP2[_pin].gpio_pin)
+#elif (PLATFORM_ID == 12) || (PLATFORM_ID == 13) || (PLATFORM_ID == 14) // Argon (12), Boron (13), Xenon (14)
+ #include "nrf.h"
+ #include "nrf_gpio.h"
+ #include "pinmap_impl.h"
+ NRF5x_Pin_Info* PIN_MAP2 = HAL_Pin_Map();
+ #define pinLO(_pin) (nrf_gpio_pin_clear(NRF_GPIO_PIN_MAP(PIN_MAP2[_pin].gpio_port, PIN_MAP2[_pin].gpio_pin)))
+ #define pinHI(_pin) (nrf_gpio_pin_set(NRF_GPIO_PIN_MAP(PIN_MAP2[_pin].gpio_port, PIN_MAP2[_pin].gpio_pin)))
+#else
+ #error "*** PLATFORM_ID not supported by this library. PLATFORM should be Particle Core, Photon, Electron, Argon, Boron, Xenon and RedBear Duo ***"
+#endif
+// fast pin access
+#define pinSet(_pin, _hilo) (_hilo ? pinHI(_pin) : pinLO(_pin))
+
+Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, uint8_t t) :
+ begun(false), type(t), brightness(0), pixels(NULL), endTime(0)
+{
+ updateLength(n);
+ setPin(p);
+}
+
+Adafruit_NeoPixel::~Adafruit_NeoPixel() {
+ if (pixels) free(pixels);
+ if (begun) pinMode(pin, INPUT);
+}
+
+void Adafruit_NeoPixel::updateLength(uint16_t n) {
+ if (pixels) free(pixels); // Free existing data (if any)
+
+ // Allocate new data -- note: ALL PIXELS ARE CLEARED
+ numBytes = n * ((type == SK6812RGBW) ? 4 : 3);
+ if ((pixels = (uint8_t *)malloc(numBytes))) {
+ memset(pixels, 0, numBytes);
+ numLEDs = n;
+ } else {
+ numLEDs = numBytes = 0;
+ }
+}
+
+void Adafruit_NeoPixel::begin(void) {
+ pinMode(pin, OUTPUT);
+ digitalWrite(pin, LOW);
+ begun = true;
+}
+
+// Set the output pin number
+void Adafruit_NeoPixel::setPin(uint8_t p) {
+ if (begun) {
+ pinMode(pin, INPUT);
+ }
+ pin = p;
+ if (begun) {
+ pinMode(p, OUTPUT);
+ digitalWrite(p, LOW);
+ }
+}
+
+void Adafruit_NeoPixel::show(void) {
+ if(!pixels) return;
+
+ // Data latch = 24 or 50 microsecond pause in the output stream. Rather than
+ // put a delay at the end of the function, the ending time is noted and
+ // the function will simply hold off (if needed) on issuing the
+ // subsequent round of data until the latch time has elapsed. This
+ // allows the mainline code to start generating the next frame of data
+ // rather than stalling for the latch.
+ uint32_t wait_time; // wait time in microseconds.
+ switch(type) {
+ case TM1803: { // TM1803 = 24us reset pulse
+ wait_time = 24L;
+ } break;
+ case SK6812RGBW: { // SK6812RGBW = 80us reset pulse
+ wait_time = 80L;
+ } break;
+ case TM1829: { // TM1829 = 500us reset pulse
+ wait_time = 500L;
+ } break;
+ case WS2812B: // WS2812, WS2812B & WS2813 = 300us reset pulse
+ case WS2812B2: {
+ wait_time = 300L;
+ } break;
+ case WS2811: // WS2811, WS2812B_FAST & WS2812B2_FAST = 50us reset pulse
+ case WS2812B_FAST:
+ case WS2812B2_FAST:
+ default: { // default = 50us reset pulse
+ wait_time = 50L;
+ } break;
+ }
+ while((micros() - endTime) < wait_time);
+ // endTime is a private member (rather than global var) so that multiple
+ // instances on different pins can be quickly issued in succession (each
+ // instance doesn't delay the next).
+
+#if (PLATFORM_ID == 0) || (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Core (0), Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ __disable_irq(); // Need 100% focus on instruction timing
+
+ volatile uint32_t
+ c, // 24-bit/32-bit pixel color
+ mask; // 1-bit mask
+ volatile uint16_t i = numBytes; // Output loop counter
+ volatile uint8_t
+ j, // 8-bit inner loop counter
+ *ptr = pixels, // Pointer to next byte
+ g, // Current green byte value
+ r, // Current red byte value
+ b, // Current blue byte value
+ w; // Current white byte value
+
+ if(type == WS2812B || type == WS2812B_FAST) { // Same as WS2812 & WS2813, 800 KHz bitstream
+ while(i) { // While bytes left... (3 bytes = 1 pixel)
+ mask = 0x800000; // reset the mask
+ i = i-3; // decrement bytes remaining
+ g = *ptr++; // Next green byte value
+ r = *ptr++; // Next red byte value
+ b = *ptr++; // Next blue byte value
+ c = ((uint32_t)g << 16) | ((uint32_t)r << 8) | b; // Pack the next 3 bytes to keep timing tight
+ j = 0; // reset the 24-bit counter
+ do {
+ pinSet(pin, HIGH); // HIGH
+ if (c & mask) { // if masked bit is high
+ // WS2812 spec 700ns HIGH
+ // Adafruit on Arduino (meas. 812ns)
+ // This lib on Spark Core (meas. 804ns)
+ // This lib on Photon (meas. 792ns)
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ // WS2812 spec 600ns LOW
+ // Adafruit on Arduino (meas. 436ns)
+ // This lib on Spark Core (meas. 446ns)
+ // This lib on Photon (meas. 434ns)
+ pinSet(pin, LOW); // LOW
+ asm volatile(
+ "mov r0, r0" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ }
+ else { // else masked bit is low
+ // WS2812 spec 350ns HIGH
+ // Adafruit on Arduino (meas. 312ns)
+ // This lib on Spark Core (meas. 318ns)
+ // This lib on Photon (meas. 308ns)
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ // WS2812 spec 800ns LOW
+ // Adafruit on Arduino (meas. 938ns)
+ // This lib on Spark Core (meas. 944ns)
+ // This lib on Photon (meas. 936ns)
+ pinSet(pin, LOW); // LOW
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ }
+ mask >>= 1;
+ } while ( ++j < 24 ); // ... pixel done
+ } // end while(i) ... no more pixels
+ }
+ else if(type == SK6812RGBW) { // similar to WS2812, 800 KHz bitstream but with RGB+W components
+ while(i) { // While bytes left... (4 bytes = 1 pixel)
+ mask = 0x80000000; // reset the mask
+ i = i-4; // decrement bytes remaining
+ r = *ptr++; // Next red byte value
+ g = *ptr++; // Next green byte value
+ b = *ptr++; // Next blue byte value
+ w = *ptr++; // Next white byte value
+ c = ((uint32_t)r << 24) | ((uint32_t)g << 16) | ((uint32_t)b << 8) | w; // Pack the next 4 bytes to keep timing tight
+ j = 0; // reset the 32-bit counter
+ do {
+ pinSet(pin, HIGH); // HIGH
+ if (c & mask) { // if masked bit is high
+ // SK6812RGBW spec 600ns HIGH
+ // WS2812 spec 700ns HIGH
+ // Adafruit on Arduino (meas. 812ns)
+ // This lib on Spark Core (meas. 610ns)
+ // This lib on Photon (meas. 608ns)
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ // SK6812RGBW spec 600ns LOW
+ // WS2812 spec 600ns LOW
+ // Adafruit on Arduino (meas. 436ns)
+ // This lib on Spark Core (meas. 598ns)
+ // This lib on Photon (meas. 600ns)
+ pinSet(pin, LOW); // LOW
+ asm volatile(
+ "mov r0, r0" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ }
+ else { // else masked bit is low
+ // SK6812RGBW spec 300ns HIGH
+ // WS2812 spec 350ns HIGH
+ // Adafruit on Arduino (meas. 312ns)
+ // This lib on Spark Core (meas. 305ns)
+ // This lib on Photon (meas. 308ns)
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ // SK6812RGBW spec 900ns LOW
+ // WS2812 spec 800ns LOW
+ // Adafruit on Arduino (meas. 938ns)
+ // This lib on Spark Core (meas. 904ns)
+ // This lib on Photon (meas. 900ns)
+ pinSet(pin, LOW); // LOW
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ }
+ mask >>= 1;
+ } while ( ++j < 32 ); // ... pixel done
+ } // end while(i) ... no more pixels
+ }
+ else if(type == WS2812B2 || type == WS2812B2_FAST) { // WS2812B with DWT timer
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ #define CYCLES_800_T0H 25 // 312ns (meas. 300ns)
+ #define CYCLES_800_T0L 70 // 938ns (meas. 940ns)
+ #define CYCLES_800_T1H 80 // 812ns (meas. 792ns)
+ #define CYCLES_800_T1L 8 // 436ns (meas. 425ns)
+
+ volatile uint32_t cyc;
+
+ while(i) { // While bytes left... (3 bytes = 1 pixel)
+ mask = 0x800000; // reset the mask
+ i = i-3; // decrement bytes remaining
+ g = *ptr++; // Next green byte value
+ r = *ptr++; // Next red byte value
+ b = *ptr++; // Next blue byte value
+ c = ((uint32_t)g << 16) | ((uint32_t)r << 8) | b; // Pack the next 3 bytes to keep timing tight
+ j = 0; // reset the 24-bit counter
+ do {
+ cyc = DWT->CYCCNT;
+ pinSet(pin, HIGH); // HIGH
+ if (c & mask) { // if masked bit is high
+ while(DWT->CYCCNT - cyc < CYCLES_800_T1H);
+ pinSet(pin, LOW);
+ cyc = DWT->CYCCNT;
+ while(DWT->CYCCNT - cyc < CYCLES_800_T1L);
+ }
+ else { // else masked bit is low
+ while(DWT->CYCCNT - cyc < CYCLES_800_T0H);
+ pinSet(pin, LOW);
+ cyc = DWT->CYCCNT;
+ while(DWT->CYCCNT - cyc < CYCLES_800_T0L);
+ }
+ mask >>= 1;
+ } while ( ++j < 24 ); // ... pixel done
+ } // end while(i) ... no more pixels
+#endif
+ }
+ else if(type == WS2811) { // WS2811, 400 KHz bitstream
+ while(i) { // While bytes left... (3 bytes = 1 pixel)
+ mask = 0x800000; // reset the mask
+ i = i-3; // decrement bytes remaining
+ r = *ptr++; // Next red byte value
+ g = *ptr++; // Next green byte value
+ b = *ptr++; // Next blue byte value
+ c = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; // Pack the next 3 bytes to keep timing tight
+ j = 0; // reset the 24-bit counter
+ do {
+ pinSet(pin, HIGH); // HIGH
+ if (c & mask) { // if masked bit is high
+ // WS2811 spec 1.20us HIGH
+ // Adafruit on Arduino (meas. 1.25us)
+ // This lib on Spark Core (meas. 1.25us)
+ // This lib on Photon (meas. 1.25us)
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ // WS2811 spec 1.30us LOW
+ // Adafruit on Arduino (meas. 1.25us)
+ // This lib on Spark Core (meas. 1.24us)
+ // This lib on Photon (meas. 1.24us)
+ pinSet(pin, LOW); // LOW
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ }
+ else { // else masked bit is low
+ // WS2811 spec 500ns HIGH
+ // Adafruit on Arduino (meas. 500ns)
+ // This lib on Spark Core (meas. 500ns)
+ // This lib on Photon (meas. 500ns)
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#endif
+ "nop" "\n\t" "nop" "\n\t"
+ ::: "r0", "cc", "memory");
+ // WS2811 spec 2.000us LOW
+ // Adafruit on Arduino (meas. 2.000us)
+ // This lib on Spark Core (meas. 2.000us)
+ // This lib on Photon (meas. 2.000us)
+ pinSet(pin, LOW); // LOW
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ }
+ mask >>= 1;
+ } while ( ++j < 24 ); // ... pixel done
+ } // end while(i) ... no more pixels
+ }
+ else if(type == TM1803) { // TM1803 (Radio Shack Tri-Color Strip), 400 KHz bitstream
+ while(i) { // While bytes left... (3 bytes = 1 pixel)
+ mask = 0x800000; // reset the mask
+ i = i-3; // decrement bytes remaining
+ r = *ptr++; // Next red byte value
+ g = *ptr++; // Next blue byte value
+ b = *ptr++; // Next green byte value
+ c = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; // Pack the next 3 bytes to keep timing tight
+ j = 0; // reset the 24-bit counter
+ do {
+ pinSet(pin, HIGH); // HIGH
+ if (c & mask) { // if masked bit is high
+ // TM1803 spec 1.36us HIGH
+ // Pololu on Arduino (meas. 1.31us)
+ // This lib on Spark Core (meas. 1.36us)
+ // This lib on Photon (meas. 1.36us)
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ // TM1803 spec 680ns LOW
+ // Pololu on Arduino (meas. 1.024us)
+ // This lib on Spark Core (meas. 680ns)
+ // This lib on Photon (meas. 684ns)
+ pinSet(pin, LOW); // LOW
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ }
+ else { // else masked bit is low
+ // TM1803 spec 680ns HIGH
+ // Pololu on Arduino (meas. 374ns)
+ // This lib on Spark Core (meas. 680ns)
+ // This lib on Photon (meas. 684ns)
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ // TM1803 spec 1.36us LOW
+ // Pololu on Arduino (meas. 2.00us)
+ // This lib on Spark Core (meas. 1.36us)
+ // This lib on Photon (meas. 1.36us)
+ pinSet(pin, LOW); // LOW
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ }
+ mask >>= 1;
+ } while ( ++j < 24 ); // ... pixel done
+ } // end while(i) ... no more pixels
+ }
+ else { // must be only other option TM1829, 800 KHz bitstream
+ while(i) { // While bytes left... (3 bytes = 1 pixel)
+ mask = 0x800000; // reset the mask
+ i = i-3; // decrement bytes remaining
+ r = *ptr++; // Next red byte value
+ b = *ptr++; // Next blue byte value
+ g = *ptr++; // Next green byte value
+ c = ((uint32_t)r << 16) | ((uint32_t)b << 8) | g; // Pack the next 3 bytes to keep timing tight
+ j = 0; // reset the 24-bit counter
+ pinSet(pin, LOW); // LOW
+ for( ;; ) { // ... pixel done
+ if (c & mask) { // if masked bit is high
+ // TM1829 spec 800ns LOW
+ // This lib on Spark Core (meas. 806ns)
+ // This lib on Photon (meas. 792ns)
+ mask >>= 1; // Do this task during the long delay of this bit
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ j++;
+ // TM1829 spec 300ns HIGH
+ // This lib on Spark Core (meas. 305ns)
+ // This lib on Photon (meas. 300ns)
+ pinSet(pin, HIGH); // HIGH
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ if(j==24) break;
+ pinSet(pin, LOW); // LOW
+ }
+ else { // else masked bit is low
+ // TM1829 spec 300ns LOW
+ // This lib on Spark Core (meas. 390ns)
+ // This lib on Photon (meas. 300ns)
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ asm volatile(
+ "mov r0, r0" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t"
+ ::: "r0", "cc", "memory");
+#endif
+ // TM1829 spec 800ns HIGH
+ // This lib on Spark Core (meas. 792ns)
+ // This lib on Photon (meas. 800ns)
+ pinSet(pin, HIGH); // HIGH
+ j++;
+ mask >>= 1; // Do this task during the long delay of this bit
+ asm volatile(
+ "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88)
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+ "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t"
+#endif
+ ::: "r0", "cc", "memory");
+ if(j==24) break;
+ pinSet(pin, LOW); // LOW
+ }
+ }
+ } // end while(i) ... no more pixels
+ }
+
+ __enable_irq();
+#elif (PLATFORM_ID == 12) || (PLATFORM_ID == 13) || (PLATFORM_ID == 14) // Argon (12), Boron (13), Xenon (14)
+// [[[Begin of the Neopixel NRF52 EasyDMA implementation
+// by the Hackerspace San Salvador]]]
+// This technique uses the PWM peripheral on the NRF52. The PWM uses the
+// EasyDMA feature included on the chip. This technique loads the duty
+// cycle configuration for each cycle when the PWM is enabled. For this
+// to work we need to store a 16 bit configuration for each bit of the
+// RGB(W) values in the pixel buffer.
+// Comparator values for the PWM were hand picked and are guaranteed to
+// be 100% organic to preserve freshness and high accuracy. Current
+// parameters are:
+// * PWM Clock: 16Mhz
+// * Minimum step time: 62.5ns
+// * Time for zero in high (T0H): 0.31ms
+// * Time for one in high (T1H): 0.75ms
+// * Cycle time: 1.25us
+// * Frequency: 800Khz
+// For 400Khz we just double the calculated times.
+// ---------- BEGIN Constants for the EasyDMA implementation -----------
+// The PWM starts the duty cycle in LOW. To start with HIGH we
+// need to set the 15th bit on each register.
+
+// WS2812 (rev A) timing is 0.35 and 0.7us
+//#define MAGIC_T0H 5UL | (0x8000) // 0.3125us
+//#define MAGIC_T1H 12UL | (0x8000) // 0.75us
+
+// WS2812B (rev B) timing is 0.4 and 0.8 us
+#define MAGIC_T0H 6UL | (0x8000) // 0.375us
+#define MAGIC_T1H 13UL | (0x8000) // 0.8125us
+
+// WS2811 (400 khz) timing is 0.5 and 1.2
+#define MAGIC_T0H_400KHz 8UL | (0x8000) // 0.5us
+#define MAGIC_T1H_400KHz 19UL | (0x8000) // 1.1875us
+
+// For 400Khz, we double value of CTOPVAL
+#define CTOPVAL 20UL // 1.25us
+#define CTOPVAL_400KHz 40UL // 2.5us
+
+// ---------- END Constants for the EasyDMA implementation -------------
+//
+// If there is no device available an alternative cycle-counter
+// implementation is tried.
+// The nRF52832 runs with a fixed clock of 64Mhz. The alternative
+// implementation is the same as the one used for the Teensy 3.0/1/2 but
+// with the Nordic SDK HAL & registers syntax.
+// The number of cycles was hand picked and is guaranteed to be 100%
+// organic to preserve freshness and high accuracy.
+// ---------- BEGIN Constants for cycle counter implementation ---------
+#define CYCLES_800_T0H 18 // ~0.36 uS
+#define CYCLES_800_T1H 41 // ~0.76 uS
+#define CYCLES_800 71 // ~1.25 uS
+
+#define CYCLES_400_T0H 26 // ~0.50 uS
+#define CYCLES_400_T1H 70 // ~1.26 uS
+#define CYCLES_400 156 // ~2.50 uS
+// ---------- END of Constants for cycle counter implementation --------
+
+ // To support both the SoftDevice + Neopixels we use the EasyDMA
+ // feature from the NRF25. However this technique implies to
+ // generate a pattern and store it on the memory. The actual
+ // memory used in bytes corresponds to the following formula:
+ // totalMem = numBytes*8*2+(2*2)
+ // The two additional bytes at the end are needed to reset the
+ // sequence.
+ //
+ // If there is not enough memory, we will fall back to cycle counter
+ // using DWT
+ uint32_t pattern_size = numBytes*8*sizeof(uint16_t)+2*sizeof(uint16_t);
+ uint16_t* pixels_pattern = NULL;
+
+ NRF_PWM_Type* pwm = NULL;
+
+ // Try to find a free PWM device, which is not enabled
+ // and has no connected pins
+ NRF_PWM_Type* PWM[3] = {NRF_PWM0, NRF_PWM1, NRF_PWM2};
+ for(int device = 0; device<3; device++) {
+ if( (PWM[device]->ENABLE == 0) &&
+ (PWM[device]->PSEL.OUT[0] & PWM_PSEL_OUT_CONNECT_Msk) &&
+ (PWM[device]->PSEL.OUT[1] & PWM_PSEL_OUT_CONNECT_Msk) &&
+ (PWM[device]->PSEL.OUT[2] & PWM_PSEL_OUT_CONNECT_Msk) &&
+ (PWM[device]->PSEL.OUT[3] & PWM_PSEL_OUT_CONNECT_Msk)
+ ) {
+ pwm = PWM[device];
+ break;
+ }
+ }
+
+ // only malloc if there is PWM device available
+ if ( pwm != NULL ) {
+ #ifdef ARDUINO_FEATHER52 // use thread-safe malloc
+ pixels_pattern = (uint16_t *) rtos_malloc(pattern_size);
+ #else
+ pixels_pattern = (uint16_t *) malloc(pattern_size);
+ #endif
+ }
+
+ // Use the identified device to choose the implementation
+ // If a PWM device is available use DMA
+ if( (pixels_pattern != NULL) && (pwm != NULL) ) {
+ uint16_t pos = 0; // bit position
+
+ for(uint16_t n=0; n0; mask >>= 1, i++) {
+ #ifdef NEO_KHZ400
+ if( !is800KHz ) {
+ pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H_400KHz : MAGIC_T0H_400KHz;
+ }else
+ #endif
+ {
+ pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H : MAGIC_T0H;
+ }
+
+ pos++;
+ }
+ }
+
+ // Zero padding to indicate the end of que sequence
+ pixels_pattern[++pos] = 0 | (0x8000); // Seq end
+ pixels_pattern[++pos] = 0 | (0x8000); // Seq end
+
+ // Set the wave mode to count UP
+ pwm->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
+
+ // Set the PWM to use the 16MHz clock
+ pwm->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos);
+
+ // Setting of the maximum count
+ // but keeping it on 16Mhz allows for more granularity just
+ // in case someone wants to do more fine-tuning of the timing.
+#ifdef NEO_KHZ400
+ if( !is800KHz ) {
+ pwm->COUNTERTOP = (CTOPVAL_400KHz << PWM_COUNTERTOP_COUNTERTOP_Pos);
+ }else
+#endif
+ {
+ pwm->COUNTERTOP = (CTOPVAL << PWM_COUNTERTOP_COUNTERTOP_Pos);
+ }
+
+ // Disable loops, we want the sequence to repeat only once
+ pwm->LOOP = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos);
+
+ // On the "Common" setting the PWM uses the same pattern for the
+ // for supported sequences. The pattern is stored on half-word
+ // of 16bits
+ pwm->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) |
+ (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
+
+ // Pointer to the memory storing the patter
+ pwm->SEQ[0].PTR = (uint32_t)(pixels_pattern) << PWM_SEQ_PTR_PTR_Pos;
+
+ // Calculation of the number of steps loaded from memory.
+ pwm->SEQ[0].CNT = (pattern_size/sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos;
+
+ // The following settings are ignored with the current config.
+ pwm->SEQ[0].REFRESH = 0;
+ pwm->SEQ[0].ENDDELAY = 0;
+
+ // The Neopixel implementation is a blocking algorithm. DMA
+ // allows for non-blocking operation. To "simulate" a blocking
+ // operation we enable the interruption for the end of sequence
+ // and block the execution thread until the event flag is set by
+ // the peripheral.
+// pwm->INTEN |= (PWM_INTEN_SEQEND0_Enabled<PSEL.OUT[0] = NRF_GPIO_PIN_MAP(PIN_MAP2[pin].gpio_port, PIN_MAP2[pin].gpio_pin);
+
+ // Enable the PWM
+ pwm->ENABLE = 1;
+
+ // After all of this and many hours of reading the documentation
+ // we are ready to start the sequence...
+ pwm->EVENTS_SEQEND[0] = 0;
+ pwm->TASKS_SEQSTART[0] = 1;
+
+ // But we have to wait for the flag to be set.
+ while(!pwm->EVENTS_SEQEND[0])
+ {
+ #ifdef ARDUINO_FEATHER52
+ yield();
+ #endif
+ }
+
+ // Before leave we clear the flag for the event.
+ pwm->EVENTS_SEQEND[0] = 0;
+
+ // We need to disable the device and disconnect
+ // all the outputs before leave or the device will not
+ // be selected on the next call.
+ // TODO: Check if disabling the device causes performance issues.
+ pwm->ENABLE = 0;
+
+ pwm->PSEL.OUT[0] = 0xFFFFFFFFUL;
+
+ #ifdef ARDUINO_FEATHER52 // use thread-safe free
+ rtos_free(pixels_pattern);
+ #else
+ free(pixels_pattern);
+ #endif
+ }// End of DMA implementation
+ // ---------------------------------------------------------------------
+ else{
+ // Fall back to DWT
+ #ifdef ARDUINO_FEATHER52
+ // Bluefruit Feather 52 uses freeRTOS
+ // Critical Section is used since it does not block SoftDevice execution
+ taskENTER_CRITICAL();
+ #elif defined(NRF52_DISABLE_INT)
+ // If you are using the Bluetooth SoftDevice we advise you to not disable
+ // the interrupts. Disabling the interrupts even for short periods of time
+ // causes the SoftDevice to stop working.
+ // Disable the interrupts only in cases where you need high performance for
+ // the LEDs and if you are not using the EasyDMA feature.
+ __disable_irq();
+ #endif
+
+ uint32_t pinMask = 1UL << NRF_GPIO_PIN_MAP(PIN_MAP2[pin].gpio_port, PIN_MAP2[pin].gpio_pin);
+
+
+ uint32_t CYCLES_X00 = CYCLES_800;
+ uint32_t CYCLES_X00_T1H = CYCLES_800_T1H;
+ uint32_t CYCLES_X00_T0H = CYCLES_800_T0H;
+
+#ifdef NEO_KHZ400
+ if( !is800KHz )
+ {
+ CYCLES_X00 = CYCLES_400;
+ CYCLES_X00_T1H = CYCLES_400_T1H;
+ CYCLES_X00_T0H = CYCLES_400_T0H;
+ }
+#endif
+
+ // Enable DWT in debug core
+ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+ DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+
+ // Tries to re-send the frame if is interrupted by the SoftDevice.
+ while(1) {
+ uint8_t *p = pixels;
+
+ uint32_t cycStart = DWT->CYCCNT;
+ uint32_t cyc = 0;
+
+ for(uint16_t n=0; n>= 1) {
+ while(DWT->CYCCNT - cyc < CYCLES_X00);
+ cyc = DWT->CYCCNT;
+
+ NRF_GPIO->OUTSET |= pinMask;
+
+ if(pix & mask) {
+ while(DWT->CYCCNT - cyc < CYCLES_X00_T1H);
+ } else {
+ while(DWT->CYCCNT - cyc < CYCLES_X00_T0H);
+ }
+
+ NRF_GPIO->OUTCLR |= pinMask;
+ }
+ }
+ while(DWT->CYCCNT - cyc < CYCLES_X00);
+
+
+ // If total time longer than 25%, resend the whole data.
+ // Since we are likely to be interrupted by SoftDevice
+ if ( (DWT->CYCCNT - cycStart) < ( 8*numBytes*((CYCLES_X00*5)/4) ) ) {
+ break;
+ }
+
+ // re-send need 300us delay
+ delayMicroseconds(300);
+ }
+
+ // Enable interrupts again
+ #ifdef ARDUINO_FEATHER52
+ taskEXIT_CRITICAL();
+ #elif defined(NRF52_DISABLE_INT)
+ __enable_irq();
+ #endif
+ }
+// END of NRF52 implementation
+
+
+#endif
+ endTime = micros(); // Save EOD time for latch on next call
+}
+
+// Set pixel color from separate R,G,B components:
+void Adafruit_NeoPixel::setPixelColor(
+ uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
+ if(n < numLEDs) {
+ if(brightness) { // See notes in setBrightness()
+ r = (r * brightness) >> 8;
+ g = (g * brightness) >> 8;
+ b = (b * brightness) >> 8;
+ }
+ uint8_t *p = &pixels[n * 3];
+ switch(type) {
+ case WS2812B: // WS2812, WS2812B & WS2813 is GRB order.
+ case WS2812B_FAST:
+ case WS2812B2:
+ case WS2812B2_FAST: {
+ *p++ = g;
+ *p++ = r;
+ *p = b;
+ } break;
+ case TM1829: { // TM1829 is special RBG order
+ if(r == 255) r = 254; // 255 on RED channel causes display to be in a special mode.
+ *p++ = r;
+ *p++ = b;
+ *p = g;
+ } break;
+ case WS2811: // WS2811 is RGB order
+ case TM1803: // TM1803 is RGB order
+ default: { // default is RGB order
+ *p++ = r;
+ *p++ = g;
+ *p = b;
+ } break;
+ }
+ }
+}
+
+// Set pixel color from separate R,G,B,W components:
+void Adafruit_NeoPixel::setPixelColor(
+ uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
+ if(n < numLEDs) {
+ if(brightness) { // See notes in setBrightness()
+ r = (r * brightness) >> 8;
+ g = (g * brightness) >> 8;
+ b = (b * brightness) >> 8;
+ w = (w * brightness) >> 8;
+ }
+ uint8_t *p = &pixels[n * (type==SK6812RGBW?4:3)];
+ switch(type) {
+ case WS2812B: // WS2812, WS2812B & WS2813 is GRB order.
+ case WS2812B_FAST:
+ case WS2812B2:
+ case WS2812B2_FAST: {
+ *p++ = g;
+ *p++ = r;
+ *p = b;
+ } break;
+ case TM1829: { // TM1829 is special RBG order
+ if(r == 255) r = 254; // 255 on RED channel causes display to be in a special mode.
+ *p++ = r;
+ *p++ = b;
+ *p = g;
+ } break;
+ case SK6812RGBW: { // SK6812RGBW is RGBW order
+ *p++ = r;
+ *p++ = g;
+ *p++ = b;
+ *p = w;
+ } break;
+ case WS2811: // WS2811 is RGB order
+ case TM1803: // TM1803 is RGB order
+ default: { // default is RGB order
+ *p++ = r;
+ *p++ = g;
+ *p = b;
+ } break;
+ }
+ }
+}
+
+// Set pixel color from 'packed' 32-bit RGB color:
+// If RGB+W color, order of bytes is WRGB in packed 32-bit form
+void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) {
+ if(n < numLEDs) {
+ uint8_t
+ r = (uint8_t)(c >> 16),
+ g = (uint8_t)(c >> 8),
+ b = (uint8_t)c;
+ if(brightness) { // See notes in setBrightness()
+ r = (r * brightness) >> 8;
+ g = (g * brightness) >> 8;
+ b = (b * brightness) >> 8;
+ }
+ uint8_t *p = &pixels[n * (type==SK6812RGBW?4:3)];
+ switch(type) {
+ case WS2812B: // WS2812, WS2812B & WS2813 is GRB order.
+ case WS2812B_FAST:
+ case WS2812B2:
+ case WS2812B2_FAST: {
+ *p++ = g;
+ *p++ = r;
+ *p = b;
+ } break;
+ case TM1829: { // TM1829 is special RBG order
+ if(r == 255) r = 254; // 255 on RED channel causes display to be in a special mode.
+ *p++ = r;
+ *p++ = b;
+ *p = g;
+ } break;
+ case SK6812RGBW: { // SK6812RGBW is RGBW order
+ uint8_t w = (uint8_t)(c >> 24);
+ *p++ = r;
+ *p++ = g;
+ *p++ = b;
+ *p = brightness ? ((w * brightness) >> 8) : w;
+ } break;
+ case WS2811: // WS2811 is RGB order
+ case TM1803: // TM1803 is RGB order
+ default: { // default is RGB order
+ *p++ = r;
+ *p++ = g;
+ *p = b;
+ } break;
+ }
+ }
+}
+
+void Adafruit_NeoPixel::setColor(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue) {
+ return setPixelColor(aLedNumber, (uint8_t) aRed, (uint8_t) aGreen, (uint8_t) aBlue);
+}
+
+void Adafruit_NeoPixel::setColor(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite) {
+ return setPixelColor(aLedNumber, (uint8_t) aRed, (uint8_t) aGreen, (uint8_t) aBlue, (uint8_t) aWhite);
+}
+
+void Adafruit_NeoPixel::setColorScaled(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aScaling) {
+ // scale RGB with a common brightness parameter
+ setColor(aLedNumber, (aRed*aScaling)>>8, (aGreen*aScaling)>>8, (aBlue*aScaling)>>8);
+}
+
+void Adafruit_NeoPixel::setColorScaled(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite, byte aScaling) {
+ // scale RGB with a common brightness parameter
+ setColor(aLedNumber, (aRed*aScaling)>>8, (aGreen*aScaling)>>8, (aBlue*aScaling)>>8, (aWhite*aScaling)>>8);
+}
+
+void Adafruit_NeoPixel::setColorDimmed(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aBrightness) {
+ setColorScaled(aLedNumber, aRed, aGreen, aBlue, brightnessToPWM(aBrightness));
+}
+
+void Adafruit_NeoPixel::setColorDimmed(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite, byte aBrightness) {
+ setColorScaled(aLedNumber, aRed, aGreen, aBlue, aWhite, brightnessToPWM(aBrightness));
+}
+
+byte Adafruit_NeoPixel::brightnessToPWM(byte aBrightness) {
+ static const byte pwmLevels[16] = { 0, 1, 2, 3, 4, 6, 8, 12, 23, 36, 48, 70, 95, 135, 190, 255 };
+ return pwmLevels[aBrightness>>4];
+}
+
+// Convert separate R,G,B into packed 32-bit RGB color.
+// Packed format is always RGB, regardless of LED strand color order.
+uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) {
+ return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
+}
+
+// Convert separate R,G,B,W into packed 32-bit WRGB color.
+// Packed format is always WRGB, regardless of LED strand color order.
+uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
+ return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
+}
+
+// Query color from previously-set pixel (returns packed 32-bit RGB value)
+uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const {
+ if(n >= numLEDs) {
+ // Out of bounds, return no color.
+ return 0;
+ }
+
+ uint8_t *p = &pixels[n * (type==SK6812RGBW?4:3)];
+ uint32_t c;
+
+ switch(type) {
+ case WS2812B: // WS2812, WS2812B & WS2813 is GRB order.
+ case WS2812B_FAST:
+ case WS2812B2:
+ case WS2812B2_FAST: {
+ c = ((uint32_t)p[1] << 16) | ((uint32_t)p[0] << 8) | (uint32_t)p[2];
+ } break;
+ case TM1829: { // TM1829 is special RBG order
+ c = ((uint32_t)p[0] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[1];
+ } break;
+ case SK6812RGBW: { // SK6812RGBW is RGBW order, but returns packed WRGB color
+ c = ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
+ } break;
+ case WS2811: // WS2811 is RGB order
+ case TM1803: // TM1803 is RGB order
+ default: { // default is RGB order
+ c = ((uint32_t)p[0] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[2];
+ } break;
+ }
+
+ // Adjust this back up to the true color, as setting a pixel color will
+ // scale it back down again.
+ if(brightness) { // See notes in setBrightness()
+ //Cast the color to a byte array
+ uint8_t * c_ptr =reinterpret_cast(&c);
+ if (type == SK6812RGBW) {
+ c_ptr[3] = (c_ptr[3] << 8)/brightness;
+ }
+ c_ptr[0] = (c_ptr[0] << 8)/brightness;
+ c_ptr[1] = (c_ptr[1] << 8)/brightness;
+ c_ptr[2] = (c_ptr[2] << 8)/brightness;
+ }
+ return c; // Pixel # is out of bounds
+}
+
+uint8_t *Adafruit_NeoPixel::getPixels(void) const {
+ return pixels;
+}
+
+uint16_t Adafruit_NeoPixel::numPixels(void) const {
+ return numLEDs;
+}
+
+uint16_t Adafruit_NeoPixel::getNumLeds(void) const {
+ return numPixels();
+}
+
+// Adjust output brightness; 0=darkest (off), 255=brightest. This does
+// NOT immediately affect what's currently displayed on the LEDs. The
+// next call to show() will refresh the LEDs at this level. However,
+// this process is potentially "lossy," especially when increasing
+// brightness. The tight timing in the WS2811/WS2812 code means there
+// aren't enough free cycles to perform this scaling on the fly as data
+// is issued. So we make a pass through the existing color data in RAM
+// and scale it (subsequent graphics commands also work at this
+// brightness level). If there's a significant step up in brightness,
+// the limited number of steps (quantization) in the old data will be
+// quite visible in the re-scaled version. For a non-destructive
+// change, you'll need to re-render the full strip data. C'est la vie.
+void Adafruit_NeoPixel::setBrightness(uint8_t b) {
+ // Stored brightness value is different than what's passed.
+ // This simplifies the actual scaling math later, allowing a fast
+ // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t,
+ // adding 1 here may (intentionally) roll over...so 0 = max brightness
+ // (color values are interpreted literally; no scaling), 1 = min
+ // brightness (off), 255 = just below max brightness.
+ uint8_t newBrightness = b + 1;
+ if(newBrightness != brightness) { // Compare against prior value
+ // Brightness has changed -- re-scale existing data in RAM
+ uint8_t c,
+ *ptr = pixels,
+ oldBrightness = brightness - 1; // De-wrap old brightness value
+ uint16_t scale;
+ if(oldBrightness == 0) scale = 0; // Avoid /0
+ else if(b == 255) scale = 65535 / oldBrightness;
+ else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness;
+ for(uint16_t i=0; i> 8;
+ }
+ brightness = newBrightness;
+ }
+}
+
+//Return the brightness value
+uint8_t Adafruit_NeoPixel::getBrightness(void) const {
+ return brightness - 1;
+}
+
+void Adafruit_NeoPixel::clear(void) {
+ memset(pixels, 0, numBytes);
+}
+
diff --git a/src/neopixel.h b/src/neopixel.h
new file mode 100644
index 0000000..a83f041
--- /dev/null
+++ b/src/neopixel.h
@@ -0,0 +1,127 @@
+/*-------------------------------------------------------------------------
+ Particle Core, Particle Photon, P1, Electron, Argon, Boron, Xenon and
+ RedBear Duo library to control WS2811/WS2812/WS2813 based RGB LED
+ devices such as Adafruit NeoPixel strips.
+
+ Supports:
+ - 800 KHz WS2812, WS2812B, WS2813 and 400kHz bitstream and WS2811
+ - 800 KHz bitstream SK6812RGBW (NeoPixel RGBW pixel strips)
+ (use 'SK6812RGBW' as PIXEL_TYPE)
+
+ Also supports:
+ - Radio Shack Tri-Color Strip with TM1803 controller 400kHz bitstream.
+ - TM1829 pixels
+
+ PLEASE NOTE that the NeoPixels require 5V level inputs
+ and the supported microcontrollers only have 3.3V level outputs. Level
+ shifting is necessary, but will require a fast device such as one of
+ the following:
+
+ [SN74HCT125N]
+ http://www.digikey.com/product-detail/en/SN74HCT125N/296-8386-5-ND/376860
+
+ [SN74HCT245N]
+ http://www.digikey.com/product-detail/en/SN74HCT245N/296-1612-5-ND/277258
+
+ Written by Phil Burgess / Paint Your Dragon for Adafruit Industries.
+ Modified to work with Particle devices by Technobly.
+ Contributions by PJRC and other members of the open source community.
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing products
+ from Adafruit!
+ --------------------------------------------------------------------*/
+
+/* ======================= neopixel.h ======================= */
+/*--------------------------------------------------------------------
+ This file is part of the Adafruit NeoPixel library.
+
+ NeoPixel is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ NeoPixel is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with NeoPixel. If not, see
+ .
+ --------------------------------------------------------------------*/
+
+#ifndef PARTICLE_NEOPIXEL_H
+#define PARTICLE_NEOPIXEL_H
+
+#include "Particle.h"
+
+// 'type' flags for LED pixels (third parameter to constructor):
+#define WS2811 0x00 // 400 KHz datastream (NeoPixel)
+#define WS2812 0x02 // 800 KHz datastream (NeoPixel)
+#define WS2812B 0x02 // 800 KHz datastream (NeoPixel)
+#define WS2813 0x02 // 800 KHz datastream (NeoPixel)
+#define TM1803 0x03 // 400 KHz datastream (Radio Shack Tri-Color Strip)
+#define TM1829 0x04 // 800 KHz datastream ()
+#define WS2812B2 0x05 // 800 KHz datastream (NeoPixel)
+#define SK6812RGBW 0x06 // 800 KHz datastream (NeoPixel RGBW)
+#define WS2812B_FAST 0x07 // 800 KHz datastream (NeoPixel)
+#define WS2812B2_FAST 0x08 // 800 KHz datastream (NeoPixel)
+
+class Adafruit_NeoPixel {
+
+ public:
+
+ // Constructor: number of LEDs, pin number, LED type
+ Adafruit_NeoPixel(uint16_t n, uint8_t p=2, uint8_t t=WS2812B);
+ ~Adafruit_NeoPixel();
+
+ void
+ begin(void),
+ show(void) __attribute__((optimize("Ofast"))),
+ setPin(uint8_t p),
+ setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
+ setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w),
+ setPixelColor(uint16_t n, uint32_t c),
+ setBrightness(uint8_t),
+ setColor(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue),
+ setColor(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite),
+ setColorScaled(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aScaling),
+ setColorScaled(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite, byte aScaling),
+ setColorDimmed(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aBrightness),
+ setColorDimmed(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite, byte aBrightness),
+ updateLength(uint16_t n),
+ clear(void);
+ uint8_t
+ *getPixels() const,
+ getBrightness(void) const;
+ uint16_t
+ numPixels(void) const,
+ getNumLeds(void) const;
+ static uint32_t
+ Color(uint8_t r, uint8_t g, uint8_t b),
+ Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w);
+ uint32_t
+ getPixelColor(uint16_t n) const;
+ byte
+ brightnessToPWM(byte aBrightness);
+
+ private:
+
+ bool
+ begun; // true if begin() previously called
+ uint16_t
+ numLEDs, // Number of RGB LEDs in strip
+ numBytes; // Size of 'pixels' buffer below
+ const uint8_t
+ type; // Pixel type flag (400 vs 800 KHz)
+ uint8_t
+ pin, // Output pin number
+ brightness,
+ *pixels; // Holds LED color values (3 bytes each)
+ uint32_t
+ endTime; // Latch timing reference
+};
+
+#endif // PARTICLE_NEOPIXEL_H
+
diff --git a/src/touch_light.ino b/src/touch_light.ino
index 431a919..8aec4fd 100644
--- a/src/touch_light.ino
+++ b/src/touch_light.ino
@@ -2,9 +2,16 @@
* Project: touch_light
* Description: A touch light that syncs with other touch lights. Adapted from
* http://www.instructables.com/id/Networked-RGB-Wi-Fi-Decorative-Touch-Lights/
- * Author: Patrick Blesi
+ *
+ * Original Author: Patrick Blesi
* Date: 2017-12-09
*
+ * Modifications By: Jeff Bush (coderforlife)
+ * Date: 2018-12-21
+ *
+ * Added feature for Turning Off after 3 TAPS By: nikostito
+ * Date: 2021-4-20
+ *
*/
#include "neopixel.h"
@@ -22,11 +29,8 @@ String touchEventName = "touch_event";
#define NUM_PARTICLES 4 // number of touch lights in your group
// Number each Filimin starting at 1.
String particleId[] = {
- "", // 0
- "330022001547353236343033", // pblesi
- "2d0047001247353236343033", // carol
- "2a0026000b47353235303037", // cindy
- "2e003e001947353236343033" // tammy
+ "", // 0
+ //add your own ids. Reducted for privacy
};
int particleColors[] = {
@@ -37,6 +41,9 @@ int particleColors[] = {
131 // Purple
};
+
+#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
+
// TWEAKABLE VALUES FOR CAP SENSING. THE BELOW VALUES WORK WELL AS A STARTING PLACE:
// BASELINE_VARIANCE: The higher the number the less the baseline is affected by
// current readings. (was 4)
@@ -59,13 +66,15 @@ const int minMaxColorDiffs[2][2] = {
// END VALUE, TIME
// 160 is approximately 1 second
-const long envelopes[6][2] = {
- {0, 0}, // NOT USED
- {255, 30}, // ATTACK
- {200, 240}, // DECAY
- {200, 1000}, // SUSTAIN
- {150, 60}, // RELEASE1
- {0, 1000000} // RELEASE2 (65535 is about 6'45")
+const long envelopes[8][2] = {
+ {0, 0}, // NOT USED
+ {255, 30}, // ATTACK ~200 ms
+ {205, 240}, // DECAY ~1.5 sec
+ {205, 1000}, // SUSTAIN ~6.25 sec
+ {155, 60}, // RELEASE1 ~400 ms to go from ~80% brightness to ~60% brightness
+ {40, 300000}, // RELEASE2 ~30 min to go from ~60% brightness to ~15% brightness
+ {10, 300000}, // RELEASE3 ~30 min to go from ~15% brightness to ~4% brightness
+ {0, 0}, // HOLD will be held at ~0% brightness forever
};
#define PERIODIC_UPDATE_TIME 5 // seconds
@@ -79,7 +88,9 @@ const long envelopes[6][2] = {
#define SUSTAIN 3
#define RELEASE1 4
#define RELEASE2 5
-#define OFF 6
+#define RELEASE3 6
+#define HOLD 7
+#define OFF 8
#define LOCAL_CHANGE 0
#define REMOTE_CHANGE 1
@@ -99,7 +110,8 @@ String eventTypes[] = {
int sPin = D4;
int rPin = D3;
-
+//Variable for checking user taps without response.
+int TAPS = 0;
// NEOPIXEL
#define PIXEL_PIN D2
#define PIXEL_COUNT 24
@@ -109,7 +121,7 @@ int rPin = D3;
unsigned char myId = 0;
int currentEvent = tEVENT_NONE;
-int eventTime = Time.now();
+int eventTime = 0;
int eventTimePrecision = random(INT_MAX);
int initColor = 0;
@@ -165,7 +177,7 @@ void setup()
pinMode(sPin, OUTPUT);
attachInterrupt(rPin, touchSense, RISING);
- myId = getMyId(particleId, NUM_PARTICLES);
+ myId = getMyId(particleId, ARRAY_SIZE(particleId));
flashWhite(&strip);
@@ -179,14 +191,13 @@ void setup()
void loop() {
int touchEvent = touchEventCheck();
- int now = Time.now();
if (touchEvent == tEVENT_NONE) {
// Publish periodic updates to synchronize state
bool touchedBefore = currentEvent != tEVENT_NONE;
- if (lastPeriodicUpdate < now - PERIODIC_UPDATE_TIME && touchedBefore) {
+ if (lastPeriodicUpdate < Time.now() - PERIODIC_UPDATE_TIME && touchedBefore) {
publishTouchEvent(currentEvent, finalColor, eventTime, eventTimePrecision);
- lastPeriodicUpdate = now;
+ lastPeriodicUpdate = Time.now();
}
return;
}
@@ -194,13 +205,25 @@ void loop() {
// Random eventTimePrecision prevents ties with other
// server events. This allows us to determine dominant
// color in the event of ties.
- setEvent(touchEvent, now, random(INT_MAX));
+ setEvent(touchEvent, Time.now(), random(INT_MAX));
if (D_SERIAL) Serial.println(eventTypes[touchEvent]);
if (touchEvent == tEVENT_TOUCH) {
- int newColor = generateColor(finalColor, prevState, lastColorChangeDeviceId);
- setColor(newColor, prevState, myId);
- changeState(ATTACK, LOCAL_CHANGE);
+ TAPS +=1;
+
+ if(TAPS >=3 && state != HOLD){ //HOLD === 7
+ changeState(HOLD, LOCAL_CHANGE);
+ fade(&strip);
+ }
+ else{
+ int newColor = generateColor(finalColor, prevState, lastColorChangeDeviceId);
+ setColor(newColor, prevState, myId);
+
+ changeState(ATTACK, LOCAL_CHANGE);
+ }
+ //for debugging
+ String Test = String(TAPS)+ "," + String(state);
+ Particle.publish("TAPS,STATE", Test, 60, PRIVATE);
}
}
@@ -257,19 +280,17 @@ void traverseColorWheel(Adafruit_NeoPixel* strip) {
strip->setPixelColor(j, color);
strip->show();
}
- delay(1);
}
}
void fade(Adafruit_NeoPixel* strip) {
int numPixels = strip->numPixels();
- for (int j = 255; j >= 0; j--) {
+ for (int j = 255; j >= 0; j-=2) {
uint32_t color = wheelColor(255, j);
for (byte k = 0; k < numPixels; k++) {
strip->setPixelColor(k, color);
strip->show();
}
- delay(1);
}
}
@@ -281,8 +302,6 @@ void fade(Adafruit_NeoPixel* strip) {
long touchSampling() {
long tDelay = 0;
int mSample = 0;
- static int timeout = 10000; // Timeout after 10000 failed readings
- int num_readings = 0;
for (int i = 0; i < SAMPLE_SIZE; i++) {
if (!(i % SAMPLES_BETWEEN_PIXEL_UPDATES)) {
@@ -293,14 +312,12 @@ long touchSampling() {
digitalWrite(rPin,LOW);
pinMode(rPin,INPUT); // revert to high impedance input
// timestamp & transition sPin to HIGH and wait for interrupt in a read loop
- num_readings = 0;
tS = micros();
tR = tS;
digitalWrite(sPin,HIGH);
do {
// wait for transition
- num_readings++;
- } while (digitalRead(rPin)==LOW && num_readings < timeout);
+ } while (digitalRead(rPin)==LOW);
// accumulate the RC delay samples
// ignore readings when micros() overflows
@@ -421,8 +438,8 @@ void handleTouchEvent(const char *event, const char *data) {
Particle.publish("touch_response", response, 61, PRIVATE);
}
- if (deviceId == myId) return;
- if (serverEventTime < eventTime) return;
+ if (deviceId == myId) { return; }
+ if (serverEventTime < eventTime) { return; }
// Race condition brought colors out of sync
if (
serverEventTime == eventTime &&
@@ -430,21 +447,28 @@ void handleTouchEvent(const char *event, const char *data) {
serverColor != finalColor &&
myId < deviceId
) {
- setColor(serverColor, prevState, deviceId);
- changeState(ATTACK, REMOTE_CHANGE);
- return;
+ if(state!= HOLD){
+ setColor(serverColor, prevState, deviceId);
+ changeState(ATTACK, REMOTE_CHANGE);
+ TAPS = 0;
+ return;
+ }
+ else{return;}
}
- if (serverEventTime == eventTime && serverEventTimePrecision <= eventTimePrecision) return;
+ if (serverEventTime == eventTime && serverEventTimePrecision <= eventTimePrecision) { return; }
// Valid remote update
setEvent(serverEvent, serverEventTime, serverEventTimePrecision);
-
- if (serverEvent == tEVENT_TOUCH) {
- setColor(serverColor, prevState, deviceId);
- changeState(ATTACK, REMOTE_CHANGE);
- } else {
- changeState(RELEASE1, REMOTE_CHANGE);
+ if(state!= HOLD){
+ if (serverEvent == tEVENT_TOUCH) {
+ setColor(serverColor, prevState, deviceId);
+ changeState(ATTACK, REMOTE_CHANGE);
+ TAPS = 0;
+ } else {
+ changeState(RELEASE1, REMOTE_CHANGE);
+ }
}
+ else{return;}
}
void setColor(int color, unsigned char prevState, unsigned char deviceId) {
@@ -491,6 +515,9 @@ void changeState(unsigned char newState, int remoteChange) {
if (D_SERIAL) { Serial.print("state: "); Serial.println(newState); }
if (remoteChange) return;
+ if(newState == HOLD){
+ TAPS = 0;
+ }
if (newState == ATTACK || newState == RELEASE1) {
publishTouchEvent(currentEvent, finalColor, eventTime, eventTimePrecision);
@@ -530,9 +557,19 @@ void updateState() {
break;
case RELEASE2:
if (loopCount >= envelopes[RELEASE2][TIME]) {
- changeState(OFF, LOCAL_CHANGE);
+ changeState(RELEASE3, LOCAL_CHANGE);
+ }
+ break;
+ case RELEASE3:
+ if (loopCount >= envelopes[RELEASE3][TIME]) {
+ changeState(HOLD, LOCAL_CHANGE);
}
break;
+ case HOLD:
+ /*if (loopCount >= envelopes[HOLD][TIME]) {
+ changeState(OFF, LOCAL_CHANGE);
+ }*/
+ break;
}
currentBrightness = getCurrentBrightness(state, initBrightness, loopCount);
@@ -548,6 +585,7 @@ void updateState() {
int getCurrentBrightness(unsigned char state, int initBrightness, int loopCount) {
if (state == OFF) return 0;
+ if (envelopes[state][TIME] == 0) return envelopes[state][END_VALUE];
int brightnessDistance = envelopes[state][END_VALUE] - initBrightness;
int brightnessDistanceXElapsedTime = brightnessDistance * loopCount / envelopes[state][TIME];
return min(255, max(0, initBrightness + brightnessDistanceXElapsedTime));
@@ -561,14 +599,13 @@ int getCurrentColor(int finalColor, int initColor, int colorLoopCount) {
}
int calcColorChange(int currentColor, int finalColor) {
- int colorChange = finalColor - currentColor;
- int direction = (colorChange < 0) * 2 - 1;
- colorChange += direction * (abs(colorChange) > 127) * 256;
- return colorChange;
+ int d = currentColor - finalColor;
+ return abs(d) > 127 ? d : -d;
}
void updateNeoPixels(uint32_t color) {
- for(char i = 0; i < strip.numPixels(); i++) {
+ uint16_t n = strip.numPixels();
+ for (char i = 0; i < n; i++) {
strip.setPixelColor(i, color);
}
strip.show();
@@ -581,27 +618,26 @@ void updateNeoPixels(uint32_t color) {
// Wheel
//------------------------------------------------------------
-uint32_t wheelColor(byte WheelPos, byte iBrightness) {
- float R, G, B;
- float brightness = iBrightness / 255.0;
-
- if (WheelPos < 85) {
- R = WheelPos * 3;
- G = 255 - WheelPos * 3;
- B = 0;
- } else if (WheelPos < 170) {
- WheelPos -= 85;
- R = 255 - WheelPos * 3;
- G = 0;
- B = WheelPos * 3;
- } else {
- WheelPos -= 170;
- R = 0;
- G = WheelPos * 3;
- B = 255 - WheelPos * 3;
- }
- R = R * brightness + .5;
- G = G * brightness + .5;
- B = B * brightness + .5;
- return strip.Color((byte) R,(byte) G,(byte) B);
+byte scale(byte x, float scale) {
+ return (byte)(x * scale + .5);
}
+
+// Converts HSV color to RGB color
+// hue is from 0 to 255 around the circle
+// saturation is fixed to max
+// value (brightness) is from 0 to 255
+uint32_t wheelColor(byte hue, byte value) {
+ //hue %= 256;
+ //if (hue < 0) { hue += 256; }
+ int H6 = 6*(int)hue;
+ byte R = 0, G = 0, B = 0;
+ // each 1/6 of a circle (42.5 is 1/6 of 255)
+ if (hue < 43) { R = 255; G = H6; }
+ else if (hue < 86) { R = 510-H6; G = 255; }
+ else if (hue < 128) { G = 255; B = H6-510; }
+ else if (hue < 171) { G = 1020-H6; B = 255; }
+ else if (hue < 213) { R = H6-1020; B = 255; }
+ else { R = 255; B = 1530-H6; }
+ float brightness = value / 255.0;
+ return strip.Color(scale(R, brightness), scale(G, brightness), scale(B, brightness));
+}
\ No newline at end of file
diff --git a/src/wifi_creds.h b/src/wifi_creds.h
index 7b352ff..913062d 100644
--- a/src/wifi_creds.h
+++ b/src/wifi_creds.h
@@ -12,12 +12,12 @@
*/
// Uncomment the line below if specifying credentials in this file
-// #define WIFI_CREDENTIALS_SPECIFIED
+#define WIFI_CREDENTIALS_SPECIFIED
// See https://docs.particle.io/reference/firmware/photon/#setcredentials- for details
struct credentials { char *ssid; char *password; int authType; int cipher; };
const credentials wifiCreds[] = {
// Set wifi creds here (up to 5) (last entry will be tried first)
- // {.ssid="SSID", .password="password", .authType=WPA2, .cipher=WLAN_CIPHER_AES}
-};
+ {.ssid="WIFINAME", .password="WIFIPASSWORD", .authType=WPA2, .cipher=WLAN_CIPHER_AES}
+};
\ No newline at end of file