corz.org uses cookies to remember that you've seen this notice explaining that corz.org uses cookies, okay!
String version = "7.4.3.2";
char mode = 'r';
float_t frequency = 1000;
uint8_t pulse = 50;
const uint8_t PWMPin = 26;
dac_channel_t channel = DAC_CHANNEL_2;
uint32_t SineUpperLimit = 500000;
uint32_t RectUpperLimit = 40000000;
uint32_t TriUpperLimit = 150000;
uint16_t TriLowerLimit = 153;
uint16_t SineLowerLimit = 16;
uint16_t RectLowerLimit = 1;
bool checkLimitsOnBoot = true;
uint8_t waveAmplitude = 4;
uint8_t touchUPPin = 33;
uint8_t touchDOWNPin = 32;
float_t fStep = 100;
uint16_t touchThreshold = 50;
bool storeTouch = false;
bool storeButton = true;
bool stepsObeyLimits = true;
uint16_t deBounce = 100;
char touchMode = 'f';
bool reportTouches = false;
uint8_t pStep = 5;
bool usePOT = false;
uint8_t potPIN = 34;
char potMode = 'f';
uint16_t FreqLowerPotLimit = 50;
uint16_t FreqUpperPotLimit = 13000;
uint8_t stepAccuracy = 1;
bool useButtons = true;
const uint8_t buttonCount = 5;
uint8_t buttonPins[buttonCount] = {
14,
0,
0,
18,
0
};
String buttonCommands[buttonCount] = {
"end",
"!",
"loop",
"",
"stop"
};
bool eXi = true;
float_t SINFAKT = 131.3;
uint8_t presetMAX = 50;
bool layerPresets = true;
bool saveALL = true;
bool exportALL = false;
// In other words, we can put blocks of code between
// We can also set this on-the-fly (so long as you leave in the above
bool RemControl = true;
uint8_t timeOut = 10;
const char *ssid = "";
const char *password = "";
const char *SGhostName = "";
String softAPSSID = "SignalGenerator";
String softAPPass = "SigzSigzFutnik";
bool onlyAP = false;
const uint8_t led = 2;
bool dailyReboot = true;
bool printWaveSymbols = true;
uint32_t cpuSpeed = 240;
bool wipeIsSerialOnly = true;
char commandsDelimiter = ';';
WebServer server(80);
const String _PLAIN_TEXT_ = "text/plain;charset=UTF-8";
const String _HTML5_TEXT_ = "text/html;charset=UTF-8";
Preferences prefs;
const uint8_t PWMChannel = 0;
uint8_t PWMResBits = 6;
uint16_t PWMSteps = 64;
uint_fast32_t tBuff[128];
static const i2s_port_t i2s_num = (i2s_port_t)0;
char oldMode = '~';
bool didLimit = false;
bool recFailed = false;
uint32_t touchTimer;
String WebCommand = "";
String QCommand = "";
String LastMessage = "";
bool fromWebConsole = false;
String knownClients;
const String _OUT_OF_RANGE_ = "Preset Number Out-Of-Range! (1-" + (String)presetMAX + ")";
uint16_t analogValue = 0;
uint16_t analogValueOLD = analogValue;
bool iLooping = false, eXiTmp;
String loopCommands;
bool amDelaying = false;
uint32_t delayTime = 500;
uint32_t delayStart;
uint8_t myOctave = 4;
struct button {
uint8_t pin;
String command;
uint8_t state;
uint8_t oldState;
};
struct SGButtons {
button my_butt[buttonCount];
};
SGButtons buttons;
String commandDelimiter = (String)commandsDelimiter;
const char *compile_time = __TIMESTAMP__;
int8_t INi2S = -1;
i2s_driver_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
.sample_rate = 10000000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.intr_alloc_flags = 0,
.dma_buf_count = 2,
.dma_buf_len = 32,
.use_apll = 0,
.tx_desc_auto_clear = false,
.fixed_mclk = 0,
.mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT,
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT
};
void startSignal(String from, bool doReport = false) {
if (eXi && doReport) \
Serial.printf(" Start Signal -> mode: %s (called from: %s)\n", makeHumanMode(mode).c_str(), from.c_str());
uint32_t freq;
frequency = abs(frequency);
recFailed = false;
switch (mode) {
case 't' :
mode = 't';
stopSignal();
startTriangle();
frequency = triangleSetFrequency(frequency, pulse);
break;
case 'r' :
mode = 'r';
if (oldMode != 'r') stopSignal();
freq = startRectangle();
rectangleSetFrequency(frequency, pulse);
if (freq == 0) recFailed = true;
break;
case 's' :
mode = 's';
if (oldMode != 's') stopSignal();
startSinus();
frequency = sinusSetFrequency(frequency);
break;
}
oldMode = mode;
}
void stopSignal() {
switch (oldMode) {
case 't' :
if (INi2S == ESP_OK) {
i2s_driver_uninstall(i2s_num);
INi2S = -1;
};
dac_i2s_disable();
break;
case 'r' :
reallyDetatchPWM();
break;
case 's' :
dac_output_disable(channel);
break;
}
}
void setMode(char myMode, bool doSave = true) {
if (myMode == 'r' || myMode == 't' || myMode == 's') {
mode = myMode;
if (doSave) prefs.putChar("m", myMode);
}
}
void setTouchMode(char myMode, bool doSave = true) {
switch (myMode) {
case 'p' :
case 'd' :
touchMode = 'p';
break;
case 'b' :
case 'r' :
touchMode = 'b';
break;
default:
touchMode = 'f';
}
if (doSave) (prefs.putChar("h", touchMode));
}
bool prefsSwitch(int8_t preset = 0) {
String lPreset = "sg";
prefs.end();
if (preset != 0) lPreset += (String)preset;
prefs.begin(lPreset.c_str());
if (prefs.getChar("i", -1) == -1) return false;
return true;
}
void startSinus() {
dac_output_enable(channel);
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
int8_t scale;
switch (channel) {
case DAC_CHANNEL_1:
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M);
SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV1, 2, SENS_DAC_INV1_S);
switch (waveAmplitude) {
case 1:
scale = B11;
break;
case 2:
scale = B10;
break;
case 3:
scale = B01;
break;
default:
scale = B00;
break;
}
SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_SCALE1, scale, SENS_DAC_SCALE1_S);
break;
case DAC_CHANNEL_2:
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M);
SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV2, 2, SENS_DAC_INV2_S);
switch (waveAmplitude) {
case 1:
scale = B11;
break;
case 2:
scale = B10;
break;
case 3:
scale = B01;
break;
default:
scale = B00;
break;
}
SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_SCALE2, scale, SENS_DAC_SCALE2_S);
break;
default :
break;
}
}
float_t sinusSetFrequency(float_t frequency) {
float_t f;
float_t delta, delta_min = 9999999.0;
int s, step = 1, divi = 0;
for (uint8_t div = 0; div < 8; div++) {
s = round(frequency * (div+1) / SINFAKT);
if ((s > 0) && ((div == 0) || (s < 1024))) {
f = SINFAKT * s / (div+1);
delta = abs(f - frequency);
if (delta < delta_min) {
step = s;
divi = div;
delta_min = delta;
}
}
}
frequency = (SINFAKT * step) / (divi + 1);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divi);
SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL1_REG, SENS_SW_FSTEP, step, SENS_SW_FSTEP_S);
if (eXi) Serial.printf(" returning frequency: %.2f \n", frequency);
return frequency;
}
int startRectangle() {
reallyDetatchPWM();
uint32_t ledc = ledcSetup(PWMChannel, frequency, PWMResBits);
ledcAttachPin(PWMPin, PWMChannel);
ledcWrite(PWMChannel, (PWMSteps * pulse) / 100.0);
return ledc;
}
void rectangleSetFrequency(float_t frequency, int8_t pulse) {
ledcSetup(PWMChannel, frequency, PWMResBits);
ledcWrite(PWMChannel, (PWMSteps * pulse) / 100.0);
}
void reallyDetatchPWM() {
ledcDetachPin(PWMPin);
pinMode(PWMPin, INPUT);
pinMode(PWMPin, OUTPUT);
digitalWrite(PWMPin, HIGH);
digitalWrite(PWMPin, LOW);
ledcDetachPin(PWMPin);
}
String recState() {
String fl = "";
if (recFailed) fl = " [FAILED]";
return fl;
}
void startTriangle() {
i2s_set_pin(i2s_num, NULL);
}
float_t triangleSetFrequency(float_t frequency, int8_t pulse) {
float_t f = frequency;
uint8_t buffLen = 64;
if (frequency < 5001) {
buffLen = 64;
} else if (frequency < 10001) {
buffLen = 32;
} else if (frequency < 25001) {
buffLen = 16;
} else {
buffLen = 8;
}
uint32_t rate = frequency * 2.000000 * buffLen;
if (rate < 5200) rate = 5200;
frequency = rate / 2.000000 / buffLen;
if (INi2S == ESP_OK) {
i2s_driver_uninstall(i2s_num);
INi2S = -1;
};
i2s_config.sample_rate = rate;
i2s_config.dma_buf_len = buffLen;
INi2S = i2s_driver_install(i2s_num, &i2s_config, 0, NULL);
if(INi2S != ESP_OK) {
delay(250);
INi2S = i2s_driver_install(i2s_num, &i2s_config, 0, NULL);
}
if(INi2S == ESP_OK) {
i2s_set_sample_rates(i2s_num, rate);
fillBuffer(pulse, buffLen * 2);
size_t bytes_written;
i2s_write(i2s_num, (const char *)&tBuff, buffLen * 8, &bytes_written, portMAX_DELAY);
return frequency;
}
return f;
}
void fillBuffer(uint8_t upTime, uint8_t buffSize) {
float_t Amplitude = 256.0 / (5-waveAmplitude);
uint8_t downTime;
uint_fast32_t sample;
float_t divUP, divDOWN, buffValue;
downTime = 100 - upTime;
uint16_t stepsUP = round(((1.0 * buffSize) / 100) * upTime);
uint16_t stepsDOWN = round(((1.0 * buffSize) / 100) * downTime);
uint16_t i;
if ((stepsUP + stepsDOWN) < buffSize) stepsUP++;
divUP = Amplitude / stepsUP;
divDOWN = Amplitude / stepsDOWN;
buffValue = 0;
for (i = 0; i < stepsUP; i++) {
sample = buffValue;
sample = sample << 8;
tBuff[i] = sample;
buffValue += divUP;
}
buffValue = Amplitude-1;
for (i = 0; i < stepsDOWN; i++) {
sample = buffValue;
sample = sample << 8;
tBuff[i + stepsUP] = sample;
buffValue -= divDOWN;
}
}
uint8_t switchResolution(uint8_t newbits, bool save = true) {
if (newbits > 12) newbits = 12;
if (newbits < 1) newbits = 1;
switch (newbits) {
case 1: PWMSteps = 2; break;
case 2: PWMSteps = 4; break;
case 3: PWMSteps = 8; break;
case 4: PWMSteps = 16; break;
case 5: PWMSteps = 32; break;
case 6: PWMSteps = 64; break;
case 7: PWMSteps = 128; break;
case 8: PWMSteps = 256; break;
case 9: PWMSteps = 512; break;
case 10: PWMSteps = 1024; break;
case 11: PWMSteps = 2048; break;
case 12: PWMSteps = 4096; break;
}
if (save) prefs.putUChar("b", newbits);
return newbits;
}
String makeHumanMode(char myMode) {
switch (myMode) {
case 's' : return "Sine";
case 't' : return "Triangle";
case 'r' : return "Square";
}
return "";
}
String makeHumanTouchMode(char myMode) {
switch (myMode) {
case 'f' : return "Frequency";
case 'p' : return "Pulse Width";
case 'b' : return "Resolution Bit Depth";
}
return "";
}
String makeHumanFrequency(float_t f, bool exporting = false) {
String humanF = "";
float_t newF;
char buffer[18];
String mV = "MHz";
String kV = "kHz";
String hV = "Hz";
if (exporting) {
mV = "m";
kV = "k";
hV = "";
}
if (f > 999999.999) {
newF = f/1000000.000;
snprintf(buffer, 18, "%.9f", newF);
humanF = chopZeros((String)buffer) + mV;
} else if (f > 999.999) {
newF = f/1000.000;
snprintf(buffer, 15, "%.6f", newF);
humanF = chopZeros((String)buffer) + kV;
} else {
humanF = chopZeros((String)f) + hV;
}
return humanF;
}
void checkLimits(float_t freq) {
uint32_t u_limit = 0;
uint32_t l_limit = 0;
didLimit = false;
switch (mode) {
case 's' :
u_limit = SineUpperLimit;
l_limit = SineLowerLimit;
break;
case 'r' :
u_limit = RectUpperLimit;
l_limit = RectLowerLimit;
break;
case 't' :
u_limit = TriUpperLimit;
l_limit = TriLowerLimit;
break;
}
if (freq < l_limit) {
frequency = l_limit;
didLimit = true;
}
if (freq > u_limit) {
frequency = u_limit;
didLimit = true;
}
}
float_t humanFreqToFloat(String newFreq) {
newFreq.toLowerCase();
if (newFreq.endsWith("k") || newFreq.endsWith("m")) {
int8_t sLen = newFreq.length();
String newFCMD = newFreq.substring(0, sLen-1);
if (newFreq.endsWith("k")) newFreq = newFCMD.toFloat() * 1000;
if (newFreq.endsWith("m")) newFreq = newFCMD.toFloat() * 1000000;
}
return newFreq.toFloat();
}
void frequencyStepSet(String newFreq) {
float_t thisFreq = humanFreqToFloat(newFreq);
if (thisFreq < 1) thisFreq = 1;
if (thisFreq > 10000000) thisFreq = 10000000;
fStep = thisFreq;
prefs.putFloat("s", fStep);
}
void frequencySet(String newFreq, bool OVRide = false, bool doReport = true) {
frequency = humanFreqToFloat(newFreq);
if (eXi && doReport) Serial.printf(" User requested frequency:\t%s\n", makeHumanFrequency(frequency).c_str());
if (OVRide == false) checkLimits(frequency);
prefs.putFloat("f", frequency);
if (eXi && doReport) Serial.printf(" Setting frequency:\t%s\n", makeHumanFrequency(frequency).c_str());
}
uint32_t setNoteFrequency(note_t note) {
const uint16_t noteFreqBase[12] = {
// Note: C C
4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902
};
uint32_t noteFreq = (uint32_t)noteFreqBase[note] / (uint32_t)(1 << (8-myOctave));
frequencySet((String)noteFreq, false, false);
return noteFreq;
}
uint32_t playMusicalNote(String musicData) {
int16_t Split = musicData.indexOf("|");
String thisNote;
uint32_t newFreq;
if (Split != -1) {
thisNote = musicData.substring(0, Split);
String tmp = musicData.substring(Split+1);
tmp.trim();
if (tmp != "") {
if (tmp == "+") {
myOctave += 1;
} else if (tmp == "-") {
myOctave -= 1;
} else {
myOctave = tmp.toInt();
}
}
} else {
thisNote = musicData;
}
if(myOctave > 8) myOctave = 8;
thisNote.trim();
if (thisNote == "c || thisNote == "db") {
newFreq = setNoteFrequency(NOTE_Cs);
} else if (thisNote == "d") {
newFreq = setNoteFrequency(NOTE_D);
} else if (thisNote == "eb" || thisNote == "d) {
newFreq = setNoteFrequency(NOTE_Eb);
} else if (thisNote == "e") {
newFreq = setNoteFrequency(NOTE_E);
} else if (thisNote == "f") {
newFreq = setNoteFrequency(NOTE_F);
} else if (thisNote == "f || thisNote == "gb") {
newFreq = setNoteFrequency(NOTE_Fs);
} else if (thisNote == "g") {
newFreq = setNoteFrequency(NOTE_G);
} else if (thisNote == "g || thisNote == "ab") {
newFreq = setNoteFrequency(NOTE_Gs);
} else if (thisNote == "a") {
newFreq = setNoteFrequency(NOTE_A);
} else if (thisNote == "bb" || thisNote == "a) {
newFreq = setNoteFrequency(NOTE_Bb);
} else if (thisNote == "b") {
newFreq = setNoteFrequency(NOTE_B);
} else {
newFreq = setNoteFrequency(NOTE_C);
}
return newFreq;
}
bool setAmplitude(uint8_t newAmp) {
if (newAmp > 0 && newAmp <= 4) {
waveAmplitude = newAmp;
prefs.putUChar("a", waveAmplitude);
return true;
}
return false;
}
String directDACVolts(float_t voltsValue) {
if (voltsValue > 3.3) Serial.printf(" Value exceeds 3.3! Will be automatically limited to 3.3\n");
uint16_t vV = min((int)(voltsValue * 100), 330);
uint8_t newVal = map(vV, 0, 330, 0, 255);
String ret = "Writing Mapped value (0-255): " + (String)newVal + " to DAC.\n";
stopSignal();
dacWrite(PWMPin, newVal);
startSignal("DAC Voltage Adjust");
return ret;
}
void frequencyStepUP(int8_t stepSource) {
if (eXi) Serial.printf(" Step UP() activation from: %s\n", stepFROM(stepSource).c_str());
frequency += fStep;
if (stepsObeyLimits) checkLimits(frequency);
if ((stepSource == 0 && storeTouch == true) || (stepSource >= 1 && storeButton == true)) {
prefs.putFloat("f", frequency);
}
if (stepSource == 3) {
LastMessage = "Frequency UP to " + makeHumanFrequency(frequency);
}
startSignal("StepUP");
}
void frequencyStepDOWN(int8_t stepSource) {
if (eXi) Serial.printf(" Step DOWN() activation from: %s\n", stepFROM(stepSource).c_str());
frequency -= fStep;
if (stepsObeyLimits) checkLimits(frequency);
if ((stepSource == 0 && storeTouch == true) || (stepSource == 1 && storeButton == true)) {
prefs.putFloat("f", frequency);
}
if (stepSource == 3) {
LastMessage = "Frequency DOWN to " + makeHumanFrequency(frequency);
}
startSignal("StepDown");
}
String stepFROM(int8_t stepSource) {
String from;
switch (stepSource) {
case 0:
from = "touch";
break;
case 1:
from = "web";
break;
case 2:
from = "console";
break;
case 3:
from = "web console";
break;
}
return from;
}
bool setPulseStep(int8_t newStepSize) {
if (newStepSize > 0 && newStepSize <= 100) {
pStep = newStepSize;
prefs.putUChar("j", pStep);
return true;
}
return false;
}
int8_t setPulseWidth(int16_t newPulse, bool doSave = true) {
if (newPulse > 100) newPulse = 100;
if (newPulse < 0) newPulse = 0;
pulse = newPulse;
if (doSave) prefs.putUChar("p", pulse);
return pulse;
}
void pwmStepUP(bool doSave = true) {
setPulseWidth(pulse+pStep, doSave);
startSignal("pwmUP");
}
void pwmStepDOWN(bool doSave = true) {
setPulseWidth(pulse-pStep, doSave);
startSignal("pwmDOWN");
}
void bitsStepUP(bool doSave = true) {
PWMResBits = switchResolution(PWMResBits+1, doSave);
startSignal("bitsStepUP");
}
void bitsStepDOWN(bool doSave = true) {
PWMResBits = switchResolution(PWMResBits-1, doSave);
startSignal("bitsStepDOWN");
}
void touchUPStep() {
switch (touchMode) {
case 'f' :
frequencyStepUP(0);
break;
case 'p' :
pwmStepUP(storeTouch);
break;
case 'b' :
bitsStepUP(storeTouch);
break;
}
}
void touchDOWNStep() {
switch (touchMode) {
case 'f' :
frequencyStepDOWN(0);
break;
case 'p' :
pwmStepDOWN(storeTouch);
break;
case 'b' :
bitsStepDOWN(storeTouch);
break;
}
}
void loadDefaultPrefs() {
Serial.println("\n Retrieving preferences from NVRAM..\n");
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) WipeNVRAM();
ESP_ERROR_CHECK(err);
prefsSwitch();
loadPrefs(false);
}
void loadPrefs(bool isPreset) {
mode = prefs.getChar("m", mode);
frequency = prefs.getFloat("f", frequency);
fStep = prefs.getFloat("s", fStep);
pulse = prefs.getUChar("p", pulse);
pStep = prefs.getUChar("j", pStep);
PWMResBits = switchResolution(prefs.getUChar("b", PWMResBits), false);
touchMode = prefs.getChar("h", touchMode);
waveAmplitude = prefs.getUChar("a", waveAmplitude);
if (!isPreset) {
eXi = prefs.getBool("e", eXi);
if (eXi) Serial.printf(" Extended Information: Enabled\n");
RemControl = prefs.getBool("r", RemControl);
if (eXi) Serial.printf(" Remote Control: %s\n", RemControl ? "Enabled" : "Disabled");
reportTouches = prefs.getBool("t", reportTouches);
if (eXi) Serial.printf(" Report Touches: %s\n", reportTouches ? "Enabled" : "Disabled");
onlyAP = prefs.getBool("w", onlyAP);
if (eXi) Serial.printf(" AP Only Mode: %s\n", onlyAP ? "Enabled" : "Disabled");
layerPresets = prefs.getBool("l", layerPresets);
if (eXi) Serial.printf(" Layering Presets: %s\n", layerPresets ? "Enabled" : "Disabled");
saveALL = prefs.getBool("c", saveALL);
if (eXi) Serial.printf(" Save ALL Settings: %s\n", saveALL ? "Enabled" : "Disabled");
exportALL = prefs.getBool("x", exportALL);
if (eXi) Serial.printf(" Export ALL Settings: %s\n", exportALL ? "Enabled" : "Disabled");
usePOT = prefs.getBool("u", usePOT);
if (eXi) Serial.printf(" Use Potentiometer: %s\n", usePOT ? "Enabled" : "Disabled");
loopCommands = prefs.getString("o", loopCommands);
if (eXi && loopCommands != "") Serial.printf(" Default Loop/Macro: %s\n", loopCommands.c_str());
cpuSpeed = prefs.getUInt("z", cpuSpeed);
if (eXi) Serial.printf(" CPU Speed: %iMHz\n", cpuSpeed);
Serial.printf("\n Touch UP Pin: %i\n Touch DOWN Pin: %i\n", touchUPPin, touchDOWNPin);
}
}
String copyPreset(uint8_t copyFrom, uint8_t copyTo) {
if (copyFrom < 1 || copyFrom > presetMAX) return "Source " + _OUT_OF_RANGE_;
if (copyTo < 1 || copyTo > presetMAX) return "Target " + _OUT_OF_RANGE_;
if (prefsSwitch(copyFrom)) {
char Cmode = prefs.getChar("m", '~');
float_t Cfrequency = prefs.getFloat("f", -1);
float_t CfStep = prefs.getFloat("s", -1);
char CtouchMode = prefs.getChar("h", '~');
uint8_t CwaveAmplitude = prefs.getUChar("a", '~');
uint8_t CPWMResBits = prefs.getUChar("b", '~');
uint8_t Cpulse = prefs.getUChar("p", '~');
uint8_t CpStep = prefs.getUChar("j", '~');
String CloopCommands = prefs.getString("o", "");
String CmyName = prefs.getString("n", "");
String newName = "(COPY)";
prefsSwitch(copyTo);
prefs.putChar("i", 1);
if (Cmode != '~') prefs.putChar("m", Cmode);
if (Cfrequency != -1) prefs.putFloat("f", Cfrequency);
if (CfStep != -1) prefs.putFloat("s", CfStep);
if (CtouchMode != '~') prefs.putChar("h", CtouchMode);
if (CwaveAmplitude != '~') prefs.putUChar("a", CwaveAmplitude);
if (CPWMResBits != '~') prefs.putUChar("b", CPWMResBits);
if (Cpulse != '~') prefs.putUChar("p", Cpulse);
if (CpStep != '~') prefs.putUChar("j", CpStep);
if (CloopCommands != "") prefs.putString("o", CloopCommands);
if (CmyName != "") {
newName = CmyName + " " + newName;
int8_t foundCpyPOS = CmyName.indexOf("(COPY");
uint8_t cNum;
if(foundCpyPOS != -1) {
cNum = CmyName.substring(foundCpyPOS+5, CmyName.lastIndexOf(")")).toInt();
newName = CmyName.substring(0, foundCpyPOS) + "(COPY" + (String)((cNum != 0) ? cNum += 1 : 2) + ")";
}
prefs.putString("n", newName);
}
prefsSwitch();
return "Preset copied OK";
}
return "Source Preset Not Found!";
}
String loadPreset(int8_t presetNumber) {
if (presetNumber < 0 || presetNumber > presetMAX) return _OUT_OF_RANGE_;
bool presetExists = true;
String retStr = "Loading ";
if (presetNumber == 0) {
retStr += "Defaults: ";
} else {
if (prefsSwitch(presetNumber)) {
retStr += "Preset " + (String)presetNumber + " '" + prefs.getString("n") + "': ";
} else {
presetExists = false;
}
}
if (presetExists) loadPrefs(true);
if (presetNumber != 0) prefsSwitch();
return (presetExists) ? retStr + "OK" : "No Such Preset!";
}
String savePreset(int8_t presetNumber, bool defaults = false) {
if (presetNumber < 0 || presetNumber > presetMAX) return _OUT_OF_RANGE_;
String ret = "Saving Defaults: ";
char lMode = prefs.getChar("m", '~');
float_t lFreq = prefs.getFloat("f", -1);
float_t lStep = prefs.getFloat("s", -1);
char lTcMd = prefs.getChar("h", '~');
uint8_t lAMP = prefs.getUChar("a", '~');
uint8_t lBits = prefs.getUChar("b", '~');
uint8_t lPulse = prefs.getUChar("p", '~');
uint8_t lpStep = prefs.getUChar("j", '~');
if (presetNumber != 0) {
ret = "Saving Preset " + (String)presetNumber + ": ";
prefsSwitch(presetNumber);
prefs.putChar("i", 1);
}
if (layerPresets && !defaults) {
if (lMode != '~') prefs.putChar("m", lMode);
if (lFreq != -1) prefs.putFloat("f", lFreq);
if (lStep != -1) prefs.putFloat("s", lStep);
if (lTcMd != '~') prefs.putChar("h", lTcMd);
if ((mode != 'r' || saveALL) && lAMP != '~') prefs.putUChar("a", lAMP);
if ((mode == 'r' || saveALL) && lBits != '~') prefs.putUChar("b", lBits);
if ((mode != 's' || saveALL) && lPulse != '~') prefs.putUChar("p", lPulse);
if ((mode != 's' || saveALL) && lpStep != '~') prefs.putUChar("j", lpStep);
} else {
prefs.putChar("m", mode);
prefs.putFloat("f", frequency);
prefs.putFloat("s", fStep);
prefs.putChar("h", touchMode);
if (mode != 'r' || saveALL) prefs.putUChar("a", waveAmplitude);
if (mode == 'r' || saveALL) prefs.putUChar("b", PWMResBits);
if (mode != 's' || saveALL) prefs.putUChar("p", pulse);
if (mode != 's' || saveALL) prefs.putUChar("j", pStep);
}
if (prefs.getChar("i") == 1) ret += "OK";
if (presetNumber != 0) {
prefsSwitch();
} else {
ret += " (Saving current settings to DEFAULTS - will persist on reboot).";
}
return ret + getFreeEntries();
}
String namePreset(String presetNameData) {
String presetNUM;
String presetNAME;
bool stillDigits = true;
char tChar;
int8_t success = -1;
for( uint8_t i = 0; i < presetNameData.length(); i++ ) {
if (i == 2) stillDigits = false;
tChar = presetNameData.charAt(i);
if (tChar == '=') {
stillDigits = false;
continue;
}
if (isDigit(tChar) and stillDigits) {
presetNUM += tChar;
} else {
presetNAME += tChar;
stillDigits = false;
}
}
uint8_t NUM = presetNUM.toInt();
if (NUM < 1 || NUM > presetMAX) success = -3;
presetNAME.trim();
if (presetNAME == "") success = -4;
if (success == -1) {
prefsSwitch(presetNUM.toInt());
if (prefs.getChar("i", -1) != -1) {
if (prefs.putString("n", presetNAME) != 0) success = 0;
} else {
success = -2;
}
prefsSwitch();
}
String result;
switch (success) {
case -1:
result = "Could not set name of preset " + presetNUM;
break;
case -2:
result = "Preset " + presetNUM + " does not exist.";
break;
case -3:
result = _OUT_OF_RANGE_;
break;
case -4:
result = "No name supplied!";
break;
default:
result = "Set name of preset [" + presetNUM + "] to \"" + presetNAME + "\"";
}
return result;
}
String getPresetName(uint8_t thisPreset) {
prefsSwitch(thisPreset);
String myName = prefs.getString("n", "");
prefsSwitch();
return myName;
}
bool wipePreset(int8_t presetNumber) {
if (presetNumber > presetMAX) return false;
bool cleared = false;
if (presetNumber != 0) prefsSwitch(presetNumber);
if (presetEmpty()) {
cleared = false;
} else {
if (prefs.getChar("i", -1) != -1) {
String wLoops = prefs.getString("o", "");
if (wLoops != "") {
prefs.remove("m");
prefs.remove("f");
prefs.remove("s");
prefs.remove("h");
prefs.remove("a");
prefs.remove("b");
prefs.remove("p");
prefs.remove("j");
cleared = true;
} else {
cleared = prefs.clear();
}
} else {
cleared = false;
}
}
if (presetNumber != 0) {
prefsSwitch();
} else {
prefs.putChar("i", 1);
}
return cleared;
}
bool presetEmpty() {
bool isEmpty = true;
if (prefs.getChar("m", '~') != '~') isEmpty = false;
if (prefs.getFloat("f", -1) != -1) isEmpty = false;
if (prefs.getFloat("s", -1) != -1) isEmpty = false;
if (prefs.getChar("h", '~') != '~') isEmpty = false;
if (prefs.getUChar("a", '~') != '~') isEmpty = false;
if (prefs.getUChar("b", '~') != '~') isEmpty = false;
if (prefs.getUChar("p", '~') != '~') isEmpty = false;
if (prefs.getUChar("j", '~') != '~') isEmpty = false;
return isEmpty;
}
bool isEmptyChar(const char **myChar) {
if (*myChar && !*myChar[0]) {
return true;
}
return false;
}
String urlDecode(String text) {
String decoded = "";
char temp[] = "0x00";
uint16_t len = text.length();
uint16_t i = 0;
while (i < len) {
char decodedChar;
char encodedChar = text.charAt(i++);
if ((encodedChar == '%') && (i + 1 < len)) {
temp[2] = text.charAt(i++);
temp[3] = text.charAt(i++);
decodedChar = strtol(temp, NULL, 16);
} else {
if (encodedChar == '+') {
decodedChar = ' ';
} else {
decodedChar = encodedChar;
}
}
decoded += decodedChar;
}
return decoded;
}
void trimDelims(String &Commands) {
Commands.trim();
while (Commands.endsWith(commandDelimiter)) {
Commands.remove(Commands.length()-1);
Commands.trim();
}
while (Commands.startsWith(commandDelimiter)) {
Commands.remove(0, 1);
Commands.trim();
}
}
String chopZeros(String bigNumber) {
if (bigNumber.indexOf(".") != -1) {
while (bigNumber.endsWith("0")) bigNumber.remove(bigNumber.length()-1);
if (bigNumber.endsWith(".")) bigNumber.remove(bigNumber.length()-1);
}
return bigNumber;
}
String getCurrentSettings() {
char bpl;
if (PWMResBits != 1) bpl = 's';
String wForm = "@";
if (printWaveSymbols) {
switch (mode) {
case 's' :
wForm = "\u223F";
break;
case 'r' :
wForm = "\u25FB";
break;
case 't' :
wForm = "\u25B3";
}
}
char buffer[164];
sprintf(buffer, "\t%s Wave %s %s\n", \
makeHumanMode(mode).c_str(), wForm.c_str(), makeHumanFrequency(frequency).c_str());
if (mode != 's') sprintf(buffer + strlen(buffer), "\tPulse Width: %i%%\n", pulse);
if (mode == 'r') sprintf(buffer + strlen(buffer), "\tPWM Resolution: %i bit%c\n", PWMResBits, bpl);
sprintf(buffer + strlen(buffer), "\tFreq Step Size: %s\n", makeHumanFrequency(fStep).c_str());
if (mode != 's') sprintf(buffer + strlen(buffer), "\tPWM Step Size: %i%%\n", pStep);
if (mode != 'r') sprintf(buffer + strlen(buffer), "\tAmplitude Level: %i\n", waveAmplitude);
sprintf(buffer + strlen(buffer), "\tTouch Mode: %s\n", makeHumanTouchMode(touchMode).c_str());
return (String)buffer;
}
String getCommands() {
char cbuf[3000];
sprintf(cbuf, "\n Commands:\n\n");
sprintf(cbuf + strlen(cbuf), "\ts Sine Wave\n");
sprintf(cbuf + strlen(cbuf), "\tr Rectangle / Square Wave\n");
sprintf(cbuf + strlen(cbuf), "\tt Triangle / Sawtooth Wave\n");
sprintf(cbuf + strlen(cbuf), "\t' Cycle through Rectangle > Sine > Triangle Waves\n");
sprintf(cbuf + strlen(cbuf), "\t*[k/m] Frequency [Hz/kHz/MHz]\n");
sprintf(cbuf + strlen(cbuf), "\t+/-*[k/m] Increase/Decrease Frequency by *[Hz/kHz/MHz]\n");
sprintf(cbuf + strlen(cbuf), "\tb* Resolution Bit Depth [1-10]\n");
sprintf(cbuf + strlen(cbuf), "\tp* Pulse Width (Duty Cycle ~ percent[0-100]) \n");
sprintf(cbuf + strlen(cbuf), "\ts*[k/m] Step size for Frequency [Hz/kHz/MHz]\n");
sprintf(cbuf + strlen(cbuf), "\tj* Step size for Pulse Width (Jump!) [1-100]\n");
sprintf(cbuf + strlen(cbuf), "\th[f|p|b] Touch Handler [frequency|pulse width|res bits]\n");
sprintf(cbuf + strlen(cbuf), "\t[ ] Frequency Step DOWN / UP\n");
sprintf(cbuf + strlen(cbuf), "\t\\ / Pulse Width Step DOWN / UP (also - and +)\n");
sprintf(cbuf + strlen(cbuf), "\tz a Resolution Bit Depth Step DOWN / UP\n");
sprintf(cbuf + strlen(cbuf), "\ta* Sine/Triangle wave Amplitude * (1-4) Default is 4.\n");
sprintf(cbuf + strlen(cbuf), "\t*n[|o] That's a literal *! Play musical note 'n' at octave 'o'\n");
sprintf(cbuf + strlen(cbuf), "\t~[*] Delay for * milliseconds (omit number to use previous time).\n");
sprintf(cbuf + strlen(cbuf), "\td Overwrite Defaults (with current settings)\n");
sprintf(cbuf + strlen(cbuf), "\tm* Save Current Defaults to Preset Memory *\n");
sprintf(cbuf + strlen(cbuf), "\tl* Load Preset Number * (Think: MEMORY -> LOAD!)\n");
sprintf(cbuf + strlen(cbuf), "\tlist List All Presets (and their settings - url: /list)\n");
sprintf(cbuf + strlen(cbuf), "\tlp[e/d] Toggle Layering of Presets [enable/disable]\n");
sprintf(cbuf + strlen(cbuf), "\t[enter] Print Current Settings (and restart generator)\n");
sprintf(cbuf + strlen(cbuf), "\t, Print Stored Default Settings (from NVS)\n");
sprintf(cbuf + strlen(cbuf), "\tk* Print Stored Settings for Preset Number *\n");
sprintf(cbuf + strlen(cbuf), "\to*[k/m] Override Limits, Set Frequency to *[Hz/kHz/MHz]\n");
sprintf(cbuf + strlen(cbuf), "\te Toggle Extended Info\n");
sprintf(cbuf + strlen(cbuf), "\tx Reboot Device\n");
sprintf(cbuf + strlen(cbuf), "\tl Load Stored Default Signal Settings\n");
sprintf(cbuf + strlen(cbuf), "\tbuttons Print Out Current Physical Button Control Assignments\n");
sprintf(cbuf + strlen(cbuf), "\tsa[e/d] Toggle Save ALL Settings [enable/disable]\n");
sprintf(cbuf + strlen(cbuf), "\tea[e/d] Toggle (Individual) Export ALL Settings [enable/disable]\n");
sprintf(cbuf + strlen(cbuf), "\trt[e/d] Toggle the Reporting of Touches [enable/disable]\n");
sprintf(cbuf + strlen(cbuf), "\tup[e/d] Toggle Use Potentiometer Control [enable/disable]\n");
sprintf(cbuf + strlen(cbuf), "\tv* Set the Handler/Accuracy of the Potentiometer [p|f|b/1-100]\n");
sprintf(cbuf + strlen(cbuf), "\treset Reset to Hard-Wired Defaults (and reboot)\n");
sprintf(cbuf + strlen(cbuf), "\tw[*] Wipe Stored Signal Settings [for Preset *]\n");
sprintf(cbuf + strlen(cbuf), "\twipe WIPE ENTIRE NVRAM (and reboot). Careful now!\n");
sprintf(cbuf + strlen(cbuf), "\texport[*/all] Export Importable Settings [for preset/all]\n");
sprintf(cbuf + strlen(cbuf), "\timport * Please Read The Fine Manual!\n");
sprintf(cbuf + strlen(cbuf), "\tloop[*]=[?] Load [?] Commands into Loop/Macro [number *] (RTFM!)\n");
sprintf(cbuf + strlen(cbuf), "\tloop[*] Start Playing Loop/Macro [number *] (RTFM!)\n");
sprintf(cbuf + strlen(cbuf), "\tend End the Currently Playing Queue/Loop/Macro\n");
sprintf(cbuf + strlen(cbuf), "\t@* Set * Volts directly on the DAC Pin (0 - 3.3).\n");
sprintf(cbuf + strlen(cbuf), "\tstop/. Stop the Currently Playing Signal (enter to restart)\n");
sprintf(cbuf + strlen(cbuf), "\tll[l] List Loops/Macros (if available) [single importable list]\n");
sprintf(cbuf + strlen(cbuf), "\tmem Print Out Memory Usage Information\n");
sprintf(cbuf + strlen(cbuf), "\tcpu* Set CPU Frequency to *[240/160/80] MHz%s\n", \
RemControl ? " (and reboot)" : "");
sprintf(cbuf + strlen(cbuf), "\tremote[e/d] Remote Control Toggle [Enable/Disable]\n");
sprintf(cbuf + strlen(cbuf), "\twap/waa Set WiFi AP Only / Station + AP (and reboot)\n");
sprintf(cbuf + strlen(cbuf), "\tc Print Out Available Commands (this screen - url: /help)\n");
return (String)cbuf;
}
String getNVRAMPresetData(uint8_t presetNumber = 0, bool listing = false, bool silent = false) {
char thisType[16];
if (presetNumber != 0) {
prefsSwitch(presetNumber);
if (!silent) {
if (prefs.getChar("i", -1) == -1) {
if (!listing) LastMessage = "Preset " + (String)presetNumber + " does not exist";
prefsSwitch();
return "";
}
sprintf(thisType, " for Preset %i", presetNumber);
}
}
char nvbuf[1024] = {'\0'};
if (!silent) {
if (presetNumber != 0) {
if (!presetEmpty()) {
sprintf(nvbuf, "\n NVRAM Settings%s: ", thisType);
String nTmp = prefs.getString("n", "");
if (nTmp != "") {
sprintf(nvbuf + strlen(nvbuf), "\n\n\t\"%s\"\n\n", nTmp.c_str());
} else {
sprintf(nvbuf + strlen(nvbuf), "\n\n");
}
}
} else {
sprintf(nvbuf, "\n\tDefault NVRAM Settings:\n\n");
}
char bpl;
if (prefs.getUChar("b") != 1) bpl = 's';
if (prefs.getChar("m", '~') != '~') {
sprintf(nvbuf + strlen(nvbuf), "\tGenerator Mode:\t\t%s Wave\n", makeHumanMode(prefs.getChar("m")).c_str());
}
if (prefs.getFloat("f", -1) != -1) {
sprintf(nvbuf + strlen(nvbuf), "\tFrequency:\t\t%s\n", makeHumanFrequency(prefs.getFloat("f")).c_str());
}
if (prefs.getUChar("a", '~') != '~') {
sprintf(nvbuf + strlen(nvbuf), "\tAmplitude Level:\t%i \n", prefs.getUChar("a"));
}
if (prefs.getFloat("s", -1) != -1) {
sprintf(nvbuf + strlen(nvbuf), "\tFrequency Step:\t\t%s \n", makeHumanFrequency(prefs.getFloat("s")).c_str());
}
if (prefs.getUChar("p", '~') != '~') {
sprintf(nvbuf + strlen(nvbuf), "\tPulse Width:\t\t%i%% \n", prefs.getUChar("p"));
}
if (prefs.getUChar("j", '~') != '~') {
sprintf(nvbuf + strlen(nvbuf), "\tPWM Step:\t\t%i%% \n", prefs.getUChar("j"));
}
if (prefs.getUChar("b", '~') != '~') {
sprintf(nvbuf + strlen(nvbuf), "\tPWM resolution:\t\t%i bit%c\n", prefs.getUChar("b"), bpl);
}
if (prefs.getChar("h", '~') != '~') {
sprintf(nvbuf + strlen(nvbuf), "\tTouch Mode:\t\t%s\n", makeHumanTouchMode(prefs.getChar("h")).c_str());
}
if (eXi && !listing) sprintf(nvbuf + strlen(nvbuf), getFreeEntries().c_str());
}
if (presetNumber != 0) prefsSwitch();
return (String)nvbuf;
}
String listPresets(bool init = false) {
String xMSG, tmpString;
for( uint8_t i = 1; i <= presetMAX; i++ ) xMSG += getNVRAMPresetData(i, true, init);
xMSG = (xMSG != "") ? "Listing Preset Memories..\n" + xMSG : "No Presets Exist!\n";
if (!init) return xMSG + getFreeEntries();
return getFreeEntries();
}
String listLoops(bool oneLine) {
String xMSG, loopEnd = "\n", divider = "";
if (oneLine) {
loopEnd = commandDelimiter;
divider = "\n";
}
String sLoops = prefs.getString("o", "");
if (sLoops != "") xMSG = " loop=" + sLoops + loopEnd;
for( uint8_t i = 1; i <= presetMAX; i++ ) {
prefsSwitch(i);
sLoops = prefs.getString("o", "");
if (sLoops != "") xMSG += " loop" + (String)i + "=" + sLoops + loopEnd;
}
prefsSwitch();
return (xMSG != "") ? "Listing Stored Loops/Macros..\n\n" + xMSG + divider + getFreeEntries(): "No loops found!";
}
void endLoop() {
iLooping = false;
QCommand = "";
eXi = eXiTmp;
}
String getFreeEntries() {
char nvbuf[64];
nvs_stats_t nvs_stats;
nvs_get_stats(NULL, &nvs_stats);
sprintf(nvbuf, "\n Used %d of %d total NVS entries (%d free)",
nvs_stats.used_entries, nvs_stats.total_entries, nvs_stats.free_entries);
return (String)nvbuf;
}
void WipeNVRAM() {
esp_err_t ret = nvs_flash_init();
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
ESP_ERROR_CHECK(ret);
}
void startServer() {
uint32_t currentTime = millis();
uint32_t startTime = currentTime;
bool WebControl = true;
bool APControl = true;
if (eXi && softAPSSID == "") Serial.println("\n Soft Access Point Disabled.");
if (onlyAP && softAPSSID != "") {
WiFi.mode(WIFI_AP);
if (!isEmptyChar(&SGhostName)) WiFi.setHostname(SGhostName);
if (eXi) Serial.println("\n Running in Access Point Only Mode.");
} else {
WiFi.mode(WIFI_AP_STA);
if (!isEmptyChar(&SGhostName)) WiFi.setHostname(SGhostName);
if (!isEmptyChar(&ssid)) {
Serial.printf("\n Connecting to %s", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
currentTime = millis();
if (currentTime > (startTime + (timeOut * 1000))) {
Serial.printf("\n\n Connecting to %s FAILED.\n", ssid);
WebControl = false;
break;
}
}
if (WiFi.status() == WL_CONNECTED) {
Serial.print(" Success!\n Local WiFi Web Address: http:); // I'd love to use printf here!
Serial.print(WiFi.localIP());
Serial.println("/");
}
} else { WebControl = false; }
}
if (RemControl && softAPSSID != "") {
IPAddress local_IP(192,168,4,1);
IPAddress gateway(192,168,4,1);
IPAddress subnet(255,255,255,0);
WiFi.softAPConfig(local_IP, gateway, subnet);
if (WiFi.softAP(softAPSSID, softAPPass)) {
Serial.print("\n WiFi Access Point Established.\n Connect your WiFi to ");
Serial.println("\"" + softAPSSID + "\".");
Serial.print(" Once connected to the AP, point your browser to: http:);
Serial.print(WiFi.softAPIP());
Serial.println("/");
} else { APControl = false; }
} else { APControl = false; }
if (APControl || WebControl) {
if (!isEmptyChar(&SGhostName)) {
Serial.println("\n You can also access your Signal Generator here: http: + (String)WiFi.getHostname() + "/");
}
Serial.println();
Serial.println(" The Web Console is at /console");
Serial.println(" To see a list of available commands, send: c");
Serial.println();
Serial.println(" Load a simple two-button frequency up/down interface at /simple");
Serial.println(" Or the same page, but instead controlling Pulse Width at /pwm or Resolution at /bits");
Serial.println();
Serial.println(" You can send *any* command as a simple URL, e.g. /p25 to set Pulse Width to 25%");
Serial.println();
Serial.println(" Some text/plain URLs you may find useful: /wave /frequency /status /list /help");
Serial.println();
pinMode(led, OUTPUT);
for (uint8_t i = 0; i < 3; i++) {
digitalWrite(led, HIGH);
delay(100);
digitalWrite(led, LOW);
delay(50);
}
server.on("/", sendRoot);
server.on("/setFreqency", handleFreqencyChange);
server.on("/setStep", handleStepChange);
server.on("/setBitDepth", handleBitDepthChange);
server.on("/setPulseWidth", handlePulseWidthChange);
server.on("/setUP", handleFreqencyUP);
server.on("/setDOWN", handleFreqencyDOWN);
server.on("/pulseUP", handlePulseUP);
server.on("/pulseDOWN", handlePulseDOWN);
server.on("/resUP", handleResUP);
server.on("/resDOWN", handleResDOWN);
server.on("/setSquare", handleSetSquareWave);
server.on("/setSine", handleSetSineWave);
server.on("/setTriangle", handleSetTriangleWave);
server.on("/wave", handleUpdateWaveMode);
server.on("/frequency", handleUpdateFrequency);
server.on("/status", handleStatus);
server.on("/reboot", handleReboot);
server.on("/loadPreset", handleLoadPreset);
server.on("/savePreset", handleSavePreset);
server.on("/console", sendWebConsole);
server.on("/LastMessage", handleLastMessage);
server.on("/simple", sendSimplePage);
server.on("/freq", sendSimplePage);
server.on("/pwm", sendSimplePage);
server.on("/bits", sendSimplePage);
server.on("/favicon.ico", handleFavicon);
server.on("/help", sendHelpPage);
server.on("/c", sendHelpPage);
server.on("/Help", sendHelpPageHTML);
server.on("/C", sendHelpPageHTML);
server.on("/list", sendListPage);
server.on("/List", sendListPageHTML);
server.on("/presets", sendListPage);
server.on("/Presets", sendListPageHTML);
server.on("/end", handleEndLoop);
server.onNotFound(handleWebConsole);
server.begin();
Serial.println(" Web Server Started. Enjoy!");
} else {
Serial.println("\n\n Connecting to WiFi FAILED.\n Web controls disabled.");
}
}
void sendRoot() {
WebPage.replace("{Version}", version);
WebPage.replace("{1}", getPresetName(1));
WebPage.replace("{2}", getPresetName(2));
WebPage.replace("{3}", getPresetName(3));
WebPage.replace("{4}", getPresetName(4));
WebPage.replace("{5}", getPresetName(5));
WebPage.replace("{6}", getPresetName(6));
WebPage.replace("{7}", getPresetName(7));
WebPage.replace("{8}", getPresetName(8));
WebPage.replace("{9}", getPresetName(9));
server.send(200, _HTML5_TEXT_, WebPage);
if (eXi) Serial.printf(" HTTP Request: Main Page for client @ %s\n", \
server.client().remoteIP().toString().c_str());
}
void handleUpdateWaveMode() {
server.send(200, _PLAIN_TEXT_, makeHumanMode(mode));
if (eXi) Serial.println(" HTTP Request: Get Waveform");
}
void handleUpdateFrequency() {
server.send(200, _PLAIN_TEXT_, makeHumanFrequency(frequency));
if (eXi) Serial.println(" HTTP Request: Get Frequency");
}
void handleFreqencyChange() {
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "frequency") {
WebCommand = server.arg(i);
break;
}
}
server.send(200, _PLAIN_TEXT_, "Changing Frequency..");
if (eXi) Serial.println(" HTTP Request (Frequency Change): " + WebCommand);
}
void handleStepChange() {
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "step") {
WebCommand = "f" + server.arg(i);
break;
}
}
server.send(200, _PLAIN_TEXT_, "Changing Frequency Step..");
if (eXi) Serial.println(" HTTP Request (Step Size Change): " + WebCommand);
}
void handleBitDepthChange() {
String iData;
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "bits") {
iData = server.arg(i);
WebCommand = "b" + iData;
break;
}
}
char bpl;
if (iData.toInt() != 1) bpl = 's';
server.send(200, _PLAIN_TEXT_, "Changing Resolution..");
if (eXi) Serial.printf(" HTTP Request: Bit Depth. %s bit%c\n", iData.c_str(), bpl);
}
void handlePulseWidthChange() {
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "pulse") {
WebCommand = "p" + server.arg(i);
break;
}
}
server.send(200, _PLAIN_TEXT_, "Changing Pulse Width..");
if (eXi) Serial.println(" HTTP Request:" + WebCommand);
}
void handleFreqencyUP() {
frequencyStepUP(1);
String mf = makeHumanFrequency(frequency);
server.send(200, _PLAIN_TEXT_, "Frequency UP to " + mf + recState());
if (eXi) Serial.printf(" HTTP Request: Frequency UP to %s\n", mf.c_str());
}
void handleFreqencyDOWN() {
frequencyStepDOWN(1);
String mf = makeHumanFrequency(frequency);
server.send(200, _PLAIN_TEXT_, "Frequency DOWN to " + mf + recState());
if (eXi) Serial.printf(" HTTP Request: Frequency DOWN to %s\n", mf.c_str());
}
void handlePulseUP() {
pwmStepUP(storeButton);
server.send(200, _PLAIN_TEXT_, "Pulse Width UP to " + (String)pulse);
if (eXi) Serial.printf(" HTTP Request: Pulse Width UP to %i\n", pulse);
}
void handlePulseDOWN() {
pwmStepDOWN(storeButton);
server.send(200, _PLAIN_TEXT_, "Pulse Width DOWN to " + (String)pulse);
if (eXi) Serial.printf(" HTTP Request: Pulse Width DOWN to %i\n", pulse);
}
void handleResUP() {
bitsStepUP(storeButton);
server.send(200, _PLAIN_TEXT_, "Resolution Bit Depth UP to " + (String)PWMResBits);
if (eXi) Serial.printf(" HTTP Request: Resolution Bit Depth UP to %i\n", PWMResBits);
}
void handleResDOWN() {
bitsStepDOWN(storeButton);
server.send(200, _PLAIN_TEXT_, "Resolution Bit Depth DOWN to " + (String)PWMResBits);
if (eXi) Serial.printf(" HTTP Request: Resolution Bit Depth DOWN to %i\n", PWMResBits);
}
void handleSetSquareWave() {
WebCommand = "r";
server.send(200, _PLAIN_TEXT_, "Setting Square Wave..");
if (eXi) Serial.println(" HTTP Request: " + WebCommand);
}
void handleSetSineWave() {
WebCommand = "s";
server.send(200, _PLAIN_TEXT_, "Setting Sine Wave..");
if (eXi) Serial.println(" HTTP Request: " + WebCommand);
}
void handleSetTriangleWave() {
WebCommand = "t";
server.send(200, _PLAIN_TEXT_, "Setting Triangle Wave..");
if (eXi) Serial.println(" HTTP Request: " + WebCommand);
}
void handleStatus() {
String settings = getCurrentSettings();
if (eXi) Serial.println(" HTTP Request: Get Current Settings.");
server.send(200, _PLAIN_TEXT_, settings);
}
void handleReboot() {
Serial.println(" HTTP Request: Reboot.");
WebCommand = "reboot";
server.send(200, _PLAIN_TEXT_, "Rebooting..");
if (eXi) Serial.println(" HTTP Request: " + WebCommand);
}
void handleEndLoop() {
endLoop();
if (eXi) Serial.println(" HTTP Request: End Loop.");
server.send(200, _PLAIN_TEXT_, "Exiting Loop");
}
void handleLoadPreset() {
String val, state;
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "preset") {
val = server.arg(i);
state = loadPreset(val.toInt());
startSignal("WebLoad");
break;
}
}
server.send(200, _PLAIN_TEXT_, " [" + state + "]");
if (eXi) Serial.println(" HTTP Request: " + state);
}
void handleSavePreset() {
String val, state = "FAIL";
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "preset") {
val = server.arg(i);
state = savePreset(val.toInt());
break;
}
}
server.send(200, _PLAIN_TEXT_, " [" + state + "]");
if (eXi) Serial.println(" HTTP Request: " + state);
}
void handleWebConsole() {
fromWebConsole = true;
WebCommand = server.uri().substring(1);
server.send(200, _PLAIN_TEXT_, WebCommand + ": OK\nSee /LastMessage for any output from your command.");
if (eXi) Serial.printf(" HTTP Request: WebCommand: %s\n", WebCommand.c_str());
}
void handleLastMessage() {
server.send(200, _PLAIN_TEXT_, (LastMessage == "") ? getCurrentSettings() : LastMessage);
LastMessage = "";
}
void sendWebConsole() {
String myClient = server.client().remoteIP().toString();
if (knownClients.indexOf(myClient) == -1) {
WebConsole.replace("<!--{insert}-->", getCommands());
knownClients += myClient;
}
server.send(200, _HTML5_TEXT_, WebConsole);
if (eXi) Serial.printf(" HTTP Request: WebConsole for client @ %s\n", myClient.c_str());
}
void sendSimplePage() {
String SimplePage = R"SimplePage(<!DOCTYPE html><html><head><title>ESP32 Signal Generator</title><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="shortcut icon" type="image/png" sizes="16x16" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+cBFRcAJyFRDxkAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAA3ElEQVQoz4WRP0tCcRSGH34u0ReIxoKQwBovTQ1iGPgxwqFdcg/nvoHQ3DdoqqFJh8ylMXFsMCSoIa+Pg97rn3vDZznDeTnnvOfFsgP/Y2CZpB07yZUwr13PLfmYowgAQy7Y55QqPTKo3nrsyJFFr5xuTEA/DbZVbUvm4gB9pkQAnAHvGxsCdNnhAIBD9nhLW01uAGJrXqcDG0YLu2Pxbn7DKg/ih6o98TmxueQEeAWgQ6CU2Fzy56UVf/yyaCuxuc6T2LDu7sJwRhB7b8EjX9JH5WT57e9KWFvingFTFG1S956a3gAAAABJRU5ErkJggg=="/></head><style>html{width:100% !important;height:100vh !important;color:controller"><button id="fup" onclick="clickUP()" class="step-button" title="UP">⌃</button><button id="fdown" onclick="clickDOWN()" class="step-button" title="DOWN">⌄</button></div><script>function clickUP(){var AJAX=new XMLHttpRequest();AJAX.open("GET","setUP",true);AJAX.send();}function clickDOWN(){var AJAX=new XMLHttpRequest();AJAX.open("GET","setDOWN",true);AJAX.send();}document.onkeydown=ArrowKeys;function ArrowKeys(e){if(e.keyCode=='38'){clickUP();}else if(e.keyCode=='40'){clickDOWN();}else if(e.keyCode=='37'){clickDOWN();}else if(e.keyCode=='39'){clickUP();}}</script></body></html>)SimplePage";
if (server.uri() == "/pwm") {
SimplePage.replace("setUP", "pulseUP");
SimplePage.replace("setDOWN", "pulseDOWN");
}
if (server.uri() == "/bits") {
SimplePage.replace("setUP", "resUP");
SimplePage.replace("setDOWN", "resDOWN");
}
server.send(200, _HTML5_TEXT_, SimplePage);
if (eXi) Serial.printf(" HTTP Request: Simple Page for client @ %s\n", \
server.client().remoteIP().toString().c_str());
}
void handleFavicon() {
String favicon = R"SVGfavicon(<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="16.000000pt" height="16.000000pt" viewBox="0 0 16.000000 16.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,16.000000) scale(0.100000,-0.100000)" fill="
server.send(200, "image/svg+xml", favicon);
}
void sendListPage() {
LastMessage = listPresets();
server.send(200, _PLAIN_TEXT_, LastMessage);
if (eXi) Serial.println(" HTTP Request: List Presets");
}
void sendListPageHTML() {
LastMessage = listPresets();
server.send(200, _PLAIN_TEXT_, "<!DOCTYPE html><pre>" + LastMessage);
if (eXi) Serial.println(" HTTP Request: List Presets (HTML)");
}
void sendHelpPage() {
LastMessage = getCommands();
server.send(200, _PLAIN_TEXT_, LastMessage);
if (eXi) Serial.println(" HTTP Request: help");
}
void sendHelpPageHTML() {
LastMessage = getCommands();
server.send(200, _PLAIN_TEXT_, "<!DOCTYPE html><pre>" + LastMessage);
if (eXi) Serial.println(" HTTP Request: help (HTML)");
}
String importSettings(char *imported, uint8_t presetNumber = 0) {
String thisPref;
char iBuff[1064];
sprintf(iBuff, "\n Importing Settings..\n\n");
char bpl;
char localMode = mode;
if (presetNumber != 0) {
prefsSwitch(presetNumber);
prefs.putChar("i", 1);
}
while ((thisPref = strsep(&imported, ","))) {
char prefType = thisPref[0];
char cVal = thisPref[2];
String thisVal = thisPref.substring(2);
int8_t thisINT = thisVal.toInt();
if (presetNumber != 0) {
switch (prefType) {
case 'm' :
prefs.putChar("m", cVal);
localMode = cVal;
sprintf(iBuff + strlen(iBuff), "\tSaving Mode: %s\n", makeHumanMode(cVal).c_str());
break;
case 'f' :
prefs.putFloat("f", humanFreqToFloat(thisVal));
sprintf(iBuff + strlen(iBuff), "\tSaving Frequency: %s\n", makeHumanFrequency(prefs.getFloat("f")).c_str());
break;
case 'p' :
if (localMode != 's' || saveALL) {
prefs.putUChar("p", thisINT);
sprintf(iBuff + strlen(iBuff), "\tSaving Pulse Width: %i%%\n", thisINT);
}
break;
case 'a' :
if (localMode != 'r' || saveALL) {
prefs.putUChar("a", thisINT);
sprintf(iBuff + strlen(iBuff), "\tSaving Amplitude Level: %i\n", thisINT);
}
break;
case 'j' :
if (localMode != 's' || saveALL) {
prefs.putUChar("j", thisINT);
sprintf(iBuff + strlen(iBuff), "\tSaving Pulse Width Step: %i%%\n", thisINT);
}
break;
case 'b' :
if (localMode == 'r' || saveALL) {
prefs.putUChar("b", thisINT);
if (thisINT != 1) bpl = 's';
sprintf(iBuff + strlen(iBuff), "\tSaving Resolution Bit Depth: %i bit%c\n", thisINT, bpl);
}
break;
case 's' :
prefs.putFloat("s", humanFreqToFloat(thisVal));
sprintf(iBuff + strlen(iBuff), \
"\tSaving Frequency Step: %s\n", makeHumanFrequency(prefs.getFloat("s")).c_str());
break;
case 'h' :
prefs.putChar("h", cVal);
sprintf(iBuff + strlen(iBuff), "\tSaving Touch Mode: %s\n", makeHumanTouchMode(cVal).c_str());
break;
}
} else {
switch (prefType) {
case 'm' :
setMode(cVal);
sprintf(iBuff + strlen(iBuff), "\tSetting Mode to: %s\n", makeHumanMode(mode).c_str());
break;
case 'f' :
frequencySet(thisVal, false, false);
sprintf(iBuff + strlen(iBuff), "\tSetting Frequency to: %s\n", makeHumanFrequency(frequency).c_str());
break;
case 'p' :
sprintf(iBuff + strlen(iBuff), "\tSetting Pulse Width to: %i%%\n", setPulseWidth(thisINT));
break;
case 'a' :
if (setAmplitude(thisINT)) sprintf(iBuff + strlen(iBuff), "\tSetting Amplitude Level to: %i\n", thisINT);
break;
case 'j' :
if (setPulseStep(thisINT)) sprintf(iBuff + strlen(iBuff), "\tSetting Pulse Width Step to: %i%%\n", thisINT);
break;
case 'b' :
PWMResBits = switchResolution(thisINT);
if (PWMResBits != 1) bpl = 's';
sprintf(iBuff + strlen(iBuff), "\tSetting Resolution Bit Depth to: %i bit%c\n", PWMResBits, bpl);
break;
case 's' :
frequencyStepSet(thisVal);
sprintf(iBuff + strlen(iBuff), "\tSetting Frequency Step to: %s\n", makeHumanFrequency(fStep).c_str());
break;
case 'h' :
setTouchMode(cVal);
sprintf(iBuff + strlen(iBuff), "\tSetting Touch Mode to: %s\n", makeHumanTouchMode(touchMode).c_str());
break;
}
}
}
if (presetNumber != 0) prefsSwitch();
return (String)iBuff;
}
0", bool all = false) { all" is true during an "export all" command
if (exData.indexOf("all") != -1 ) return exportALLSettings();
int8_t presetNUM = 0;
int8_t success = 0;
char prebuff[256];
char eBuff[256];
String loopData, thisPreset, eName;
String first = exData.substring(0,1);
loopData.reserve(20480);
export" (to export defaults).
if (exData[0] == '=') {
presetNUM = exData.substring(1).toInt();
} else if (first != "0" && first != "") {
presetNUM = exData.substring(0).toInt(); 4" as well as "4", " 04" and "04".
}
if (presetNUM < 0 || presetNUM > presetMAX) success = -1;
if (success == 0) {
if (presetNUM != 0) {
thisPreset = (String)presetNUM;
if (!prefsSwitch(presetNUM)) success = -2;
}
if (success == 0) {
String eType;
if (!all) {
eType = "Exporting ";
eType += (presetNUM == 0) ? "Default settings: \n\n " : \
"Preset " + thisPreset + ": \"" + prefs.getString("n") + "\"\n\n ";
eType += "w" + ((presetNUM == 0) ? "" : thisPreset) + commandDelimiter;
}
sprintf(prebuff, "%simport%s ", eType.c_str(), (presetNUM == 0) ? "" : thisPreset.c_str());
if (prefs.getChar("m", '~') != '~') sprintf(eBuff, "m=%c,", prefs.getChar("m"));
if (prefs.getFloat("f", -1) != -1) sprintf(eBuff + strlen(eBuff), \
"f=%s,", makeHumanFrequency(prefs.getFloat("f"), true).c_str());
if (prefs.getUChar("p", '~') != '~') sprintf(eBuff + strlen(eBuff), "p=%i,", prefs.getUChar("p"));
if (prefs.getUChar("b", '~') != '~') sprintf(eBuff + strlen(eBuff), "b=%i,", prefs.getUChar("b"));
if (prefs.getFloat("s", -1) != -1) sprintf(eBuff + strlen(eBuff), "s=%s,", \
makeHumanFrequency(prefs.getFloat("s"), true).c_str());
if (prefs.getUChar("j", '~') != '~') sprintf(eBuff + strlen(eBuff), "j=%i,", prefs.getUChar("j"));
if (prefs.getUChar("a", '~') != '~') sprintf(eBuff + strlen(eBuff), "a=%i,", prefs.getUChar("a"));
if (prefs.getChar("h", '~') != '~') sprintf(eBuff + strlen(eBuff), "h=%c,", prefs.getChar("h"));
if (prefs.getString("n", "") != "" && thisPreset != "") \
eName = commandDelimiter + "n" + thisPreset + "=" + prefs.getString("n");
if (!all && prefs.getString("o", "") != "" && exportALL) {
loopData += commandDelimiter + " loop" + ((presetNUM == 0) ? "" : thisPreset) + "=" + prefs.getString("o");
success = 0;
}
}
if (presetNUM != 0) prefsSwitch();
}
String ret;
uint8_t length = strlen(eBuff);
if (length > 1) {
eBuff[length-1] = '\0';
ret = (String)prebuff + (String)eBuff + eName;
} else if (loopData == "" && success != -2) success = -3;
switch (success) {
case -1:
if (!all) return _OUT_OF_RANGE_;
break;
case -2:
if (!all) return " No such preset";
break;
case -3:
if (!all) return " No settings to export!";
break;
case 0:
return ret + loopData;
}
return "";
}
list" to have a look-see. "l1", "l2", etc.. to load them up.)
It's basically just a string of commands separated by the ";" (semicolon - or whatever you set in
your prefs) character:
:repeat:
wipe specified preset
load settings into preset
name the preset
:repeat:
The /final/ batch of settings is/becomes your *current* settings.
And yes, it's fine to send that as a URL.
Any stored loops/macros encountered along the way will be tagged onto the end.
*/
String exportALLSettings() {
String data = "", seperator, lD, loopData = "";
data.reserve(20480);
loopData.reserve(20480);
for( uint8_t i = 1; i <= presetMAX; i++ ) {
String pData = exportSettings((String)i, true);
if (prefsSwitch(i)) {
if (pData != "") {
data += "w" + (String)i + commandDelimiter;
data += pData + commandDelimiter;
}
lD = prefs.getString("o", "");
if (lD != "") loopData += commandDelimiter + " loop" + (String)i + "=" + lD;
}
prefsSwitch();
}
String curSettings = exportSettings("", true);
if (curSettings != "") data += "w" + commandDelimiter + curSettings;
lD = prefs.getString("o", "");
if (lD != "") loopData = commandDelimiter + " loop=" + lD + loopData;
if (data != "" || loopData != "") return data + loopData;
return "No settings to export!";
}
;e" or ";rte", etc. to your setup command, if required.
void printBasicSketchInfo() {
int sketchSize = ESP.getSketchSize();
int sketchFreeSpace = ESP.getFreeSketchSpace();
Sketch MD5: %s\n", sketchMD5.c_str());
float_t sketchFreePct = 100 * sketchSize / sketchFreeSpace;
Serial.printf("\n Sketch Size: %i (total: %i, %.1f%% used)\n", sketchSize, sketchFreeSpace, sketchFreePct);
Last Modified: %s\n", modified_time); // This is set up near the top (see notes there).
Compiled: %s\n", compile_time);
Serial.printf(" Compiled: %s\n", compile_time);
Serial.printf(" ESP32 SDK: %s\n", ESP.getSdkVersion());
Serial.println();
}
bool setCPUSpeed(uint32_t newSpeed, bool init = false) {
bool setFrequency = false;
if (newSpeed == 240 || newSpeed == 160 || newSpeed == 80) {
setFrequency = setCpuFrequencyMhz(newSpeed);
} else {
Serial.printf("\n Allowed CPU Speed Values: 240, 160 & 80\n");
return false;
}
if (init || !RemControl) {
Serial.printf("\n Crystal Frequency: %iMHz\n", getXtalFrequencyMhz());
Serial.printf(" APB Frequency: %s\n", makeHumanFrequency(getApbFrequency()).c_str());
Serial.printf(" CPU Frequency Set to: %iMHz\n", getCpuFrequencyMhz());
}
if (setFrequency) cpuSpeed = newSpeed;
return setFrequency;
}
String setupPhysicalButtons(bool reportOnly = true) {
char demButts[512] = {'\0'};
if (useButtons) {
Serial.println("\n Available Buttons:");
for (uint8_t i = 0; i < buttonCount; i++) {
if (buttonPins[i] != 0 && buttonCommands[i] != "") {
if (!reportOnly) {
buttons.my_butt[i].pin = buttonPins[i];
buttons.my_butt[i].command = buttonCommands[i];
buttons.my_butt[i].state = 0;
buttons.my_butt[i].oldState = 0;
pinMode(buttonPins[i], INPUT_PULLDOWN);
}
sprintf(demButts, " Button %i: Pin: %i Command: %s\n", i+1, buttonPins[i], buttonCommands[i].c_str());
}
}
}
return (String)demButts;
}
void loop() {
bool buttonPressed = false;
uint32_t currentTime = millis();
bool tmpE = eXi;
if (useButtons) {
for (uint8_t i = 0; i < buttonCount; i++) {
if (buttons.my_butt[i].pin != 0) {
buttons.my_butt[i].state = digitalRead(buttons.my_butt[i].pin);
if (buttons.my_butt[i].state != buttons.my_butt[i].oldState) {
if (buttons.my_butt[i].state == 1) {
QCommand = buttons.my_butt[i].command;
buttonPressed = true;
}
buttons.my_butt[i].oldState = buttons.my_butt[i].state;
}
}
}
}
if (!buttonPressed) {
if (touchRead(touchUPPin) < touchThreshold) {
if (mode == 'f' || currentTime > (touchTimer + deBounce)) {
touchTimer = currentTime;
if (!reportTouches) eXi = false;
touchUPStep();
if (!reportTouches) eXi = tmpE;
return;
}
}
if (touchRead(touchDOWNPin) < touchThreshold) {
if (mode == 'f' || currentTime > (touchTimer + deBounce)) {
touchTimer = currentTime;
if (!reportTouches) eXi = false;
touchDOWNStep();
if (!reportTouches) eXi = tmpE;
return;
}
}
if (amDelaying) {
if(currentTime < delayStart + delayTime) return;
amDelaying = false;
}
if (usePOT) {
uint16_t lowVAL = 0;
uint16_t highVAL = 10;
uint16_t pValue;
if (currentTime > (touchTimer + deBounce/stepAccuracy)) {
touchTimer = currentTime;
analogValue = analogRead(potPIN);
if (analogValue > analogValueOLD + (101-stepAccuracy) || analogValue < analogValueOLD - (101-stepAccuracy) ) {
switch (potMode) {
case 'p' :
lowVAL = 0;
highVAL = 100;
break;
case 'f' :
lowVAL = FreqLowerPotLimit;
highVAL = FreqUpperPotLimit;
break;
case 'b' :
lowVAL = 1;
highVAL = 10;
}
pValue = map(analogValue, 0, 4096, lowVAL, highVAL);
Setting %s to mapped POT Value: %i\n", makeHumanTouchMode(potMode), pValue); //debug
switch (potMode) {
case 'p' :
setPulseWidth(pValue);
break;
case 'f' :
frequencySet((String)pValue);
break;
case 'b' :
switchResolution(pValue);
}
startSignal("Potentiometer Change");
analogValueOLD = analogValue;
}
}
}
}
raw" with that String, whatever it is..
*/
if ((Serial.available() > 0) || (WebCommand != "") || QCommand !="") {
bool isSerial = false;
String raw, input, xMSG;
if (QCommand != "") {
if (Serial.peek() > 0 && Serial.readStringUntil('\n') == "end") {
endLoop();
if (eXi) Serial.println(" Command: 'end'");
return;
}
raw = QCommand;
} else {
if (Serial.peek() > 0) {
isSerial = true;
raw = Serial.readStringUntil('\n');
} else {
raw = urlDecode(WebCommand);
WebCommand = "";
}
}
raw.trim();
int16_t eqPos = raw.indexOf("=");
loop*=" (loop/macro load) ..
if (eqPos != -1 && eqPos < 11 && raw.substring(0,4) == "loop") {
trimDelims(raw);
loop" only found in the comment/name)
loopCommands = raw.substring(eqPos+1);
QCommand = "";
loop" somewhere..
if (raw.substring(eqPos).indexOf("loop") != -1 ) {
loop" in their names. Let's check /all/ that..
*/
int16_t gotLoopPlay = -1, gotLoopLoad = -1;
bool insideComment = false, foundLoop = false;
stream parser".
Makes sense here as we have a lot to check for. Also, I like simple.
*/
for (int16_t i = (eqPos+1); i < raw.length(); i++) {
if (raw[i] == ' ') continue;
if (raw[i] == ':') {
insideComment = true;
continue;
}
if ((String)raw[i] == commandDelimiter) {
if (foundLoop) {
loop" and now the command has ended. Gotta be a simple (default) loop play..
gotLoopPlay = i;
break;
}
insideComment = false;
continue;
}
if (insideComment) continue;
if (raw[i] == 'p' && raw[i-1] == 'o' && raw[i-2] == 'o' && raw[i-3] == 'l') {
foundLoop = true;
continue;
}
loop"), move on to next iteration..
if (!foundLoop) continue;
loop". w00H00!
continue" as long as it's more digits)
if (isDigit(raw[i])) continue;
if (raw[i] == '=') {
gotLoopLoad = i;
break;
loop" then maybe digits, but no '='. Must be a loop PLAY command, then.
} else {
gotLoopPlay = i;
break;
}
} loop" test loop.
if (gotLoopPlay != -1) {
loopCommands = raw.substring((eqPos+1), gotLoopPlay);
QCommand = raw.substring(loopCommands.length() + (eqPos+1));
} else if (gotLoopLoad != -1) {
loopCommands = raw.substring((eqPos+1), gotLoopLoad - (eqPos+1));
QCommand = raw.substring(loopCommands.length() + (eqPos+1));
}
trimDelims(QCommand);
}
trimDelims(loopCommands);
String presetNumTest = raw.substring(4, eqPos); loop" up to the "=" sign
presetNumTest.trim();
int16_t presetNumber = presetNumTest.toInt();
if (presetNumber < 0 || presetNumber > presetMAX) {
LastMessage = "Specified " + _OUT_OF_RANGE_;
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
return;
}
if (presetNumber != 0) {
prefsSwitch(presetNumber);
if (loopCommands != "-") prefs.putChar("i", 1);
}
if (loopCommands == "-") {
if (prefs.getString("o", "") != "") {
prefs.putString("o", "");
LastMessage = "Wiping loop commands";
if (presetEmpty()) {
LastMessage += " and empty preset";
wipePreset(presetNumber);
}
} else LastMessage = "No loop commands found!";
} else if (loopCommands) {
if (loopCommands.length() > 3999) {
Serial.println(" Loop Commands Too Large To Store! (4000 bytes maximum)");
Serial.println(" NOTE: You can split your commands into multiple loops and chain them together.");
} else {
LastMessage = (prefs.putString("o", loopCommands)) ? \
"Saved loop commands" : "Failed to save loop commands";
}
}
if (presetNumber != 0) {
LastMessage += " (for preset " + presetNumTest + ")";
prefsSwitch();
}
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
entries"..
if (QCommand.indexOf("loop") == QCommand.indexOf("=") && (isSerial || eXi)) \
Serial.printf("%s\n\n", getFreeEntries().c_str());
return;
} else {
int16_t qTest = raw.indexOf(commandDelimiter);
if (qTest != -1) {
input"..
input = raw.substring(0, qTest);
QCommand = raw.substring(qTest + 1);
} else {
input = raw;
QCommand = (iLooping) ? loopCommands : "";
}
}
input.trim();
input" (a String) is now set.
Input Command: \'%s\'\n", input.c_str()); // debug
if (input[0] == 'n' || input[0] == 'N' ) {
LastMessage = namePreset(input.substring(1));
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
if (eXi) Serial.printf("%s\n\n", getFreeEntries().c_str());
return;
}
input.toLowerCase();
if (isSerial && eXi && QCommand == "") Serial.printf("\n Command: \'%s\'\n", input.c_str());
char cmd = input[0];
char chr2 = input[1];
String cmdData = input.substring(1);
cmdData.trim();
uint16_t iData = cmdData.toInt();
String vChange = "", loadedPreset = "", savedPreset = "";
bool mChange = false, fChange = false, pChange = false;
bool bChange = false, tChange = false, jChange = false, aChange = false;
other stuff" in the background during long delays.
This can also be used to create lighting displays, or whatever, e.g..
p10;~10;p15;~9;p20;~8;p30;~7;p40;~6;p50;~5;p60;~4;p70;~3;p80;~2;p90;~;p95;~;p100;~;p95;~;p90;~3;p80;~4;p70;~5;p60;~6;p50;~7;p40;~8;p30;~9;p20;~9;p15;~10
*/
if (cmd == '~') {
amDelaying = true;
if (iData != 0) delayTime = iData;
delayStart = millis();
return;
}
if (cmd == '*' && cmdData != "") {
xMSG = cmdData;
xMSG.trim();
uint32_t newFrequency = playMusicalNote(cmdData);
LastMessage = " Set Musical Note (" + xMSG + ") Frequency: " + (String)newFrequency + "Hz\n";
startSignal("Music");
if (isSerial && eXi && QCommand == "") Serial.printf(LastMessage.c_str());
return;
}
if (cmd == '+' && cmdData != "") {
xMSG = cmdData;
xMSG.trim();
frequencySet((String)(frequency + humanFreqToFloat(xMSG)));
fChange = true;
}
if (cmd == '-' && cmdData != "") {
xMSG = cmdData;
xMSG.trim();
frequencySet((String)(frequency - humanFreqToFloat(xMSG)));
fChange = true;
}
-" and "+" control PWM.
begin with" a char, but must == a "String" (or substring).
If you want a list of commands, you need to type exactly "c" (no quotes), so if you type
"crap", you get nada. This is mainly to prevent typos setting off unwanted consequences.
Also, some of the letters are dual (or more) use.
*/
if (input == "wipe") {
if (!isSerial && wipeIsSerialOnly) {
LastMessage = "NVRAM Wipe can only be performed from Serial Connexion";
Serial.printf(" %s\n", LastMessage.c_str());
return;
} else {
Serial.println(" Wiping NVRAM..");
WipeNVRAM();
input = "x";
}
}
i", "n", "o" and "q" are used internally, for preset index, preset name, stored loop/macro
data, and stored queued commands, respectively.
*/
if (input == "reset") {
prefs.remove("a");
prefs.remove("b");
prefs.remove("c");
prefs.remove("e");
prefs.remove("f");
prefs.remove("h");
prefs.remove("j");
prefs.remove("l");
prefs.remove("m");
prefs.remove("p");
prefs.remove("r");
prefs.remove("s");
prefs.remove("t");
prefs.remove("u");
prefs.remove("w");
prefs.remove("x");
prefs.remove("z");
Serial.println(" Wiping Stored Default Settings.");
input = "x";
}
if (input == "wap") {
onlyAP = true;
prefs.putBool("w", onlyAP);
Serial.println(" Setting WiFi Access Point Only Mode..");
input = "x";
}
if (input == "waa") {
onlyAP = false;
prefs.putBool("w", onlyAP);
Serial.println(" Setting WiFi Station + AP (All Access) Mode..");
input = "x";
}
if (input.substring(0,3) == "cpu") {
String newSpeed = input.substring(3);
newSpeed.trim();
if (setCPUSpeed(newSpeed.toInt())) {
prefs.putUInt("z", cpuSpeed);
if (RemControl) input = "x";
}
}
if (input.substring(0,6) == "remote") {
switch (input[6]) {
case 'e' :
RemControl = true;
break;
case 'd' :
RemControl = false;
break;
default:
RemControl = (RemControl) ? false : true;
}
xMSG = (RemControl) ? "enabled" : "disabled";
if (isSerial || eXi) Serial.printf("Remote Control is %s\n", xMSG.c_str());
prefs.putBool("r", RemControl);
input = "x";
}
if ((input == "x") || input == "reboot") {
if (QCommand != "") {
if (QCommand.length() > 3999) {
Serial.println(" Queued Commands Too Large To Store! (4000 bytes maximum)");
Serial.println("Do your 'wipe' command on its own, THEN your commands.");
} else {
prefsSwitch();
if (prefs.putString("q", QCommand)) Serial.println(" Queued Commands Stored: OK");
}
}
Serial.println(" Rebooting..");
Serial.flush();
prefs.end();
ESP.restart();
}
if (input == "ll") {
LastMessage = listLoops(false);
if (isSerial || eXi) Serial.printf("\n %s\n", LastMessage.c_str());
return;
}
if (input == "lll") {
LastMessage = listLoops(true);
if (isSerial || eXi) Serial.printf("\n %s\n", LastMessage.c_str());
return;
}
if (input == "buttons") {
LastMessage = setupPhysicalButtons();
if (isSerial || eXi) Serial.printf("%s", LastMessage.c_str());
return;
}
eqPos = input.indexOf(">");
if (eqPos != -1 && input.substring(0,4) == "copy") {
String copyFrom = input.substring(4, eqPos);
copyFrom.trim();
String copyTo = input.substring(eqPos+1);
copyTo.trim();
int8_t cT = copyTo.toInt();
LastMessage = copyPreset(copyFrom.toInt(), cT);
if (LastMessage.indexOf("OK") != -1) LastMessage += "\n" + getNVRAMPresetData(cT);
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
return;
}
if (input.substring(0,4) == "loop") {
String pNum = input.substring(4); loop".
pNum.trim();
int8_t ipNum = pNum.toInt();
String displayNum = "";
if (ipNum != 0) {
if (ipNum < 0 || ipNum > presetMAX) {
LastMessage = "Specified Loop/Macro " + _OUT_OF_RANGE_;
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
return;
}
prefsSwitch(ipNum);
displayNum = " (" + pNum + ")";
}
loopCommands = prefs.getString("o", loopCommands);
if (loopCommands != "") {
iLooping = true; end" command..
while (loopCommands.endsWith(commandDelimiter)) loopCommands.remove(loopCommands.length()-1);
QCommand = loopCommands;
LastMessage = "Processing Loop Commands" + displayNum + ": " + loopCommands;
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
eXiTmp = eXi;
eXi = false;
} else {
LastMessage = "No Loop Commands Found: ";
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
}
if (ipNum != 0) prefsSwitch();
return;
}
if (input == "end") {
endLoop();
return;
}
if (input == "stop" || input == "." || input == "silence") {
stopSignal();
return;
}
if (input == "version") {
LastMessage = "Signal Generator v" + version;
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
return;
}
m" would have the same effect. But when layering is enabled
(the default), you need to use "d" to get ALL the current settings into defaults.
*/
if (input == "d") {
LastMessage = savePreset(0, true);
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
return;
}
if (input == "wtf") {
LastMessage = "\n RTFM! ;o)";
\n %s\n", LastMessage.c_str());
if (isSerial || eXi) Serial.printf("\n %s\n", LastMessage.c_str());
return;
}
if (input == "c" || input == "help" || input == "?") {
LastMessage = getCommands();
if (isSerial || eXi) Serial.printf(" %s", LastMessage.c_str());
return;
}
if (input == "]") {
frequencyStepUP(fromWebConsole ? 3 : 2);
fromWebConsole = false;
fChange = true;
}
if (input == "[") {
frequencyStepDOWN(fromWebConsole ? 3 : 2);
fromWebConsole = false;
fChange = true;
}
if (input == "/" || input == "=" || input == "+") {
pwmStepUP(storeButton);
pChange = true;
}
if (input == "\\" || input == "-") {
pwmStepDOWN(storeButton);
pChange = true;
}
if (input == "a") {
PWMResBits = switchResolution(PWMResBits+1);
bChange = PWMResBits+1;
}
if (input == "z" ) {
PWMResBits = switchResolution(PWMResBits-1);
bChange = PWMResBits-1;
}
if (input == "e") {
eXi = eXi ? false : true;
LastMessage = "Extended Info: " + (String)(eXi ? "Enabled" : "Disabled");
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
prefs.putBool("e", eXi);
return;
}
if (input == "list") {
LastMessage = listPresets();
if (isSerial || eXi) Serial.printf(" %s\n\n", LastMessage.c_str());
return;
}
if (input.substring(0,6) == "import") {
xMSG = input.substring(6);
xMSG.trim();
String pNum;
while (isDigit(xMSG.charAt(0))) {
pNum += xMSG.charAt(0);
xMSG = xMSG.substring(1);
}
xMSG.trim();
char importDATA[72];
xMSG.toCharArray(importDATA, xMSG.length()+1);
sprintf(importDATA + strlen(importDATA), ",");
LastMessage = importSettings(importDATA, pNum.toInt()) + getFreeEntries() + "\n\n";
if (isSerial || eXi) Serial.print(LastMessage);
startSignal("import");
return;
}
if (input.substring(0,6) == "export") {
LastMessage = exportSettings(input.substring(6));
if (isSerial || eXi) Serial.printf("\n %s\n\n", LastMessage.c_str());
return;
}
ea" to toggle, "eae" to enable, "ead" to disable)
Only applies to exporting of /individual/ presets.
*/
if (input.substring(0,2) == "ea") {
switch (input[2]) {
case 'e' :
exportALL = true;
break;
case 'd' :
exportALL = false;
break;
default:
exportALL = (exportALL) ? false : true;
}
xMSG = (exportALL) ? "Enabled" : "Disabled";
LastMessage = "Export ALL is " + xMSG + ".";
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
prefs.putBool("x", exportALL);
return;
}
rt" to toggle, "rte" to enable, "rtd" to disable.
*/
if (input.substring(0,2) == "rt") {
switch (input[2]) {
case 'e' :
reportTouches = true;
break;
case 'd' :
reportTouches = false;
break;
default:
reportTouches = (reportTouches) ? false : true;
}
xMSG = (reportTouches) ? "enabled" : "disabled";
LastMessage = "Reporting touches to the console is " + xMSG + ".";
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
prefs.putBool("t", reportTouches);
return;
}
lp" to toggle, "lpe" to enable, "lpd" to disable)
*/
if (input.substring(0,2) == "lp") {
switch (input[2]) {
case 'e' :
layerPresets = true;
break;
case 'd' :
layerPresets = false;
break;
default:
layerPresets = (layerPresets) ? false : true;
}
xMSG = (layerPresets) ? "Enabled" : "Disabled";
LastMessage = "Layering Presets is " + xMSG + ".";
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
prefs.putBool("l", layerPresets);
return;
}
sa" to toggle, "sae" to enable, "sad" to disable)
*/
if (input.substring(0,2) == "sa") {
switch (input[2]) {
case 'e' :
saveALL = true;
break;
case 'd' :
saveALL = false;
break;
default:
saveALL = (saveALL) ? false : true;
}
xMSG = (saveALL) ? "Enabled" : "Disabled";
LastMessage = "Save ALL is " + xMSG + ".";
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
prefs.putBool("c", saveALL);
return;
}
if (input.substring(0,2) == "up") {
switch (input[2]) {
case 'e' :
usePOT = true;
break;
case 'd' :
usePOT = false;
break;
default:
usePOT = (usePOT) ? false : true;
}
xMSG = (usePOT) ? "Enabled" : "Disabled";
LastMessage = "Potentiometer Control is " + xMSG + ".";
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
prefs.putBool("u", usePOT);
return;
}
if (input.substring(0,3) == "mem") { memory information please" will also work.
char mbuf[380];
sprintf(mbuf, "\n Free memory: %d bytes\n", esp_get_free_heap_size());
sprintf(mbuf + strlen(mbuf), " This Task High Watermark: %d bytes\n", uxTaskGetStackHighWaterMark(NULL));
sprintf(mbuf + strlen(mbuf), " Available Internal Heap Size: %d\n", esp_get_free_internal_heap_size());
sprintf(mbuf + strlen(mbuf), " Minimum Free Heap Ever Available Size: %d\n", esp_get_minimum_free_heap_size());
sprintf(mbuf + strlen(mbuf), " Total Heap: %d\n", ESP.getHeapSize());
sprintf(mbuf + strlen(mbuf), " Free Heap: %d\n", ESP.getFreeHeap());
sprintf(mbuf + strlen(mbuf), getFreeEntries().c_str());
LastMessage = (String)mbuf;
if (isSerial || eXi) Serial.println(mbuf);
return;
}
if (input == "!") {
} else if (input == "r" || input == "s" || input == "t" || input == "'") {
char newMode = cmd;
s", cmd also == 's' (cmd == input[0], a char)
if (newMode != mode || input == "'") {
mChange = true;
if (input == "'") {
switch (mode) {
case 'r' :
mode = 's';
break;
case 's' :
mode = 't';
break;
default :
mode = 'r';
}
} else {
mode = newMode;
}
startSignal("Console Mode Change");
}
set". So we save it..
prefs.putChar("m", mode);
} else {
bool doWipe = true;
bool reGen = true;
switch (cmd) {
case ':' :
reGen = false;
break;
w" on its own wipes the main settings, which is useful for creating layered presets and
other stuff.
NOTE: Wiping a preset does NOT wipe any loop/macro data contained within the preset's
namespace. You need to wipe loops separately (loop*=-).
*/
case 'w' :
xMSG = "\n Clearing ";
if (input == "w") {
xMSG += "default preset.";
} else {
xMSG += "preset " + cmdData;
switch (cmdData.length()) {
case 3:
if (!isDigit(cmdData.charAt(2))) doWipe = false;
case 2:
if (!isDigit(cmdData.charAt(1))) doWipe = false;
case 1:
if (!isDigit(cmdData.charAt(0))) doWipe = false;
fall through" statements tell the compiler that we /meant/ to do this (i.e. no break;s).
}
}
if (doWipe) {
if (wipePreset(iData)) {
LastMessage = xMSG + "\n" + getFreeEntries() + "\n";
} else{
LastMessage = " No Such Preset";
}
} else {
LastMessage = " Invalid Wipe Command!";
}
if (isSerial || eXi) Serial.println("\n" + LastMessage);
return;
case '0' ... '9' :
fChange = true;
frequencySet(input);
break;
case 'p' :
setPulseWidth(iData);
pChange = true;
break;
fail" state returned here.
*/
case 'b' :
PWMResBits = switchResolution(iData);
bChange = iData;
break;
case 'f' :
case 's' :
frequencyStepSet(cmdData);
tChange = true;
reGen = false;
break;
case 'j' :
if (setPulseStep(iData)) jChange = true;
break;
case 'v' :
if (usePOT) {
switch (chr2) {
case 'p' :
potMode = 'p';
break;
case 'f' :
potMode = 'f';
break;
case 'b' :
potMode = 'b';
break;
default:
if (iData > 0 && iData <= 100) {
stepAccuracy = iData;
aChange = stepAccuracy;
}
}
} else {
LastMessage = "Potentiometer Not Enabled!";
if (isSerial || eXi) Serial.printf("\n %s\n", LastMessage.c_str());
return;
}
break;
case 'a' :
if (mode != 'r') {
if (iData == waveAmplitude) {
vChange = "No Change";
reGen = false;
} else if (setAmplitude(iData)) {
vChange = (String)waveAmplitude;
} else {
vChange = "Ignored: Out-Of-Range! (1-4)";
reGen = false;
}
} else {
vChange = "Square Wave always 100%";
reGen = false;
}
break;
entries" is printed out to the console (when extended info is enabled).
Search this sketch (for "hunners") for how to increase the amount of available NVRAM,
to around 690 free "entries".
*/
case 'm' :
LastMessage = savedPreset = savePreset(iData);
if (isSerial || eXi) Serial.printf(" %s\n", savedPreset.c_str());
return;
case 'l' :
LastMessage = loadedPreset = loadPreset(iData);
if (isSerial || eXi) Serial.printf(" %s\n", loadedPreset.c_str());
break;
case ',' :
case 'k' :
LastMessage = getNVRAMPresetData(iData);
if (LastMessage == "") LastMessage = "No such preset";
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
return;
Doh!" moment. But I keep both in because
case 'h' :
setTouchMode(chr2);
LastMessage = "Touch handler set to " + makeHumanTouchMode(touchMode);
if (isSerial || eXi) Serial.printf(" %s\n", LastMessage.c_str());
prefs.putChar("h", touchMode);
return;
x") but not total power-down.
This function will not always do what you expect.
Best to test before you deploy.
*/
case '@' :
xMSG = cmdData;
xMSG.trim();
LastMessage = directDACVolts(cmdData.toFloat());
if ((isSerial || eXi) && QCommand == "") Serial.printf(" %s\n", LastMessage.c_str());
return;
}
if (cmd == 'o') {
fChange = true;
frequencySet(cmdData, true);
}
if (reGen) startSignal("Main Loop");
}
if (!iLooping && (fChange || mChange || pChange || bChange || tChange || jChange || vChange || aChange)) {
char buffer[512];
String rState;
if (mode == 'r') rState = recState();
if (mChange) sprintf(buffer, " Generator set to: %s Wave\n", makeHumanMode(mode).c_str());
if (fChange) {
if (didLimit) {
sprintf(buffer + strlen(buffer), "\n*** Frequency out-of-bounds! Auto-reset to: ");
} else {
sprintf(buffer + strlen(buffer), " Frequency set to: ");
}
sprintf(buffer + strlen(buffer), "%s%s", makeHumanFrequency(frequency).c_str(), rState.c_str());
if (didLimit) sprintf(buffer + strlen(buffer), " ***");
sprintf(buffer + strlen(buffer), "\n");
}
if (pChange) sprintf(buffer + strlen(buffer), " Pulse Width set to: %i%s\n", pulse, rState.c_str());
if (tChange) sprintf(buffer + strlen(buffer), " Frequency Step set to: %s\n", makeHumanFrequency(fStep).c_str());
if (jChange) sprintf(buffer + strlen(buffer), " PWM Step set to: %i\n", pStep);
if (vChange != "") sprintf(buffer + strlen(buffer), " Amplitude set to: %s\n", vChange.c_str());
if (aChange) sprintf(buffer + strlen(buffer), " Potentiometer Accuracy set to: %i\n", stepAccuracy);
if (bChange) {
char bpl;
if (PWMResBits != 1) bpl = 's';
sprintf(buffer + strlen(buffer), " PWM Resolution set to: %i bit%c%s", PWMResBits, bpl, rState.c_str());
}
if (loadedPreset != "") sprintf(buffer + strlen(buffer), " Loaded Preset %s\n", loadedPreset.c_str());
if (savedPreset != "") sprintf(buffer + strlen(buffer), " Saved Preset %s\n", savedPreset.c_str());
LastMessage = (String)buffer;
if (isSerial || eXi) Serial.println(buffer);
}
if (isSerial) Serial.println("\n Current Settings:\n");
if (isSerial) Serial.println(getCurrentSettings());
}
if (RemControl) server.handleClient();
if (!iLooping && dailyReboot && millis() > 86400000) {
if (eXi) Serial.println("\n Scheduled Reboot..");
}
}
void setup() {
Serial.setDebugOutput(true);
Serial.begin(115200);
just forgot". Or maybe c) like things SLOW and annoying.
Serial.println("\n *** Welcome to ESP32 Signal Generator v" + version + " ***");
loadDefaultPrefs();
Serial.print(setupPhysicalButtons(false).c_str());
setCPUSpeed(cpuSpeed, true);
if (eXi) printBasicSketchInfo();
if (prefs.getChar("i", -1) == -1) {
prefs.putChar("i", 1);
Serial.println(" First Run: Initialising " + (String)presetMAX + " Preset NameSpaces..");
}
if (checkLimitsOnBoot) checkLimits(frequency);
startSignal("INIT", true);
BeeJeez") that will jump around a lot.
QCommand.reserve(4096);
LastMessage.reserve(4096);
if (RemControl) startServer();
Serial.printf("\n Current Settings:\n\n %s\n", getCurrentSettings().c_str());
Serial.println(listPresets(true));
String readQ = prefs.getString("q", "");
if (readQ != "") {
Serial.printf("\n Discovered Queued Commands: %s\n Processing..\n", readQ.c_str());
QCommand = readQ;
prefs.remove("q");
}
}
;" separator, just like in C/C++/
PHP/etc..This is some slick sh*t!
v7: Now with loops / macros, musical notes and more. Booyah!
Seriously though; who is down here reading this stuff?!
btw, if that's you. I love you!
*/"