// --- Liver Perfusion System (HOPE & NMP Modes) ---
// STM32 Central Controller - Data Logging Version (30 seconds)
#define MODE_SWITCH_PIN PC13
#define BUZZER_PIN PA5
#define RED_LED_PIN PA4
#define GREEN_LED_PIN PB12
#define SENS_PV_FLOW_1 PA0
#define SENS_PV_FLOW_2 PA1
#define SENS_HA_FLOW PA2
#define SENS_EXTRA_FLOW PA3
#define SENS_PV_PRESS PB0
#define SENS_HA_PRESS PB1
// --- NMP TARGETS ---
const float NMP_PVF_MIN = 1000.0, NMP_PVF_MAX = 1200.0;
const float NMP_HAF_MIN = 250.0, NMP_HAF_MAX = 350.0;
const float NMP_PVP_MIN = 8.0, NMP_PVP_MAX = 12.0;
const float NMP_HAP_MIN = 50.0, NMP_HAP_MAX = 70.0;
// --- HOPE TARGETS ---
const float HOPE_PVF_MIN = 100.0, HOPE_PVF_MAX = 200.0;
const float HOPE_HAF_MAX = 20.0;
const float HOPE_PVP_MAX = 3.0;
const float HOPE_HAP_MAX = 5.0;
// --- DATA LOGGING VARIABLES (30 Seconds at 4Hz = 120 samples) ---
const int MAX_SAMPLES = 120;
int sampleCount = 0;
// Arrays to store history in RAM (~2.1 KB required, easily fits in STM32)
bool modeHist[MAX_SAMPLES];
float pvFlowHist[MAX_SAMPLES];
float haFlowHist[MAX_SAMPLES];
float pvPressHist[MAX_SAMPLES];
float haPressHist[MAX_SAMPLES];
bool alarmHist[MAX_SAMPLES];
void setup() {
Serial.begin(115200);
pinMode(MODE_SWITCH_PIN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RED_LED_PIN, OUTPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
delay(100); // Give system time to boot
Serial.println("Starting 30-Second Simulation...");
Serial.println("Adjust your potentiometers/sensors now!");
}
void loop() {
if (sampleCount < MAX_SAMPLES) {
// 1. READ MODE SWITCH
bool isNMP = digitalRead(MODE_SWITCH_PIN);
// 2. READ & CONVERT SENSORS
float pvFlow1 = mapFloat(analogRead(SENS_PV_FLOW_1), 0, 4095, 0, 1500);
float haFlow = mapFloat(analogRead(SENS_HA_FLOW), 0, 4095, 0, 500);
float pvPress = mapFloat(analogRead(SENS_PV_PRESS), 0, 4095, 0, 20);
float haPress = mapFloat(analogRead(SENS_HA_PRESS), 0, 4095, 0, 100);
// 3. EVALUATE BOUNDS
bool alarm = false;
if (isNMP) {
if (pvFlow1 < NMP_PVF_MIN || pvFlow1 > NMP_PVF_MAX) alarm = true;
if (haFlow < NMP_HAF_MIN || haFlow > NMP_HAF_MAX) alarm = true;
if (pvPress < NMP_PVP_MIN || pvPress > NMP_PVP_MAX) alarm = true;
if (haPress < NMP_HAP_MIN || haPress > NMP_HAP_MAX) alarm = true;
} else {
if (pvFlow1 < HOPE_PVF_MIN || pvFlow1 > HOPE_PVF_MAX) alarm = true;
if (haFlow > HOPE_HAF_MAX) alarm = true;
if (pvPress > HOPE_PVP_MAX) alarm = true;
if (haPress > HOPE_HAP_MAX) alarm = true;
}
// 4. TRIGGER PHYSICAL ALARMS
if (alarm) {
digitalWrite(GREEN_LED_PIN, LOW);
digitalWrite(RED_LED_PIN, HIGH);
tone(BUZZER_PIN, 1500);
} else {
digitalWrite(GREEN_LED_PIN, HIGH);
digitalWrite(RED_LED_PIN, LOW);
noTone(BUZZER_PIN);
}
// 5. STORE DATA IN ARRAYS
modeHist[sampleCount] = isNMP;
pvFlowHist[sampleCount] = pvFlow1;
haFlowHist[sampleCount] = haFlow;
pvPressHist[sampleCount] = pvPress;
haPressHist[sampleCount] = haPress;
alarmHist[sampleCount] = alarm;
// Show live progress so the user knows it's working
Serial.print("Recording Sample: ");
Serial.print(sampleCount + 1);
Serial.println(" / 120");
sampleCount++;
delay(250); // 4Hz refresh rate
} else if (sampleCount == MAX_SAMPLES) {
// 6. SIMULATION COMPLETE - DUMP DATA
noTone(BUZZER_PIN); // Turn off buzzer during dump
printJSONData();
printCSVData();
Serial.println("\n\n--- SIMULATION COMPLETE ---");
Serial.println("You can now highlight the JSON or CSV text above, copy it,");
Serial.println("and save it to a file (e.g. data.json or data.csv) on your computer.");
sampleCount++; // Increment once more to stop the loop from repeating the print
}
// If sampleCount > MAX_SAMPLES, do nothing (System halts)
}
// --- HELPER FUNCTIONS ---
float mapFloat(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void printJSONData() {
Serial.println("\n\n=============== BEGIN JSON FILE ===============");
Serial.println("[");
for (int i = 0; i < MAX_SAMPLES; i++) {
Serial.print(" {\"time_sec\":"); Serial.print(i * 0.25, 2);
Serial.print(", \"mode\":\""); Serial.print(modeHist[i] ? "NMP" : "HOPE");
Serial.print("\", \"PV_Flow\":"); Serial.print(pvFlowHist[i], 1);
Serial.print(", \"HA_Flow\":"); Serial.print(haFlowHist[i], 1);
Serial.print(", \"PV_Press\":"); Serial.print(pvPressHist[i], 1);
Serial.print(", \"HA_Press\":"); Serial.print(haPressHist[i], 1);
Serial.print(", \"Alarm\":"); Serial.print(alarmHist[i] ? "true" : "false");
Serial.print("}");
if (i < MAX_SAMPLES - 1) {
Serial.println(","); // Add comma for all but the last item
} else {
Serial.println(); // No comma for the last item
}
}
Serial.println("]");
Serial.println("================ END JSON FILE ================");
}
void printCSVData() {
Serial.println("\n\n=============== BEGIN CSV FILE ===============");
Serial.println("Time(s),Mode,PV_Flow,HA_Flow,PV_Press,HA_Press,Alarm");
for (int i = 0; i < MAX_SAMPLES; i++) {
Serial.print(i * 0.25, 2); Serial.print(",");
Serial.print(modeHist[i] ? "NMP" : "HOPE"); Serial.print(",");
Serial.print(pvFlowHist[i], 1); Serial.print(",");
Serial.print(haFlowHist[i], 1); Serial.print(",");
Serial.print(pvPressHist[i], 1); Serial.print(",");
Serial.print(haPressHist[i], 1); Serial.print(",");
Serial.println(alarmHist[i] ? "1" : "0");
}
Serial.println("================ END CSV FILE ================");
}--- INPUTS & SENSORS ---
STM32 CENTRAL CONTROLLER
--- OUTPUTS & DISPLAYS ---
HOPE / NMP Switch
Flow 1 (PV)
Flow 2 (PV)
Flow 3 (HA)
Flow 4
Press 1 (PV)
Press 2 (HA)
ESP32 (Wi-Fi Data Bridge)