#include <StringSplitter.h>
#include <NewPing.h>
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel *strip;
// Trig, Echo, dist
NewPing sonar(5, 6, 300);
// 수신 메세지
String readMsg = "";
// 생상
long pixelHue = 0;
// 거리측정 가운트
int sonarCheckCnt = 0;
// 거리
int dist = 0;
// 생상모드
bool filMode = false;
// LED ON 거리
int checkDist = 30;

void setup() {
  // 스트랩 초기화 led count, pin
  strip = new Adafruit_NeoPixel(16, 3, NEO_GRB + NEO_KHZ800);
  strip->begin();
  delay(10);
  strip->clear();
  strip->show();
  Serial.begin(9600);
  while (!Serial) {}
}

void loop() {
  // 시리얼 읽기
  String msg = readSerial();
  // 메세지 길이 확인
  if(msg.length() > 0) {
    // LED FILL 모드
    if(msg.startsWith("[FIL:")) {
      // 문자열 ,로 분리 최대 4개
      StringSplitter *splitter = new StringSplitter(msg.substring(5, msg.length()-1), ',', 4);
      int red = splitter->getItemAtIndex(0).toInt();
      int green = splitter->getItemAtIndex(1).toInt();
      int blue = splitter->getItemAtIndex(2).toInt();
      int brightness = splitter->getItemAtIndex(3).toInt();
      // 색상설정
      colorWipe(strip->Color(red, green, blue), brightness, 20);
      filMode = true;
    }
    // 레인보우 모드
    else if(msg.startsWith("[RNBW]")) {
      strip->clear();
      strip->show();
      filMode = false;
    }
  }
  // FILL모드가 아닐 경우에만
  if(!filMode) {
    // 200ms마다 확인
    if(sonarCheckCnt++ >= 20) {
      // 거리 조회
      dist = sonar.ping_cm();
      Serial.println(dist);
      sonarCheckCnt = 0;
    }
    // ON 거리 이내일 경우
    if(dist < checkDist) {
      rainbow();
    }
    else {
      // LED OFF
      strip->clear();
      strip->show();
      pixelHue = 0;
    }
  }
  delay(10);
}
// LED 레인보우 효과
void rainbow() {
  for(int i=0; i<strip->numPixels(); i++) {
    int newPixelHue = pixelHue + (i * 65536L / strip->numPixels());
    strip->setPixelColor(i, strip->gamma32(strip->ColorHSV(newPixelHue)));
  }
  strip->show();
  if(pixelHue >= 5*65536) pixelHue = 0;
  else pixelHue += 256;
}
// FILL 모드
void colorWipe(uint32_t color, int brightness, int wait) {
  strip->clear();
  strip->setBrightness(brightness);
  for(int led=0; led<strip->numPixels(); led++) {
    strip->setPixelColor(led, color);
    if(wait > 0) {
      strip->show();
      delay(wait);
    }
  }
  if(wait == 0) strip->show();
}
// 시리얼 데이터 읽기
String readSerial() {
  // 데이터가 있을경우
  if(Serial.available()) {
    char rd = Serial.read();
    // 종료 문자 확인
    if(rd == ']') {
      String retVal = readMsg += rd;
      readMsg = "";
      return retVal;
    }
    else {
      // 시작문자 확인
      if(rd == '[') readMsg = "[";
      else if(readMsg != "") readMsg += rd;
    }
  }
  return "";
}
$abcdeabcde151015202530fghijfghij