Need help exiting rainbowCycle loop using Bluefruit Flora

I need help if someone has a moment.

I have been searching for the answer to my issue for over 2 weeks. I have been pointed towards some solutions but just can't wrap my head around how to apply them to my code.

I have successfully coded my controller to work with my Bluetooth app in the first 4 modes, but when one of the rainbow buttons gets pressed, it gets stuck in the dreaded never ending rainbow loop.

I have been exploring interrupts but nothing is working so far.

I'm using a ATmega382p 3.3v 8MHz

I will post code in this thread.

Dee

// Bluetooth shoes tinylilly --

// Works with Bluefruit LE Connect app on iOS or Android --
// pick colors or use buttons to select modes.
// if space is VERY tight...helps to use Arduino IDE
// 1.6.4 or later; produces slightly smaller code than the 1.0.X releases.

// BLUEFRUIT LE UART FRIEND MUST BE SWITCHED TO 'UART' MODE

#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__         
#endif

#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"

#define RX_PIN    2            // Connect this pin to BLE 'TX' pin
#define TX_PIN    1            // Connect this pin to BLE 'RX' pin 2
#define LED_PIN   3            // Connect NeoPixels to this pin
#define NUM_LEDS 73            // Number of led lights
#define FPS      30            // Animation frames/second (ish)
#define CTS_PIN  -1            // Connect this pin to BLE 'CTS' pin
#define RTS_PIN  -1
#define BLUEFRUIT_UART_MODE_PIN -1


SoftwareSerial    ser(RX_PIN, -0);
Adafruit_NeoPixel pixels(NUM_LEDS, LED_PIN);

void setup()
{
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
             // MUST do this on 16 MHz Trinket for serial & NeoPixels!
  clock_prescale_set(clock_div_1);
#endif

            // Stop incoming data & init software serial
 
  pinMode(CTS_PIN, OUTPUT);
    digitalWrite(CTS_PIN, HIGH);

  //pinMode(interruptPin, INPUT);
  //interrupts();
  //attachInterrupt(digitalPinToInterrupt(RX_PIN, Update, CHANGE); 
  //void Update();
  //pixels.Update(animMode);
  //detachInterrupt();
   
  pixels.setBrightness(255);
  ser.begin(9600);
  pixels.begin();       // NeoPixel init
 
}

uint8_t  buf[3],                  // Enough for RGB parse; expand if using sensors
         animMode = 0,            // Current animation mode
         animPos  = 0;            // Current animation position
uint32_t color    = 0x400000,     // Red default
         prevTime = 0L;           // For animation timing

void loop(void) {
  int      c;
  uint32_t t;

          // Animation happens at about 30 frames/sec.  Rendering frames takes less
         // than that, so the idle time is used to monitor incoming serial data.
 
  digitalWrite(CTS_PIN, LOW); // Signal to BLE, OK to send data!
 
  for (;;) {
    t = micros();                                // Current time
    if ((t - prevTime) >= (1000000L / FPS)) {    // 1/30 sec elapsed?
      prevTime = t;
      break;                                     // Yes, go update LEDs
    }                                            // otherwise...
    if ((c = ser.read()) == '!') {               // Received UART app input?
      while ((c = ser.read()) < 0);              // Yes, wait for command byte
     
      switch (c) {
        case 'B':                    // Button (Control Pad)
          if (readAndCheckCRC(255 - '!' - 'B', buf, 2) & (buf[1] == '1')) {
            buttonPress(buf[0]);      // Handle button-press message
          }
          break;
         
        case 'C':                   // Color Picker
          if (readAndCheckCRC(255 - '!' - 'C', buf, 3)) {
            // As mentioned earlier, setBrightness() was avoided to save space.
            color = pixels.Color(buf[0] / 4, buf[1] / 4, buf[2] / 4);
          }
          break;
         
        case 'Q':                   // Quaternion
          skipBytes(17);             // 4 floats + CRC (see note below re: parsing)
          break;
         
        case 'A':                   // Accelerometer
#if 0
          // The phone sensors are NOT used by this sketch, but this shows how
          // they might be read.  First, buf[] must be delared large enough for
          // the expected data packet (minus header & CRC) -- that's 16 bytes
          // for quaternions (above), or 12 bytes for most of the others.
          // Second, the first arg to readAndCheckCRC() must be modified to
          // match the data type (e.g. 'A' here for accelerometer).  Finally,
          // values can be directly type-converted to float by using a suitable
          // offset into buf[] (e.g. 0, 4, 8, 12) ... it's not used in this
          // example because floating-point math uses lots of RAM and code
          // space, not suitable for the space-constrained Trinket/Gemma, but
          // maybe you're using a Pro Trinket, Teensy, etc.
         
          if (readAndCheckCRC(255 - '!' - 'A', buf, 12)) {
            float x = *(float *)(&buf[0]),
                  y = *(float *)(&buf[4]),
                  z = *(float *)(&buf[8]);
          }
         
          // In all likelihood, updates from the buttons and color picker
          // alone are infrequent enough that you could do without any mention
          // of the CTS pin in this code.  It's the extra sensors that really
          // start the firehose of data.
         
          break;
         
#endif
        case 'G':            // Gyroscope
        case 'M':            // Magnetometer
        case 'L':            // Location
          skipBytes(13);      // 3 floats + CRC
      }
    }
  }

the rest of it...

digitalWrite(CTS_PIN, HIGH);    // BLE STOP!

 // Show pixels calculated on *prior* pass; this ensures more uniform timing
 pixels.show();

 // Then calculate pixels for *next* frame...
 switch (animMode) {
   
   case 0:   //solid mode
     for(uint8_t i = 0; i < NUM_LEDS; i++) {
         uint32_t c = 0;
            if (((animPos) & 15) < 15) c = color;       // all pixels lit
               pixels.setPixelColor(   i, c);              
     }
     break;

     
   case 1:    //blinking mode
     for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
         uint32_t c = 0;
            if (((animPos + 1) & 15) < 2) c = color;   // all pixels lit
               pixels.setPixelColor(   i, c);
     }
     animPos++;
     break;
  

   case 2:       // chasing mode
     for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
         uint32_t c = 0;
            if (((animPos + i) & 15) < 4) c = color;    //16 total pixels, 4 lit at a time
               pixels.setPixelColor(   i, c);
     }
     animPos++;
     break; 

     
   case 3:   // Sparkle mode
     pixels.setPixelColor(animPos, 0);          // Erase old dot
         animPos = random(NUM_LEDS);                // Pick a new one
            pixels.setPixelColor(animPos, color);      // and light it
     break; 
   
     
   case 4:    // Up = rainbowCycle
     { 
     uint16_t i, j;
        for(j=0; j<256; j++) { // cycles of all colors on wheel
           for(i=0; i< pixels.numPixels(); i++) {
              pixels.setPixelColor(i, Wheel(((i * 256 / pixels.numPixels()) + j) & 255));
     }
     pixels.show();
       }
      } 
     break;


   case 5:    // Down = theaterChaseRainbow
    {
     for(int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
        for(int q=0; q < 3; q++) {
           for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
             pixels.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
     }
     pixels.show();
     
       for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
           pixels.setPixelColor(i+q, 0);        //turn every third pixel off
     }
   }
 }
}
     
     break;

     
        
   case 6:    // left button - rainbow
     {
     uint16_t i, j;
       for(j=0; j<256; j++) {
          for(i=0; i<pixels.numPixels(); i++) {
            pixels.setPixelColor(i, Wheel((i+j) & 255));
   }
   pixels.show();
 }
}
     
     break;

     

    case 7:   // right button - rainbow sparkle mode
      {
      uint16_t i, j;
        for(j=0; j<256; j++) {
           for(i=0; i<pixels.numPixels(); i++) {
             if (random(pixels.numPixels()) == i)
                pixels.setPixelColor(i,255, 255, 255);
                 else
                    pixels.setPixelColor(i, Wheel((i+j) & 255)); 
   }
   pixels.show();
 }
}
    
     break;
     
 }
}

boolean readAndCheckCRC(uint8_t sum, uint8_t *buf, uint8_t n) {
 for (int c;;) {
   while ((c = ser.read()) < 0);      // Wait for next byte
   if (!n--) return (c == sum);       // If CRC byte, we're done
   *buf++ = c;                        // Else store in buffer
   sum   -= c;                        // and accumulate sum
 }
}

void skipBytes(uint8_t n) {
 while (n--) {
   while (ser.read() < 0);
 }
}

void buttonPress(char c) {

 pixels.clear();         // Clear pixel data when switching modes (else residue)

switch (c) 
{
   case '1':
     animMode = 0;       // Switch to chase mode
     break;
   case '2':
     animMode = 1;       // Switch to sparkle mode
     break;
   case '3':
     animMode = 2;       // Switch to solid mode
     break;
   case '4':
     animMode = 3;       // Switch to blinking mode
     break;
   case '5':            
     animMode = 4;       // Up = rainbowCycle
     break;
   case '6':              
     animMode = 5;        // Down = theaterChaseRainbow
     break;
   case '7':              
     animMode = 6;        // Left = 
     break;
   case '8':              
     animMode = 7;        // Right = rainbowSparkle
     break;
 }
}

            // 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 pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
 }
 if(WheelPos < 170) {
   WheelPos -= 85;
   return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
 }
 WheelPos -= 170;
 return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

I feel like my answer lies in one of the following sections of code. I am wondering if I put an update line in, if that would trigger an interrupt.

for (;;) {
    startTime = micros();                                // Current time
    if ((startTime - prevTime) >= (1000000L / FPS)) {    // 1/30 sec elapsed?
      prevTime = startTime;
      break;                                     // Yes, go update LEDs
    }                                            // otherwise...

    if ((c_witch = serial.read()) == '!') {               // Received UART app input?
      while ((c_witch = serial.read()) < 0);              // Yes, wait for command byte

      switch (c_witch)

      {
        case 'B':                    // Button (Control Pad)
          if (readAndCheckCRC(255 - '!' - 'B', buf, 2) & (buf[1] == '1')) {
            buttonPress(buf[0]);      // Handle button-press message
          }
          break;

        case 'C':                   // Color Picker
          if (readAndCheckCRC(255 - '!' - 'C', buf, 3)) {
            color = pixels.Color(buf[4] / 4, buf[4] / 4, buf[4] / 4);
          }
          break;
boolean readAndCheckCRC(uint8_t sum, uint8_t *buf, uint8_t n) {
  for (int c;;) {
    while ((c = serial.read()) < 0);      // Wait for next byte
    if (!n--) return (c == sum);       // If CRC byte, we're done
    *buf++ = c;                        // Else store in buffer
    sum   -= c;                        // and accumulate sum
  }
}

void skipBytes(uint8_t n) {
  while (n--) {
    while (serial.read() < 0);
  }
}

void buttonPress(char c)
{

Not just the OP but whomever..

 for (int c;;)  <- is this a thing? Or just an error? What's it supposed to do?

-jim lee

jimLee:
Not just the OP but whomever..

 for (int c;;)  <- is this a thing? Or just an error? What's it supposed to do?

-jim lee

I wish I could answer that for you. The sketch compiles and works with my first 4 cases.

Adafruit has a tutorial about implementing their NeoPixel patterns in a non-blocking fashion: Overview | Multi-tasking the Arduino - Part 3 | Adafruit Learning System