#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <AccelStepper.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Keypad Pin Definitions
#define KEYPAD_C1 4
#define KEYPAD_C2 5
#define KEYPAD_C3 6
#define KEYPAD_C4 7
#define KEYPAD_C5 15
#define KEYPAD_C6 16
#define KEYPAD_R1 17
#define KEYPAD_R2 18
#define KEYPAD_R3 8
#define KEYPAD_R4 9
// I2C pins for ESP32-S3
#define I2C_SDA_PIN 1
#define I2C_SCL_PIN 2
// Other Pin Definitions
#define LID_HEATER 11
#define BTS_RPWM 12
#define BTS_LPWM 13
#define BTS_R_EN 14
#define BTS_L_EN 21
#define BUZZER 38
#define LID_SENSOR 3 // analog input for lid temperature (DS18B20)
#define BLOCK_SENSOR 10 // analog input for block temperature
#define HEATSINK_SENSOR 47
#define HEATSINK_FAN 48
OneWire oneWire(LID_SENSOR);
DallasTemperature lidSensor(&oneWire);
// LCD
#define LCD_ADDRESS 0x27
#define LCD_COLS 20
#define LCD_ROWS 4
LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLS, LCD_ROWS);
const int TOTAL_PROTOCOLS = 50;
struct PCRProtocol
{
String name;
byte steps;
float temp[10];
int timeSec[10];
byte cycleStart;
byte cycleEnd;
byte cycles;
byte lidTemp;
};
PCRProtocol savedProtocol[50];
String protocolName[TOTAL_PROTOCOLS] =
{
"HCV PCR",
"HBV PCR",
"HIV PCR",
"COVID-19",
"Dengue PCR",
"CMV PCR",
"EBV PCR",
"HSV PCR",
"Influenza A/B",
"Multiplex PCR",
"User 1",
"User 2",
"User 3",
"User 4",
"User 5",
"User 6",
"User 7",
"User 8",
"User 9",
"User 10",
"User 11",
"User 12",
"User 13",
"User 14",
"User 15",
"User 16",
"User 17",
"User 18",
"User 19",
"User 20",
"User 21",
"User 22",
"User 23",
"User 24",
"User 25",
"User 26",
"User 27",
"User 28",
"User 29",
"User 30",
"User 31",
"User 32",
"User 33",
"User 34",
"User 35",
"User 36",
"User 37",
"User 38",
"User 39",
"User 40"
};
int protocolIndex = 0;
int menuPosition = 0;
const int MENU_ITEMS = 9;
const char* menuOptions[] = {"Run Protocol", "Saved Protocols", "New Protocol", "View Protocol", "Run save Protocol","Edit Protocol", "Delete Protocol", "Setting", "Calibration"};
// Function prototypes
void setup();
void loop();
void menu();
void keypadInit();
char readKeypad();
void updateMenuDisplay();
void handleKeypadInput();
void executeMenuAction(int position);
void runProtocol();
void savedProtocols();
void newProtocol();
void editProtocol();
void settings();
void calibration();
void deleteProtocol();
void processKey(char key);
void loadFactoryProtocols();
void runSavedProtocol(int index);
void displayStartupScreen();
float readFloatFromKeypad();
int readIntFromKeypad(const char* prompt);
float readBlockTemperature();
float readLidTemperature();
void regulateLid(float target);
void test();
// ========== SETUP ==========
void setup() {
Serial.begin(115200);
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
Wire.setClock(100000);
lcd.init();
lcd.backlight();
lcd.clear();
displayStartupScreen();
keypadInit();
pinMode(LID_HEATER, OUTPUT);
pinMode(BTS_RPWM, OUTPUT);
pinMode(BTS_LPWM, OUTPUT);
pinMode(BTS_R_EN, OUTPUT);
pinMode(BTS_L_EN, OUTPUT);
pinMode(BUZZER, OUTPUT);
lidSensor.begin();
lidSensor.setWaitForConversion(false);
pinMode(BLOCK_SENSOR, INPUT);
pinMode(HEATSINK_FAN, OUTPUT);
digitalWrite(BTS_R_EN, HIGH);
digitalWrite(BTS_L_EN, HIGH);
digitalWrite(BUZZER, LOW);
digitalWrite(LID_HEATER, LOW);
digitalWrite(HEATSINK_FAN, LOW);
loadFactoryProtocols();
menuPosition = 0;
menu();
}
// ========== LOOP ==========
void loop() {
handleKeypadInput();
}
// ========== DISPLAY AND KEYPAD FUNCTIONS ==========
void displayStartupScreen() {
lcd.setCursor(3, 0);
lcd.print("THERMAL CYCLER");
lcd.setCursor(9, 1);
lcd.print("BY");
lcd.setCursor(1, 2);
lcd.print("VITANIX DIAGNOSTIC");
delay(1000);
lcd.setCursor(3, 3);
lcd.print("PH:");
delay(20);
char phNumber[] = "03009413429";
for(int i = 0; i < 11; i++) {
lcd.setCursor(6 + i, 3);
lcd.print(phNumber[i]);
delay(20);
}
delay(500);
lcd.clear();
}
void keypadInit() {
pinMode(KEYPAD_C1, INPUT_PULLUP);
pinMode(KEYPAD_C2, INPUT_PULLUP);
pinMode(KEYPAD_C3, INPUT_PULLUP);
pinMode(KEYPAD_C4, INPUT_PULLUP);
pinMode(KEYPAD_C5, INPUT_PULLUP);
pinMode(KEYPAD_C6, INPUT_PULLUP);
pinMode(KEYPAD_R1, OUTPUT);
pinMode(KEYPAD_R2, OUTPUT);
pinMode(KEYPAD_R3, OUTPUT);
pinMode(KEYPAD_R4, OUTPUT);
digitalWrite(KEYPAD_R1, HIGH);
digitalWrite(KEYPAD_R2, HIGH);
digitalWrite(KEYPAD_R3, HIGH);
digitalWrite(KEYPAD_R4, HIGH);
}
// Updated keymap for Eppendorf Mastercycler Personal layout
char readKeypad() {
const char keymap[4][6] = {
{'O','X','E','7','8','9'},
{'U','L','N','4','5','6'},
{'D','R','1','2','3','\0'},
{'S','I','V','0','.','+'}
};
int colPins[6] = {KEYPAD_C1, KEYPAD_C2, KEYPAD_C3, KEYPAD_C4, KEYPAD_C5, KEYPAD_C6};
int rowPins[4] = {KEYPAD_R1, KEYPAD_R2, KEYPAD_R3, KEYPAD_R4};
for (int row = 0; row < 4; row++) {
for (int r = 0; r < 4; r++) digitalWrite(rowPins[r], HIGH);
digitalWrite(rowPins[row], LOW);
for (int col = 0; col < 6; col++) {
if (digitalRead(colPins[col]) == LOW) {
delay(20);
while (digitalRead(colPins[col]) == LOW);
return keymap[row][col];
}
}
}
return 0;
}
void handleKeypadInput() {
char key = readKeypad();
if(key != 0) {
processKey(key);
delay(50);
}
}
void processKey(char key) {
digitalWrite(BUZZER, HIGH);
delay(30);
digitalWrite(BUZZER, LOW);
switch(key) {
case 'U':
if(menuPosition > 0) { menuPosition--; updateMenuDisplay(); }
break;
case 'D':
if(menuPosition < MENU_ITEMS-1) { menuPosition++; updateMenuDisplay(); }
break;
case 'N':
executeMenuAction(menuPosition);
break;
case 'E':
menu();
break;
case 'V': // Start protocol (shortcut)
runProtocol();
break;
// Optional: additional keys for future expansion
case 'X': // Delete/backspace is handled inside input routines
case 'L':
case 'R':
case 'O':
case 'I':
case 'S':
default:
break;
}
}
// ========== SCROLLING MENU DISPLAY ==========
void updateMenuDisplay() {
const int visibleRows = LCD_ROWS - 1;
static int topIndex = 0;
if (menuPosition < topIndex) {
topIndex = menuPosition;
} else if (menuPosition >= topIndex + visibleRows) {
topIndex = menuPosition - visibleRows + 1;
}
if (topIndex < 0) topIndex = 0;
if (topIndex > MENU_ITEMS - visibleRows) topIndex = MENU_ITEMS - visibleRows;
if (topIndex < 0) topIndex = 0;
lcd.clear();
for (int i = 0; i < visibleRows; i++) {
int index = topIndex + i;
lcd.setCursor(0, i);
if (index < MENU_ITEMS) {
if (index == menuPosition) {
lcd.print(">");
lcd.print(menuOptions[index]);
} else {
lcd.print(" ");
lcd.print(menuOptions[index]);
}
for (int j = strlen(menuOptions[index]) + 1; j < LCD_COLS; j++) {
lcd.print(" ");
}
} else {
lcd.print(" ");
}
}
lcd.setCursor(0, LCD_ROWS - 1);
lcd.print("U/D:Nav N:Sel E:Exit");
}
void menu() {
menuPosition = 0;
updateMenuDisplay();
}
void executeMenuAction(int position) {
switch(position) {
case 0: runProtocol(); break;
case 1: savedProtocols(); break;
case 2: newProtocol(); break;
case 3: editProtocol(); break;
default: menu(); break;
}
}
// ========== SENSOR READING FUNCTIONS ==========
float readBlockTemperature() {
int raw = analogRead(BLOCK_SENSOR);
float voltage = raw * (3.3 / 4095.0);
float temp = voltage * 30.0;
if(temp < 0) temp = 0;
if(temp > 100) temp = 100;
return temp;
}
float readLidTemperature()
{
static bool firstRead = true;
if(firstRead)
{
lidSensor.requestTemperatures();
firstRead = false;
}
float temp = lidSensor.getTempCByIndex(0);
lidSensor.requestTemperatures();
if(temp == DEVICE_DISCONNECTED_C)
return -127;
return temp;
}
void regulateLid(float target) {
static float current = 0;
current = readLidTemperature();
if(current == -127) {
digitalWrite(LID_HEATER, LOW);
return;
}
if(current < target - 1.5) digitalWrite(LID_HEATER, HIGH);
else if(current > target + 0.5) digitalWrite(LID_HEATER, LOW);
}
// ========== HELPER: READ FLOAT WITH BACKSPACE ==========
float readFloatFromKeypad() {
char buffer[10] = "";
int pos = 0;
bool hasDecimal = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Enter Block Temp :");
lcd.setCursor(0, 1);
lcd.print("> ");
while (true) {
char key = readKeypad();
if (key == 0) continue;
if ((key >= '0' && key <= '9') || (key == '.' && !hasDecimal)) {
if (pos < 9) {
buffer[pos++] = key;
if (key == '.') hasDecimal = true;
lcd.setCursor(2, 1);
lcd.print(buffer);
lcd.print(" ");
}
digitalWrite(BUZZER, HIGH); delay(30); digitalWrite(BUZZER, LOW);
} else if (key == 'X') { // backspace
if (pos > 0) {
pos--;
if (buffer[pos] == '.') hasDecimal = false;
buffer[pos] = '\0';
lcd.setCursor(2, 1);
lcd.print(buffer);
lcd.print(" ");
}
} else if (key == 'N') {
if (pos > 0) {
buffer[pos] = '\0';
float val = atof(buffer);
lcd.setCursor(2, 1);
lcd.print(" ");
return val;
}
} else if (key == 'E') {
return -1.0;
}
}
}
// ========== HELPER: READ INTEGER WITH BACKSPACE ==========
int readIntFromKeypad(const char* prompt) {
char buffer[5] = "";
int pos = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(prompt);
lcd.setCursor(0, 1);
lcd.print("> ");
while (true) {
char key = readKeypad();
if (key == 0) continue;
if (key >= '0' && key <= '9') {
if (pos < 4) {
buffer[pos++] = key;
lcd.setCursor(2, 1);
lcd.print(buffer);
lcd.print(" ");
}
digitalWrite(BUZZER, HIGH); delay(30); digitalWrite(BUZZER, LOW);
} else if (key == 'X') { // backspace
if (pos > 0) {
pos--;
buffer[pos] = '\0';
lcd.setCursor(2, 1);
lcd.print(buffer);
lcd.print(" ");
}
} else if (key == 'N') {
if (pos > 0) {
buffer[pos] = '\0';
int val = atoi(buffer);
lcd.setCursor(2, 1);
lcd.print(" ");
return val;
}
} else if (key == 'E') {
return -1;
}
}
}
// ========== RUN PROTOCOL (fully updated) ==========
void runProtocol() {
// ----- Step 1: Number of Steps -----
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Protocol");
lcd.setCursor(12, 0);
lcd.print("L:105 C");
lcd.setCursor(0, 1);
lcd.print("Temp Steps(1-99):");
String input = "";
int numSteps = 0;
while (true) {
char key = readKeypad();
if (key >= '0' && key <= '9') {
if (input.length() < 2) {
input += key;
lcd.setCursor(18, 1);
lcd.print(" ");
lcd.setCursor(18, 1);
lcd.print(input);
digitalWrite(BUZZER, HIGH); delay(30); digitalWrite(BUZZER, LOW);
}
}
if (key == 'X') { // backspace
if (input.length() > 0) {
input.remove(input.length()-1);
lcd.setCursor(18, 1);
lcd.print(" ");
lcd.setCursor(18, 1);
lcd.print(input);
}
}
if (key == 'N') {
if (input.length() > 0) {
numSteps = input.toInt();
if(numSteps >= 1 && numSteps <= 99) break;
lcd.setCursor(0, 3);
lcd.print("Enter 1-99 ");
}
}
if (key == 'E') { menu(); return; }
}
// ----- Step 2: Each Step (Temp and Time in seconds) -----
float temperatures[100];
int times[100];
for (int i = 0; i < numSteps; i++) {
// Temperature
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Protocol");
lcd.setCursor(12, 0);
lcd.print("L:105C");
lcd.setCursor(0, 1);
lcd.print("Step ");
lcd.print(i + 1);
lcd.print("/");
lcd.print(numSteps);
lcd.print(" Temp:");
if (i > 0) {
lcd.setCursor(0, 2);
lcd.print("P:");
lcd.print(temperatures[i-1], 1);
lcd.print("C ");
lcd.print(times[i-1]);
lcd.print("s");
} else {
lcd.setCursor(0, 2);
lcd.print("New Protocol ");
}
lcd.setCursor(0, 3);
lcd.print(" ");
lcd.setCursor(13, 1);
float temp = readFloatFromKeypad();
if (temp < 0) { menu(); return; }
temperatures[i] = temp;
// Time (seconds)
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Protocol");
lcd.setCursor(12, 0);
lcd.print("L:105C");
lcd.setCursor(0, 1);
lcd.print("Step ");
lcd.print(i + 1);
lcd.print("/");
lcd.print(numSteps);
lcd.print(" Time (s):");
if (i > 0) {
lcd.setCursor(0, 2);
lcd.print("P:");
lcd.print(temperatures[i-1], 1);
lcd.print("C ");
lcd.print(times[i-1]);
lcd.print("s");
} else {
lcd.setCursor(0, 2);
lcd.print("New Protocol ");
}
lcd.setCursor(0, 3);
lcd.print(" ");
lcd.setCursor(13, 1);
int t = readIntFromKeypad("Enter time (sec):");
if (t < 0) { menu(); return; }
times[i] = t;
// Confirm
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Step ");
lcd.print(i + 1);
lcd.print(" Set:");
lcd.setCursor(0, 1);
lcd.print("Temp:");
lcd.print(temperatures[i], 1);
lcd.print("C ");
lcd.print("Time:");
lcd.print(times[i]);
lcd.print("s");
if (i < numSteps - 1) {
lcd.setCursor(0, 3);
lcd.print("Press N for next");
} else {
lcd.setCursor(0, 3);
lcd.print("All steps set! ");
}
while (true) {
char key = readKeypad();
if (key == 'N') break;
if (key == 'E') { menu(); return; }
}
}
// ----- Step 3: Cycle range and cycles -----
int cycleStart, cycleEnd, cyclesCount = 0;
// Start step
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Cycle from step:");
lcd.setCursor(0, 1);
lcd.print("(1..");
lcd.print(numSteps);
lcd.print(")");
cycleStart = readIntFromKeypad("Repeat from cycle");
if (cycleStart < 1 || cycleStart > numSteps) { menu(); return; }
// End step
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Cycle to step:");
lcd.setCursor(0, 1);
lcd.print("(");
lcd.print(cycleStart);
lcd.print("..");
lcd.print(numSteps);
lcd.print(")");
cycleEnd = readIntFromKeypad("End step:");
if (cycleEnd < cycleStart || cycleEnd > numSteps) { menu(); return; }
// Number of cycles
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Cycles (2-99):");
lcd.setCursor(0, 1);
lcd.print("Step ");
lcd.print(cycleStart);
lcd.print("-");
lcd.print(cycleEnd);
while (true) {
char key = readKeypad();
if (key >= '0' && key <= '9') {
cyclesCount = cyclesCount * 10 + (key - '0');
lcd.setCursor(0, 3);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print("Cycles: ");
lcd.print(cyclesCount);
digitalWrite(BUZZER, HIGH); delay(30); digitalWrite(BUZZER, LOW);
}
if (key == 'X') { // backspace
cyclesCount = cyclesCount / 10;
lcd.setCursor(0, 3);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print("Cycles: ");
lcd.print(cyclesCount);
}
if (key == 'N') {
if (cyclesCount >= 2 && cyclesCount <= 99) break;
else {
lcd.setCursor(0, 3);
lcd.print("Enter 2-99 only!");
}
}
if (key == 'E') { menu(); return; }
}
// ----- Lid pre-heating -----
const float LID_TARGET = 105.0;
const float LID_START_THRESHOLD = 100.0;
bool lidReady = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Heating lid...");
lcd.setCursor(0, 1);
lcd.print("Target: 105 C");
digitalWrite(LID_HEATER, HIGH);
while (!lidReady) {
float lidTemp = readLidTemperature();
lcd.setCursor(0, 2);
lcd.print("Lid: ");
lcd.print(lidTemp, 1);
lcd.print(" C ");
regulateLid(LID_TARGET);
if (lidTemp >= LID_START_THRESHOLD) {
lidReady = true;
break;
}
char key = readKeypad();
if (key == 'V' || key == 'E') { // Stop with V or Exit with E
digitalWrite(LID_HEATER, LOW);
menu();
return;
}
delay(20);
}
lcd.setCursor(0, 3);
lcd.print("Lid ready! ");
delay(500);
// ----- RUN PROTOCOL -----
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Running Protocol");
lcd.setCursor(0, 1);
lcd.print("Press V to stop");
delay(1000);
bool stopRequested = false;
const float TOLERANCE = 0.5;
float currentTemp = 0.0;
// Helper to execute one step (heating + hold)
auto executeStep = [&](int step, bool inCycle, int cycleNum, int totalCycles) -> bool {
float target = temperatures[step];
int duration = times[step];
// Heating phase
lcd.clear();
lcd.setCursor(0, 0);
if (inCycle) {
lcd.print("Cycle ");
lcd.print(cycleNum);
lcd.print("/");
lcd.print(totalCycles);
} else {
lcd.print("Pre/Post Step ");
}
lcd.setCursor(0, 1);
lcd.print("Step ");
lcd.print(step+1);
lcd.print(" Heating...");
while (!stopRequested) {
currentTemp = readBlockTemperature();
regulateLid(LID_TARGET);
float lidTemp = readLidTemperature();
lcd.setCursor(12,0);
lcd.print("L:");
lcd.print(lidTemp,1);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print("Target: ");
lcd.print(target);
lcd.print(" C ");
lcd.setCursor(0, 3);
lcd.print("Now: ");
lcd.print(currentTemp);
lcd.print(" C ");
if (abs(currentTemp - target) <= TOLERANCE) break;
char key = readKeypad();
if (key == 'V') { stopRequested = true; return false; } // Stop with V
delay(20);
}
if (stopRequested) return false;
if (duration == 0) return true;
// Hold phase
unsigned long startMillis = millis();
unsigned long elapsed = 0;
lcd.clear();
lcd.setCursor(0, 0);
if (inCycle) {
lcd.print("Cycle ");
lcd.print(cycleNum);
lcd.print("/");
lcd.print(totalCycles);
} else {
lcd.print("Pre/Post Step ");
}
lcd.setCursor(0, 1);
lcd.print("Step ");
lcd.print(step+1);
lcd.print(" Holding");
while (!stopRequested && elapsed < (unsigned long)duration) {
currentTemp = readBlockTemperature();
regulateLid(LID_TARGET);
elapsed = (millis() - startMillis) / 1000;
long remaining = duration - elapsed;
int min = remaining / 60;
int sec = remaining % 60;
float lidTemp = readLidTemperature();
lcd.setCursor(12,0);
lcd.print("L:");
lcd.print(lidTemp,1);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print("Temp: ");
lcd.print(currentTemp);
lcd.print(" C ");
lcd.setCursor(0, 3);
lcd.print("Time left: ");
lcd.print(min);
lcd.print(":");
if (sec < 10) lcd.print("0");
lcd.print(sec);
lcd.print(" ");
char key = readKeypad();
if (key == 'V') { stopRequested = true; return false; } // Stop with V
delay(20);
}
return true;
};
// ---- Pre-cycle steps (1 to cycleStart-1) ----
for (int i = 0; i < cycleStart-1 && !stopRequested; i++) {
if (!executeStep(i, false, 0, 0)) break;
}
// ---- Cycle steps (repeated) ----
for (int cycle = 1; cycle <= cyclesCount && !stopRequested; cycle++) {
for (int i = cycleStart-1; i < cycleEnd && !stopRequested; i++) {
if (!executeStep(i, true, cycle, cyclesCount)) break;
}
}
// ---- Post-cycle steps (cycleEnd to numSteps-1) ----
if (!stopRequested) {
for (int i = cycleEnd; i < numSteps && !stopRequested; i++) {
if (!executeStep(i, false, 0, 0)) break;
}
}
// ----- Completion -----
digitalWrite(LID_HEATER, LOW);
if (!stopRequested) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Protocol Complete");
lcd.setCursor(0, 1);
lcd.print("Holding at 4 C");
for (int i = 0; i < 3; i++) {
digitalWrite(BUZZER, HIGH); delay(300);
digitalWrite(BUZZER, LOW); delay(20);
}
delay(5000);
} else {
lcd.clear();
lcd.print("Protocol aborted");
delay(1000);
}
menu();
}
// ========== OTHER MENU FUNCTIONS ==========
void savedProtocols()
{
lcd.clear();
while (1)
{
lcd.setCursor(0,0);
lcd.print("Saved Protocol");
lcd.setCursor(0,1);
lcd.print(protocolIndex+1);
lcd.print(".");
lcd.print(protocolName[protocolIndex]);
lcd.setCursor(0,3);
lcd.print("U/D N=OK E=Exit");
char key = readKeypad();
if(key=='U')
{
if(protocolIndex>0)
protocolIndex--;
}
if(key=='D')
{
if(protocolIndex<TOTAL_PROTOCOLS-1)
protocolIndex++;
}
if(key=='N')
{
runSavedProtocol(protocolIndex);
return;
}
if(key=='E')
{
menu();
return;
}
delay(150);
}
}
void newProtocol() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(">New Protocol");
lcd.setCursor(0, 1);
lcd.print("Press 0 to exit");
while(true) {
char key = readKeypad();
if(key == '0') { menu(); break; }
delay(100);
}
}
void editProtocol() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(">Edit Protocol");
lcd.setCursor(0, 1);
lcd.print("Press 0 to exit");
while(true) {
char key = readKeypad();
if(key == '0') { menu(); break; }
delay(100);
}
}
void deleteProtocol() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(">Delete Protocol");
lcd.setCursor(0, 1);
lcd.print("Press 0 to exit");
while(true) {
char key = readKeypad();
if(key == '0') { menu(); break; }
delay(100);
}
}
void settings() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(">Settings");
lcd.setCursor(0, 1);
lcd.print("Press 0 to exit");
while(true) {
char key = readKeypad();
if(key == '0') { menu(); break; }
delay(100);
}
}
void calibration() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(">Calibration");
lcd.setCursor(0, 1);
lcd.print("Press 0 to exit");
while(true) {
char key = readKeypad();
if(key == '0') { menu(); break; }
delay(100);
}
}
void loadFactoryProtocols()
{
savedProtocol[0].name="HCV PCR";
savedProtocol[0].steps=3;
savedProtocol[0].temp[0]=95;
savedProtocol[0].timeSec[0]=300;
savedProtocol[0].temp[1]=95;
savedProtocol[0].timeSec[1]=15;
savedProtocol[0].temp[2]=60;
savedProtocol[0].timeSec[2]=60;
savedProtocol[0].cycleStart=2;
savedProtocol[0].cycleEnd=3;
savedProtocol[0].cycles=40;
savedProtocol[0].lidTemp=105;
savedProtocol[1]=savedProtocol[0];
savedProtocol[1].name="HBV PCR";
savedProtocol[2]=savedProtocol[0];
savedProtocol[2].name="HIV PCR";
savedProtocol[3]=savedProtocol[0];
savedProtocol[3].name="COVID-19";
}
void runSavedProtocol(int index)
{
lcd.clear();
lcd.print("Loading...");
delay(500);
lcd.clear();
lcd.print(savedProtocol[index].name);
delay(1000);
lcd.clear();
for(byte i=0;i<savedProtocol[index].steps;i++)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Step ");
lcd.print(i+1);
lcd.print("/");
lcd.print(savedProtocol[index].steps);
lcd.setCursor(0,1);
lcd.print(savedProtocol[index].temp[i]);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(12,1);
lcd.print(savedProtocol[index].timeSec[i]);
lcd.print(" s");
delay(2000);
}
lcd.clear();
lcd.print("Protocol Finish");
delay(1500);
menu();
}