Sensor updates

This commit is contained in:
Brian Hrebec 2024-08-20 13:45:22 -05:00
parent f4e95668ce
commit 80c8ccd54b
8 changed files with 251 additions and 179 deletions

View file

@ -221,7 +221,7 @@ int breath() {
int breathCCval, breathCCvalFine;
unsigned int breathCCvalHires;
breathCCvalHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathThrVal, instrument.breathMaxVal, 0, 16383));
breathCCvalHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathBaseline, instrument.breathMaxVal, 0, 16383));
breathCCvalHires = breathCCFilter.input(breathCCvalHires);
breathCCval = (breathCCvalHires >> 7) & 0x007F;
breathCCvalFine = breathCCvalHires & 0x007F;
@ -252,24 +252,9 @@ int breath() {
//**************************************************************
void pitch_bend() {
// handle input from pitchbend touchpads and
// on-pcb variable capacitor for vibrato.
static int oldpb = 0;
void vibrato(int calculatedPBdepth) {
int vibMax;
int vibMaxBite;
int calculatedPBdepth;
byte pbTouched = 0;
int vibRead = 0;
int vibReadBite = 0;
bool halfPitchBendKey = (state.currentPreset->pinkySetting == PBD) && instrument.pinkyKey; // hold pinky key for 1/2 pitchbend value
instrument.quarterToneTrigger = (state.currentPreset->pinkySetting == QTN) && instrument.pinkyKey; // pinky key for a quarter tone down using pitch bend (assuming PB range on synth is set to 2 semitones)
calculatedPBdepth = pbDepthList[state.currentPreset->PBdepth];
if (halfPitchBendKey)
calculatedPBdepth = calculatedPBdepth * 0.5;
vibMax = vibMaxList[state.currentPreset->vibSens - 1];
float calculatedDepth = 0;
if (state.currentPreset->vibratoMode == VibratoMode::VSTART_DOWN) {
@ -278,36 +263,26 @@ void pitch_bend() {
calculatedDepth = (0 - calculatedPBdepth * vibDepth[state.currentPreset->vibratoDepth]);
}
if (ExtraControl::VIBRATO == state.currentPreset->biteControl) { // bite vibrato
vibMaxBite = vibMaxBiteList[state.currentPreset->vibSens - 1];
vibReadBite = instrument.biteSignal;
vibMax = vibMaxList[state.currentPreset->vibSens - 1];
if (vibReadBite > instrument.vibThrBite) {
instrument.vibSignal = (instrument.vibSignal + mapConstrain(
vibReadBite, (instrument.vibZeroBite - vibMaxBite), instrument.vibThrBite, calculatedDepth, 0)
) / 2;
} else if (vibReadBite < instrument.vibThrBiteLo) {
instrument.vibSignal = (instrument.vibSignal + mapConstrain(
vibReadBite, (instrument.vibZeroBite + vibMaxBite), instrument.vibThrBite, calculatedDepth, 0)
) / 2;
} else {
instrument.vibSignal = instrument.vibSignal / 2;
}
if (ExtraControl::VIBRATO == state.currentPreset->biteControl) { // bite vibrato
vibRead = instrument.biteSignal;
} else if (ExtraControl::VIBRATO == state.currentPreset->leverControl) { // lever vibrato
vibRead = instrument.leverSignal;
} else if (ExtraControl::VIBRATO == state.currentPreset->extraControl) { // lever vibrato
vibRead = instrument.extraSignal;
} else if (ExtraControl::VIBRATO == state.currentPreset->pbControl) { // lever vibrato
vibRead = instrument.pbSignal;
} else if (ExtraControl::VIB_BEND == state.currentPreset->pbControl && !instrument.pbActive) { // lever vibrato
vibRead = instrument.pbSignal;
}
if (ExtraControl::VIBRATO == state.currentPreset->leverControl) { // lever vibrato
vibRead = instrument.leverSignal;
if (vibRead > instrument.vibThr) {
instrument.vibSignal = (instrument.vibSignal +
mapConstrain(vibRead, (instrument.vibZero - vibMax), instrument.vibThr, calculatedDepth, 0)
) / 2;
} else if (vibRead < instrument.vibThrLo) {
instrument.vibSignal = (instrument.vibSignal +
mapConstrain(vibRead, (instrument.vibZero + vibMax), instrument.vibThr, calculatedDepth, 0)
) / 2;
} else {
instrument.vibSignal = instrument.vibSignal / 2;
}
if (vibRead < instrument.vibThrLo) {
instrument.vibSignal = (instrument.vibSignal + mapConstrain(
vibRead, (instrument.vibZero + vibMax), instrument.vibThr, calculatedDepth, 0)
) / 2;
} else {
instrument.vibSignal = instrument.vibSignal / 2;
}
switch (state.currentPreset->vibRetn) { // moving baseline
@ -316,40 +291,59 @@ void pitch_bend() {
break;
case 1:
instrument.vibZero = instrument.vibZero * 0.95 + vibRead * 0.05;
instrument.vibZeroBite = instrument.vibZeroBite * 0.95 + vibReadBite * 0.05;
break;
case 2:
instrument.vibZero = instrument.vibZero * 0.9 + vibRead * 0.1;
instrument.vibZeroBite = instrument.vibZeroBite * 0.9 + vibReadBite * 0.1;
break;
case 3:
instrument.vibZero = instrument.vibZero * 0.8 + vibRead * 0.2;
instrument.vibZeroBite = instrument.vibZeroBite * 0.8 + vibReadBite * 0.2;
break;
case 4:
instrument.vibZero = instrument.vibZero * 0.6 + vibRead * 0.4;
instrument.vibZeroBite = instrument.vibZeroBite * 0.6 + vibReadBite * 0.4;
}
instrument.vibThr = instrument.vibZero + state.currentPreset->vibSquelch;
instrument.vibThrLo = instrument.vibZero - state.currentPreset->vibSquelch;
instrument.vibThrBite = instrument.vibZeroBite + state.currentPreset->vibSquelch;
instrument.vibThrBiteLo = instrument.vibZeroBite - state.currentPreset->vibSquelch;
}
void pitch_bend() {
// handle input from pitchbend touchpads and
// on-pcb variable capacitor for vibrato.
static int oldpb = 0;
int calculatedPBdepth;
bool halfPitchBendKey = (state.currentPreset->pinkySetting == PBD) && instrument.pinkyKey; // hold pinky key for 1/2 pitchbend value
instrument.quarterToneTrigger = (state.currentPreset->pinkySetting == QTN) && instrument.pinkyKey; // pinky key for a quarter tone down using pitch bend (assuming PB range on synth is set to 2 semitones)
calculatedPBdepth = pbDepthList[state.currentPreset->PBdepth];
if (halfPitchBendKey)
calculatedPBdepth = calculatedPBdepth * 0.5;
instrument.pbActive = false;
if (ExtraControl::BEND == state.currentPreset->pbControl || ExtraControl::VIB_BEND == state.currentPreset->pbControl) {
// Only activate PB if we're outside the deadzone
if (
(instrument.pbSignal > state.calibration->pbCenterVal + state.calibration->pbDeadzone ||
instrument.pbSignal < state.calibration->pbCenterVal - state.calibration->pbDeadzone)
&& instrument.pbSignal != INT16_MIN) {
instrument.pbActive = true;
}
}
vibrato(calculatedPBdepth);
// PB calculation
int pbPos = mapConstrain(instrument.pbSignal, calibration.pbCenterVal, calibration.pbMaxVal, calculatedPBdepth, 0);
int pbNeg = mapConstrain(instrument.pbSignal, calibration.pbCenterVal, calibration.pbMinVal, calculatedPBdepth, 0);
int pbPos = mapConstrain(instrument.pbSignal, calibration.pbCenterVal + calibration.pbDeadzone, calibration.pbMaxVal, 0, calculatedPBdepth);
int pbNeg = mapConstrain(instrument.pbSignal, calibration.pbMinVal, calibration.pbCenterVal - calibration.pbDeadzone, calculatedPBdepth, 0);
int pbSum = 8193 + pbPos - pbNeg;
int pbDif = abs(pbPos - pbNeg);
if ((pbPos > calibration.pbDeadzone || pbNeg < calibration.pbDeadzone) && state.currentPreset->PBdepth) {
if (instrument.pbActive) {
if (pbDif < 10) {
instrument.pitchBend = 8192;
} else {
instrument.pitchBend = instrument.pitchBend * 0.6 + 0.4 * pbSum;
}
pbTouched = 1;
}
if (!pbTouched) {
} else {
instrument.pitchBend = instrument.pitchBend * 0.6 + 8192 * 0.4; // released, so smooth your way back to zero
if ((instrument.pitchBend > 8187) && (instrument.pitchBend < 8197))
instrument.pitchBend = 8192; // 8192 is 0 pitch bend, don't miss it bc of smoothing
@ -390,9 +384,8 @@ void portamento_() {
if (ExtraControl::GLIDE == state.currentPreset->leverControl) {
// Portamento is controlled with thumb lever
// FIXME: Fix this for new lever signal
if (((3000 - instrument.leverSignal) >= calibration.leverMinVal)) { // if we are enabled and over the threshold, send portamento
portSumCC += mapConstrain((3000 - instrument.leverSignal), calibration.leverMinVal, calibration.leverMaxVal, 0, state.currentPreset->portamentoLimit);
if (instrument.leverSignal >= calibration.leverMinVal) { // if we are enabled and over the threshold, send portamento
portSumCC += mapConstrain(instrument.leverSignal, calibration.leverMinVal, calibration.leverMaxVal, 0, state.currentPreset->portamentoLimit);
}
}
@ -402,7 +395,7 @@ void portamento_() {
//***********************************************************
void sendCC() {
int biteVal = 0;
int biteVal = instrument.biteSignal;
if (ExtraControl::CC == state.currentPreset->biteControl) {
if (instrument.biteSignal >= calibration.biteThrVal) { // we are over the threshold, calculate CC value
biteVal = mapConstrain(instrument.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, 127);
@ -414,10 +407,9 @@ void sendCC() {
instrument.biteVal = biteVal;
}
int extraVal = 0;
int extraVal = instrument.extraVal;
if (ExtraControl::CC == state.currentPreset->extraControl) {
// FIXME: Fix this for new extra signal
if (instrument.extraSignal >= calibration.extraMinVal) { // we are over the threshold, calculate CC value
if (instrument.extraSignal != INT16_MIN) { // we are over the threshold, calculate CC value
extraVal = mapConstrain(instrument.extraSignal, calibration.extraMinVal, calibration.extraMaxVal, 0, 127);
}
@ -427,6 +419,30 @@ void sendCC() {
instrument.extraVal = extraVal;
}
int leverVal = instrument.leverVal;
if (ExtraControl::CC == state.currentPreset->leverControl) {
if (instrument.leverSignal != INT16_MIN) { // we are over the threshold, calculate CC value
leverVal = mapConstrain(instrument.leverSignal, calibration.leverMinVal, calibration.leverMaxVal, 0, 127);
}
if (leverVal != instrument.leverVal) {
midiSendControlChange(state.currentPreset->leverCC, leverVal);
}
instrument.leverVal = leverVal;
}
int pbVal = instrument.pbVal;
if (ExtraControl::CC == state.currentPreset->pbControl) {
if (instrument.pbSignal != INT16_MIN) { // we are over the threshold, calculate CC value
pbVal = mapConstrain(instrument.pbSignal, calibration.pbMinVal, calibration.pbMaxVal, 0, 127);
}
if (pbVal != instrument.pbVal) {
midiSendControlChange(state.currentPreset->pbCC, pbVal);
}
instrument.pbVal = pbVal;
}
if (!inMenu()) {
for (int i = 0; i < 4; i++) {
byte val = constrain((int)state.instrument->knobVals[i] + readKnob(i), 0, 127);
@ -456,31 +472,34 @@ void sendCC() {
// Re-zero floating calibration values
void rezero() {
instrument.vibZero = 0;
instrument.vibThr = instrument.vibZero + state.currentPreset->vibSquelch;
instrument.vibThrLo = instrument.vibZero - state.currentPreset->vibSquelch;
instrument.vibThrBite = instrument.vibZeroBite + state.currentPreset->vibSquelch;
instrument.vibThrBiteLo = instrument.vibZeroBite - state.currentPreset->vibSquelch;
instrument.breathThrVal = instrument.breathZero + calibration.breathThrValOffset;
instrument.breathBaseline = instrument.breathZero + calibration.breathThrValOffset;
instrument.breathThrOffVal = instrument.breathZero + calibration.breathThrValOffset / 2;
instrument.breathMaxVal = instrument.breathThrVal + calibration.breathMaxValOffset;
instrument.breathAltThrVal = instrument.breathAltZero + calibration.breathAltThrValOffset;
instrument.breathAltMaxVal = instrument.breathAltThrVal + calibration.breathAltMaxValOffset;
instrument.breathAltZeroOffset = instrument.breathZero - instrument.breathAltZero;
}
void autoCal() {
instrument.vibZero = instrument.vibZeroBite = 0;
long int bZero = 0;
long int bAltZero = 0;
long int bLeverTouchZero = 0, bExtraTouchZero = 0, bPBTouchZero = 0;
for (int i = 1; i <= CALIBRATE_SAMPLE_COUNT; ++i) {
bZero += readPressure();
bAltZero += readAltPressure();
instrument.vibZeroBite += readTouchRoller(bitePin);
bLeverTouchZero += readRawSlider(Slider::SLIDER_LEVER);
bExtraTouchZero += readRawSlider(Slider::SLIDER_EXTRA);
bPBTouchZero += readRawSlider(Slider::SLIDER_PITCH_BEND);
}
instrument.breathZero = bZero / CALIBRATE_SAMPLE_COUNT;
instrument.breathAltZero = bAltZero / CALIBRATE_SAMPLE_COUNT;
instrument.vibZero /= CALIBRATE_SAMPLE_COUNT;
instrument.vibZeroBite /= CALIBRATE_SAMPLE_COUNT;
instrument.breathAltZero = (bAltZero / CALIBRATE_SAMPLE_COUNT);
instrument.sliderPBThr = bPBTouchZero /= CALIBRATE_SAMPLE_COUNT;
instrument.sliderExtraThr = bExtraTouchZero /= CALIBRATE_SAMPLE_COUNT;
instrument.sliderLeverThr = bLeverTouchZero /= CALIBRATE_SAMPLE_COUNT;
rezero();
}
@ -500,26 +519,6 @@ void fullAutoCal() {
calibration.biteThrVal = constrain(calRead + 100, BITE_LO_LIMIT, BITE_HI_LIMIT);
calibration.biteMaxVal = constrain(calRead + 300, BITE_LO_LIMIT, BITE_HI_LIMIT);
/*
// Lever
calRead = readTouchRoller(leverPin);
calibration.leverThrVal = constrain(calRead + 100, LEVER_LO_LIMIT, LEVER_HI_LIMIT);
calibration.leverMaxVal = constrain(calRead + 300, LEVER_LO_LIMIT, LEVER_HI_LIMIT);
// Extra
calRead = readTouchRoller(extraPin);
calibration.extraThrVal = constrain(calRead + 100, EXTRA_LO_LIMIT, EXTRA_HI_LIMIT);
calibration.extraMaxVal = constrain(calRead + 300, EXTRA_LO_LIMIT, EXTRA_HI_LIMIT);
// PB
calRead = readTouchRoller(pbDnPin);
calibration.pbDnThrVal = constrain(calRead + 100, BITE_LO_LIMIT, BITE_HI_LIMIT);
calibration.pbDnMaxVal = constrain(calRead + 300, BITE_LO_LIMIT, BITE_HI_LIMIT);
calRead = readTouchRoller(pbUpPin);
calibration.pbUpThrVal = constrain(calRead + 100, BITE_LO_LIMIT, BITE_HI_LIMIT);
calibration.pbUpMaxVal = constrain(calRead + 300, BITE_LO_LIMIT, BITE_HI_LIMIT);
*/
// Touch sensors
calRead = CTOUCH_HI_LIMIT;
for (byte i = 0; i < 12; i++) {
@ -769,15 +768,17 @@ void readSwitches() {
void noteOn(int fingeredNote, int pressureSensor, int initial_breath_value) {
// Yes, so calculate MIDI note and velocity, then send a note on event
// We should be at tonguing peak, so set velocity based on current pressureSensor value unless fixed velocity is set
instrument.breathSignal = constrain(max(pressureSensor, initial_breath_value), instrument.breathThrVal, instrument.breathMaxVal);
instrument.breathSignal = constrain(max(pressureSensor, initial_breath_value), instrument.breathBaseline, instrument.breathMaxVal);
byte velocitySend;
if (!state.currentPreset->fixedVelocity) {
unsigned int breathValHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathThrVal, instrument.breathMaxVal, 0, 16383));
unsigned int breathValHires = breathCurve(mapConstrain(instrument.breathSignal, instrument.breathBaseline, instrument.breathMaxVal, 0, 16383));
velocitySend = (breathValHires >> 7) & 0x007F;
velocitySend = constrain(velocitySend + velocitySend * .1 * state.currentPreset->velBias, 1, 127);
} else {
velocitySend = state.currentPreset->fixedVelocity;
}
Serial.print(">velocity:");
Serial.println(velocitySend);
midiSendNoteOn(fingeredNote, velocitySend); // send Note Off message
}
@ -844,9 +845,9 @@ void initState() {
*/
void readUtil() {
instrument.biteSignal = readTouchRoller(bitePin);
instrument.pbSignal = readSlider(SLIDER_PITCH_BEND);
instrument.leverSignal = readSlider(SLIDER_LEVER);
instrument.extraSignal = readSlider(SLIDER_EXTRA);
instrument.pbSignal = readSlider(Slider::SLIDER_PITCH_BEND, instrument.sliderPBThr);
instrument.leverSignal = readSlider(Slider::SLIDER_LEVER, instrument.sliderLeverThr);
instrument.extraSignal = readSlider(Slider::SLIDER_EXTRA, instrument.sliderExtraThr);
}
/**
@ -866,19 +867,16 @@ void handleCCs() {
}
if (currentTime - ccSendTime > CC_INTERVAL_PRIMARY) {
// deal with Pitch Bend, Modulation, etc.
readUtil();
pitch_bend();
sendCC();
checkICM(state);
ccSendTime = currentTime;
}
if (currentTime - ccSendTime2 > CC_INTERVAL_PORT) {
readUtil();
portamento_();
ccSendTime2 = currentTime;
}
if (currentTime - ccSendTime3 > CC_INTERVAL_OTHER) {
readUtil();
updateSensorLEDs(*state.instrument);
ccSendTime3 = currentTime;
}
@ -889,32 +887,36 @@ void handleCCs() {
*/
void readBreath() {
int16_t breathSignal = constrain(readPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
int16_t breathAltSignal = constrain(readAltPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
// Get the pressure sensor reading
int16_t breathSignal = constrain(readPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT);
int16_t breathAltSignal = constrain(readAltPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT) + instrument.breathAltZeroOffset;
int16_t spikeSignal = constrain(readSpikePressure(), -SPIKE_HI_LIMIT, SPIKE_HI_LIMIT);
instrument.breathMovingThrVal = constrain(
breathBaselineFilter.input((breathSignal + instrument.breathZero) / 2),
instrument.breathThrVal,
instrument.breathMaxVal
);
int16_t diffSignal = breathAltSignal - breathSignal;
int16_t halfOffset = state.calibration->breathThrValOffset / 2;
if (state.currentPreset->breathMode == BREATH_ACC || state.currentPreset->breathMode == BREATH_ACC_AT) {
int delta = breathSignal - instrument.breathZero;
if (abs(delta) > state.calibration->breathAltThrValOffset) {
if (abs(delta) > state.calibration->breathThrValOffset) {
instrument.breathSignal = constrain(instrument.breathSignal + delta / 15, instrument.breathZero, instrument.breathMaxVal);
}
} else {
instrument.breathSignal = breathSignal + (spikeSignal > 0 ? spikeSignal * state.currentPreset->spikeOnFactor : spikeSignal * state.currentPreset->spikeOffFactor);
instrument.breathSignal = breathSignal + diffSignal + (spikeSignal > 0 ? spikeSignal * state.currentPreset->spikeOnFactor : spikeSignal * state.currentPreset->spikeOffFactor);
}
instrument.breathAltSignal = breathAltSignal;
instrument.breathMovingThrVal = constrain(
breathBaselineFilter.input(instrument.breathBaseline + (instrument.breathSignal - instrument.breathBaseline) * .75),
instrument.breathZero + halfOffset,
instrument.breathMaxVal - halfOffset
);
instrument.breathThrVal = instrument.breathMovingThrVal + halfOffset;
instrument.breathThrOffVal = instrument.breathMovingThrVal - halfOffset;
if (instrument.mode == MODE_DEBUG) {
Serial.print(">breath:");
Serial.println(breathSignal);
Serial.print(">breathAlt:");
Serial.println(breathAltSignal);
Serial.print(">Diff:");
Serial.println(breathSignal - breathAltSignal);
Serial.println(diffSignal);
Serial.print(">breathMovingThr:");
Serial.println(instrument.breathMovingThrVal);
Serial.print(">note:");
@ -923,6 +925,12 @@ void readBreath() {
Serial.println(spikeSignal);
Serial.print(">combo:");
Serial.println(instrument.breathSignal);
Serial.print(">zero:");
Serial.println(instrument.breathZero);
Serial.print(">thr:");
Serial.println(instrument.breathThrVal);
Serial.print(">off:");
Serial.println(instrument.breathThrOffVal);
}
}
@ -934,7 +942,7 @@ void runStateMachine() {
static int initial_breath_value = 0; // The breath value at the time we observed the transition
if (state.mainState == NOTE_OFF) {
handleOffStateActions();
if (instrument.breathSignal > instrument.breathMovingThrVal && state.mainState == NOTE_OFF) {
if (instrument.breathSignal > instrument.breathThrVal && state.mainState == NOTE_OFF) {
// Value has risen above threshold. Move to the RISE_WAIT
// state. Record time and initial breath value.
breath_on_time = millis();
@ -945,21 +953,21 @@ void runStateMachine() {
if ((instrument.breathSignal > instrument.breathMovingThrVal)) {
// Has enough time passed for us to collect our second sample?
if ((millis() - breath_on_time > state.currentPreset->velSmpDl) || (0 == state.currentPreset->velSmpDl) || state.currentPreset->fixedVelocity) {
noteOn(instrument.fingeredNote, instrument.breathSignal, initial_breath_value);
if (instrument.fingeredNote != instrument.fingeredNote2) {
noteOn(instrument.fingeredNote2, instrument.breathSignal, initial_breath_value);
}
breath(); // send breath data
state.mainState = NOTE_ON;
instrument.activeNote = instrument.fingeredNote;
instrument.activeNote2 = instrument.fingeredNote2;
noteOn(instrument.fingeredNote, instrument.breathSignal, initial_breath_value);
if (instrument.fingeredNote != instrument.fingeredNote2) {
noteOn(instrument.fingeredNote2, instrument.breathSignal, initial_breath_value);
}
breath(); // send breath data
state.mainState = NOTE_ON;
instrument.activeNote = instrument.fingeredNote;
instrument.activeNote2 = instrument.fingeredNote2;
}
} else {
// Value fell below threshold before velocity sample delay time passed. Return to NOTE_OFF state
state.mainState = NOTE_OFF;
}
} else if (state.mainState == NOTE_ON) {
if (instrument.breathSignal < instrument.breathMovingThrVal) {
if (instrument.breathSignal < instrument.breathThrOffVal) {
// Value has fallen below threshold - turn the note off
midiSendNoteOff(instrument.activeNote); // send Note Off message
if (instrument.activeNote != instrument.activeNote2) {
@ -1019,12 +1027,8 @@ void setup() {
//_______________________________________________________________________________________________ MAIN LOOP
void loop() {
static unsigned long lastUpdate = millis();
static unsigned long pixelUpdateTime = 0;
static const unsigned long pixelUpdateInterval = 80;
unsigned long time = millis();
unsigned long deltaTime = time - lastUpdate;
lastUpdate = time;
// If in config mgmt loop, do that and nothing else
if (instrument.mode == MODE_CONFIG) {
@ -1039,6 +1043,7 @@ void loop() {
readBreath();
readSwitches();
readUtil();
runStateMachine();
handleCCs();