#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define DEBUG 0
#define SERIAL 1 // ds("This will write to the serial monitor %i\n", int);
#if DEBUG == 1
#define debug(x) Serial.print(x)
#define debugln(x) Serial.println(x)
#else
#define debug(x)
#define debugln(x)
#endif
#if SERIAL == 1
#define dss(x, y) printf(x, y)
#define ds(x) printf(x)
#else
#define dss(x, y)
#define ds(x)
#endif
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) // ARRAYSIZE(k1) Returns int with element couont of k1
//External Identifiers
extern void SetAll(byte red, byte green, byte blue);
extern void SetAll(int function, byte red, byte green, byte blue);
extern void SetHue(int hue);
extern byte red;
extern byte green;
extern byte blue;
extern byte brightness;
extern byte rPlus;
extern byte gPlus;
extern byte bPlus;
extern byte rMinus;
extern byte gMinus;
extern byte bMinus;
struct CompChars
{
char key0[10];
char value0[10];
char key1[10];
char value1[10];
char key2[10];
char value2[10];
char key3[10];
char value3[10];
char key4[10];
char value4[10];
char key5[10];
char value5[10];
char answer[10];
char power[10];
};
struct CompChars c[10] =
{// key0 value0 key1 value1 key2 value2 key3 value3 key4 value4 key5 value5 answer power
{ "set", "\0", "function", "0", "status", "up", "rgb", "\0", "\0", "\0", "\0", "\0", "yes", "on"},
{ "get", "\0", "wifi", "1", "bright", "down", "red", "\0", "\0", "\0", "\0", "\0", "no", "off"},
{ "clear", "\0", "ble", "2", "delay", "add", "green", "\0", "\0", "\0", "\0", "\0", "\0", "\0"},
{ "reset", "\0", "\0", "3", "fade", "subtract", "blue", "\0", "\0", "\0", "\0", "\0", "\0", "\0"},
{ "read", "\0", "\0", "4", "fillall", "\0", "hue", "\0", "\0", "\0", "\0", "\0", "\0", "\0"},
{ "write", "\0", "\0", "5", "effect", "\0", "sat", "\0", "\0", "\0", "\0", "\0", "\0", "\0"},
{ "clrbfr", "\0", "\0", "6", "\0", "\0", "\0", "\0", "\0", "\0", "\0", "\0", "\0", "\0"}
};
int Comp(char *a, char *b) {
return (*a == *b && *b == '\0')? 0 : (*a == *b)? Comp(++a, ++b): 1;
}
//Key:Value Comparisons
void KVZero(){
//0
//Key0
for(int i = 0; i < 10; i++) {
if(strncmp(p[0].keys, c[i].key0, strlen(c[i].key0)) == 0) {
p[0].kres = i;
break;
}
}
//Value0
do {
if(isdigit(p[0].values[0]) != 0) {
p[0].vres = atoi(p[0].values);
printf("Value0 is a numerical entity.\n");
break;
}
for(int j = 0; j < 10; j++) {
if(strncmp(p[0].values, c[j].value0, strlen(c[j].value0)) == 0) {
p[0].vres = j;
break;
}
else {
p[0].vres = -1;
break;
}
}
}while(0);
}
void KVOne() {
//1
//Key1
do {
for(int i = 0; i < 10; i++) {
if(strncmp(p[1].keys, c[i].key1, strlen(p[1].keys)) == 0) {
printf("Key 1 match: %s\n", c[i].key1);
p[1].kres = i;
break;
}
}
//Value1
if(isdigit(p[1].values[0]) != 0) {
p[1].vres = atoi(p[1].values);
printf("Value1 is a numerical entity.\n");
break;
}
for(int j = 0; j < 10; j++) {
if(strncmp(p[1].values, c[j].value1, strlen(c[j].value1)) == 0) {
p[j].vres = j;
break;
}
}
} while(0);
}
void KVTwo() {
//2
//Key2
for(int i = 0; i < 10; i++) {
if(strncmp(p[2].keys, c[i].key2, strlen(c[i].key2)) == 0) {
p[2].kres = i;
break;
}
}
//Value2
do {
if(isdigit(p[2].values[0]) != 0) {
p[2].vres = atoi(p[2].values);
printf("Value2 is a numerical entity.\n");
break;
}
for(int j = 0; j < 10; j++) {
if(strncmp(p[2].values, c[j].value2, strlen(c[j].value2)) == 0) {
p[2].vres = j;
break;
}
}
} while(0);
}
void KVThree() {
//3
//Key3
for(int i = 0; i < 10; i++) {
if(strncmp(p[3].values, c[i].key3, strlen(c[i].key3)) == 0) {
p[3].kres = i;
break;
}
}
//Value3
do {
if(isdigit(p[3].values[0]) != 0) {
p[3].vres = atoi(p[3].values);
printf("Value3 is a numerical entity.\n");
break;
}
for(int j = 0; j < 10; j++) {
if(strncmp(p[3].values, c[j].value3, strlen(c[j].value3)) == 0) {
p[3].vres = j;
break;
}
}
} while(0);
}
void ClearMemory() {
for(int i = 0; i < track.pairs; i++) {
p[i] = {0};
}
//for(int i = 0; i < ARRAYSIZE(p); i++) {
memset(&p,0,sizeof(KV));
//}
}
void SetFunction() {
// function wifi ble
int functNum;
// Value2
// Check Value2 / p[1].values is a #, Copy to functNum
if(isdigit(p[1].values[0]) != 0) { functNum = atoi(p[1].values); }
printf("Function Number = %i\n", functNum);
// KEY 3
// check p[2].keys / key2
// status, bright, delay fade, fillall, effect
/*
for(int i = 0; i < 10; i++) {
if(strcmp(p[2].keys, c[i].key2) == 0) {
track.kres3 = i;
}
}
*/
int i = 0;
for(;;) {
Comp(p[2].keys, c[i].key2) == 0 ? printf("Yes p[2].keys = %s\n", c[0].key2) : printf("No p[2].keys does not = %s\n", c[i].key2) ? p[2].kres = i ? break : i ++;
printf("p[2].keys = %i\n", p[2].kres);
}
/*
int outcome;
outcome = Comp(p[2].keys, c[0].key2);
printf("Outcome = %i\n", outcome);
outcome = Comp(p[2].keys, c[1].key2);
printf("Outcome = %i\n", outcome);
printf("Key1 %i\n", p[1].kres);
printf("Value1 %i\n", p[1].vres);
KVOne();
printf("Key1 %i\n", p[1].kres);
printf("Value1 %i\n", p[1].vres);
printf("Key2 %i\n", p[2].kres);
printf("Value2 %i\n", p[2].vres);
KVTwo();
printf("Key1 %i\n", p[2].kres);
printf("Value1 %i\n", p[2].vres);
*/
if(p[2].kres == 0 && functNum == 1) { // Status funct 1
if(strncmp(p[2].values, "on", int(2)) == 0) { // on
if(f[0].state == -1) {
f[0].state *= -1;
printf("Enabling Primary Function\n");
}
else {
printf("Primary Function already on\n");
}
}
else if(strncmp(p[2].values, "off", int(3)) == 0) { // off
if(f[0].state == 1) {
f[0].state *= -1;
printf("Disabling Primary Function\n");
}
else {
printf("Primary Function already off\n");
}
}
}
else if(p[2].kres == 0 && functNum == 2) { // Status funct 2
if(strncmp(p[2].values, "on", int(2)) == 0) { // on
if(f[1].state == -1) {
f[1].state *= -1;
printf("Enabling Secondary Function\n");
}
else {
printf("Secondary Function already on\n");
}
}
else if(strncmp(p[2].values, "off", int(3)) == 0) { // off
if(f[1].state == 1) {
f[1].state *= -1;
printf("Disabling Secondary Function\n");
}
else {
printf("Secondary Function already off\n");
}
}
}
else if(p[2].kres == 0 && functNum == 3) { // Status funct 2
if(strncmp(p[2].values, "on", int(2)) == 0) { // on
if(f[2].state == -1) {
f[2].state *= -1;
printf("Enabling Tertiary Function\n");
}
else {
printf("Tertiary Function already on\n");
}
}
else if(strncmp(p[2].values, "off", int(3)) == 0) { // off
if(f[2].state == 1) {
f[2].state *= -1;
printf("Disabling Tertiary Function\n");
}
else {
printf("Tertiary Function already off\n");
}
}
}
if(p[2].kres == 1) { // Bright
}
if(p[2].kres == 2) { // Delay
}
if(p[2].kres == 3) { // Fade
}
if(p[2].kres == 4) { // Fillall
}
if(p[2].kres == 5) { // Effect
}
ClearMemory();
}
void Set() {
// key1 options - function-wifi-ble
printf("Triggered set\n");
// Key2
// p[1].keys / Key2
for(int i = 0; i < 10; i++) {
if(strcmp(p[1].keys, c[i].key1) == 0) {
p[1].kres = i;
}
}
switch(p[1].kres) {
case 0: // Function
SetFunction();
break;
case 1: // wifi
printf("Triggered WiFi\n");
break;
case 2: // ble
printf("Triggered BLE\n");
break;
}
}
void Locate(char* tempInput, char* d, int* index) {
char input[strlen(tempInput)];
strcpy(input, tempInput);
*index = 0;
int i = 0;
for(; i < input[i] != '\0'; i++) {
if(input[i] != *d) {
*index += 1;
}
else {
*index += 1;
break;
}
if(input[i] == *d) { break; }
}
}
//Instructions
//Commands
// All commands are listed with double quotes " surrounding them.
// Do not enter the command with the doublt quotes, it will not work.
// Only enter the text inside the quotes.
// Example:
// cmd:set function:1 delay:2 ms:5
//Emergency Operations
// Clear the input buffer "clearbuffer"
// Reset the ESP32 CPU's "resetesp"
//Parsing the Input into pairs
// token temorarily stores the the k:v pair before transferring to p1.pairs
// p1.pairs stores the k:v pairs after they are parsed by the space delimiter
// p1.pairCnt tracks the iterations and gives us a count of the pairs
// p1.len captures and stores the length of each of the pairs
// Each p1 element lines up with one another to provide different properties
//
char* ParseInput(char* tempInput, byte tempChars, size_t* length) { //Parse the input using a (space) as the delimiter
//Checking input
static char* input = NULL;
debugln("1");
if(tempInput != NULL) {
track.parsing = true;
debugln("2");
input = tempInput;
}
if(input == NULL) {
debugln("3");
return "\0";
}
//Dynamic memory allocaion and iteration through the input
char* result = new char[strlen(input) + 1];
int i = 0;
for(; input[i] != '\0'; i++) {
debugln("4");
if(input[i] != ' ') {
debugln("5");
result[i] = input[i];
}
else {
debugln("6");
result[i] = '\0';
input = input + i + 1;
*length = strlen(result);
return result;
}
}
debugln("7");
track.parsing = false;
result[i] = '\0';
input = NULL;
return result;
}
void ReadSerial2() {
//Setting up variables
debugln("Reading Serial");
char userInput[75] = "";
size_t length = 0;
track.tokcnt = 0;
track.pairs = 0;
//Readin the Serial Input
while(Serial.available() > 0) {
track.readingSerial = true;
debugln("Serial available");
size_t numChars = Serial.readBytesUntil('\n', userInput, sizeof(userInput) - 1);
if(!numChars) {
printf("Error: incorect or corrupt input,\nplease check and try again.\n");
break; // If the incoming bytes are < 1 bye, cancel t5he operation to avoid issues
}
userInput[numChars] = '\0';
size_t userInputLen = sizeof(userInput);
printf("You entered: %s\n", userInput);
//Checking for emergency reset cmd
if (strcmp(userInput, "resetesp") == 0) {
debugln("1");
printf(" Reseting ESP CPU!\n");
esp_cpu_reset(0);
esp_cpu_reset(1);
debugln("2");
printf(" ESP CPU has been reset.\n");
}
//Checking for emergency buffer clear
else if(strcmp(userInput, "clearbuffer") == 0) {
debugln("3");
printf("Clearing Buffers\n");
memset(userInput,0,sizeof(userInput));
debugln("4");
ClearMemory();
debugln("5");
}
// Parsing input into tokens
track.tokcnt = 0; // Tracks the number of key:value pairs
char* token = ParseInput(userInput, userInputLen, &length);
strcpy(p[track.tokcnt].pairs, token); //Store the parsed token data in the struct
track.toklen[track.tokcnt] = length; //Capture the length of the token and store in the struct
debugln("Token: "+String(p[track.tokcnt].pairs));
debugln("Token length: "+String(track.toklen[track.tokcnt]));
track.tokcnt++;
while(token != "\0") { //Remaining string is stored in NULL for futher parsing
token = ParseInput(NULL, userInputLen, &length);
strcpy(p[track.tokcnt].pairs, token);
debugln("Token: "+String(p[track.tokcnt].pairs));
debugln("Token length: "+String(track.toklen[track.tokcnt]));
track.toklen[track.tokcnt] = length;
track.tokcnt++;
debugln("*1");
if(track.parsing == false) {
debugln("*2");
break;
}
debugln("*3");
}
// Separating tokens to key values
track.keys = 0;
track.values = 0;
track.pairs = 0;
printf("Pairs = %i\n", track.pairs);
for(int i = 0; i < track.tokcnt; i++) {
if(!strchr(p[i].pairs, ':')) {
printf("Colon \":\" Not Found in pair %i\n", i);
strcpy(p[i].keys, p[i].pairs);
printf("Copied the contents of p[%i].pairs,\nto p[%i].keys and advanced the index by 1.\nThe first value will be empty.\n", i, i);
i++;
}
//Breaking pairs to keys and values
Locate(p[i].pairs, ":", &p[i].ci); // Locate the Comma (:) and store in p[i].ci
strncpy(p[i].keys, p[i].pairs, p[i].ci - 1); // Copy text inp[i].pairs before the comma (key) to p[i].keys
if(p[i].keys > 0) { track.keys++; } // tracker to track the number of keys parsed
printf("keys %i: %s\n", i, p[i].keys);
strncpy(p[i].values, &p[i].pairs[p[i].ci], strlen(p[i].pairs) - p[i].ci);
if(p[i].values > 0) { track.values++; }
printf("Values %i: %s\n", i, p[i].values);
track.pairs++;
memset(userInput,0,sizeof(userInput));
track.readingSerial = false;
}
}
// Key 0
// comparing keys and values to set commands
for(int i = 0; i < 10; i++) {
if(strcmp(p[0].keys, c[i].key0) == 0) {
switch (i) {
case 0: // set
//value0 not currently in use, moving to compare key1
//key1 - capture for use with Set()
Set();
break;
case 1:
printf("Triggered get\n");
break;
case 2:
printf("Triggered clear\n");
break;
case 3:
printf("Triggered reset\n");
break;
}
}
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32-S3!");
}
void loop() {
if(Serial.available() > 0) {
//ReadSerial();
ReadSerial2();
}
if(f[0].state == 1 && track.readingSerial == false) {
FastLED.setBrightness(f[0].bright);
//WhiteFlame(red, green, blue);
//WhiteFlameBackup(red, green, blue);
}
if(f[1].state == 1 && track.readingSerial == false) {
FastLED.setBrightness(f[1].bright);
//CandleFlame();
}
if(f[2].state == 1 && track.readingSerial == false) {
}
}