From 83235487a30908b66e70cbd360ff09af07c24dcf Mon Sep 17 00:00:00 2001 From: Caril <caril.martinez@cti.espol.edu.ec> Date: Mon, 28 Oct 2024 16:33:28 -0500 Subject: [PATCH] Updates in nes_main.ino --- firmware/nest_main/nest_main.ino | 533 ++++++++++++++++++++++++++++++- 1 file changed, 532 insertions(+), 1 deletion(-) diff --git a/firmware/nest_main/nest_main.ino b/firmware/nest_main/nest_main.ino index 1fd83ec..a7aeeae 100644 --- a/firmware/nest_main/nest_main.ino +++ b/firmware/nest_main/nest_main.ino @@ -1,3 +1,535 @@ +#include <Adafruit_TinyUSB.h> +#include <SPI.h> +#include "Ucglib.h" +#include <TouchScreen.h> +#include <bluefruit.h> +#include "algorithm_by_RF.h" +#include "max30102.h" + +#define TFT_CS 33 +#define TFT_RST 2 +#define TFT_DC 25 +#define TFT_MOSI 24 +#define TFT_SCLK 26 +#define LIGHT_PIN 10 +#define OXI_INT 18 +//#define PIN_BUTTON1 1 // Button defined in variant + +Ucglib_ST7735_18x128x160_HWSPI ucg(TFT_DC, TFT_CS, TFT_RST); + +// Touchscreen pins +#define YP A6 +#define XM A2 +#define YM A0 +#define XP A7 +#define TS_MINX 150 +#define TS_MINY 120 +#define TS_MAXX 920 +#define TS_MAXY 940 +TouchScreen ts = TouchScreen(XP, YP, XM, YM, 150); + +// Global variables for the screen state +// Screen enumerations for various views +enum Screen { MAIN_MENU, RESCUE_CONFIRM, SENDING_DATA, SURVEY_SENT, HEART_RATE, PAIN_DIARY, PAIN_DESCRIPTION, DAILY_LIMITATION, HR_MEASUREMENT, HR_RESULT, HR_ERROR, DATA_CONFIRMATION, DATA_SENDING }; + +Screen currentScreen = MAIN_MENU; +Screen previousScreen = MAIN_MENU; // Stores the previous screen for easy navigation back + +int selectedPainLevel = -1; // Pain intensity level +int dailyLimitation = -1; // Daily activity limitation level +int painDescription = -1; // Pain description + +int currentBpm = -1; // Default BPM value, indicating no valid value yet +uint32_t elapsedTime, timeStart; + +uint32_t aun_ir_buffer[BUFFER_SIZE]; // Infrared LED sensor data +uint32_t aun_red_buffer[BUFFER_SIZE]; // Red LED sensor data +float old_n_spo2; // Previous SPO2 value +uint8_t uch_dummy, k; + +// Define UUIDs for BLE service and characteristic +#define SERVICE_UUID "12345678-1234-5678-1234-56789abcdef0" +#define CHARACTERISTIC_UUID "abcdef12-3456-7890-1234-56789abcdef1" +BLEService customService(SERVICE_UUID); +BLECharacteristic alertCharacteristic(CHARACTERISTIC_UUID); + +// Initial setup function for initializing the screen, BLE, and setting pins +void setup(void) { + pinMode(OXI_INT, INPUT); // Initialize the MAX30102 interrupt pin + pinMode(PIN_BUTTON1, INPUT_PULLUP); // Configure button as input with pull-up resistor + + Serial.begin(115200); // Begin serial communication for debugging + while (!Serial); // Wait for the serial port to be ready for debugging + + maxim_max30102_init(); // Initialize the MAX30102 sensor + old_n_spo2 = 0.0; + + pinMode(LIGHT_PIN, OUTPUT); + analogWrite(LIGHT_PIN, 255); + ucg.begin(UCG_FONT_MODE_TRANSPARENT); + ucg.clearScreen(); + setupBLE(); // Initialize BLE configuration + drawInterface(); // Draw the main menu screen +} + +// Main loop that runs continuously for screen interactions and heart rate updates +void loop(void) { + bool isTouched = checkTouch(); // Checks if the screen was touched + + if (currentScreen == HEART_RATE && !isTouched) { + updateHeartRate(); // Only update heart rate if on heart rate screen and no touch is detected + } + + checkButtonPress(); // Check button status for navigation + delay(100); // Small delay to avoid frequent refresh +} + +// Check if button 1 is pressed for navigation +void checkButtonPress() { + if (digitalRead(PIN_BUTTON1) == LOW) { // If button is pressed + Serial.println("Button pressed"); + delay(200); // Small delay to prevent multiple button reads + goToPreviousScreen(); // Navigate back to the previous screen + } +} + +// Go to the previous screen based on the stored value of `previousScreen` +void goToPreviousScreen() { + switch (previousScreen) { + case MAIN_MENU: + drawInterface(); + break; + case RESCUE_CONFIRM: + drawRescueConfirmationScreen(); + break; + case SENDING_DATA: + drawSendingDataScreen(); + break; + case SURVEY_SENT: + drawSurveySentScreen(); + break; + case HEART_RATE: + drawHeartRateScreen(); + break; + case PAIN_DIARY: + drawPainDiaryScreen(); + break; + case PAIN_DESCRIPTION: + drawPainDescriptionScreen(); + break; + case DAILY_LIMITATION: + drawDailyLimitationScreen(); + break; + default: + drawInterface(); // Default to main menu if no previous screen is found + break; + } +} + +// BLE setup for configuring the device and starting advertising +void setupBLE() { + Bluefruit.begin(); + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + Bluefruit.setName("NEST Device"); + + // Initialize BLE service + customService.begin(); + + // Initialize BLE characteristic for notifications + alertCharacteristic.setProperties(CHR_PROPS_NOTIFY); + alertCharacteristic.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); + alertCharacteristic.setFixedLen(20); + alertCharacteristic.begin(); + + startAdvertising(); +} + +// Start BLE advertising +void startAdvertising() { + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addService(customService); + Bluefruit.Advertising.addName(); + Bluefruit.Advertising.start(0); // 0 for continuous advertising +} + +// BLE connection callback +void connect_callback(uint16_t conn_handle) { + Serial.println("Device Connected!"); +} + +// BLE disconnection callback +void disconnect_callback(uint16_t conn_handle, uint8_t reason) { + Serial.println("Device Disconnected!"); +} + +// Draw main interface with options for different screens +void drawInterface() { + previousScreen = currentScreen; + currentScreen = MAIN_MENU; + ucg.clearScreen(); + ucg.setColor(255, 255, 255); // White + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 15); + ucg.print("NEST - OS"); + + drawButton(5, 30, 118, 36, "Diario del dolor", 0x2104); + drawButton(5, 75, 118, 36, "Rescate", 0x2104); + drawButton(5, 120, 118, 36, "Monitoreo", 0x2104); +} + +// Draw screen for pain diary options +void drawPainDiaryScreen() { + previousScreen = currentScreen; + currentScreen = PAIN_DIARY; + ucg.clearScreen(); + + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 15); + ucg.print("Intensidad"); + + drawButton(10, 30, 110, 25, "Ausencia de dolor", 0x00E0); // Green + drawButton(10, 60, 110, 25, "Dolor leve", 0xCC60); // Yellow + drawButton(10, 90, 110, 25, "Dolor moderado", 0xFB40); // Orange + drawButton(10, 120, 110, 25, "Dolor severo", 0xF800); // Red +} + +// Draw screen for pain description options +void drawPainDescriptionScreen() { + previousScreen = currentScreen; + currentScreen = PAIN_DESCRIPTION; + ucg.clearScreen(); + + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 15); + ucg.print("¿Como te duele?"); + + drawButton(10, 30, 110, 25, "Intensidad cambia", 0x2104); // Yellow + drawButton(10, 60, 110, 25, "Intensidad igual", 0x2104); // Orange + drawButton(10, 90, 110, 25, "Punzadas", 0x2104); // Red + drawButton(10, 120, 110, 25, "Al levantarse", 0x2104); // Green +} + +// Draw screen to assess daily limitation from pain +void drawDailyLimitationScreen() { + previousScreen = currentScreen; + currentScreen = DAILY_LIMITATION; + ucg.clearScreen(); + + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 15); + ucg.print("¿Lo limita?"); + + drawButton(10, 30, 110, 25, "No me limita", 0x00E0); // Green + drawButton(10, 60, 110, 25, "Ligeramente", 0xCC60); // Yellow + drawButton(10, 90, 110, 25, "Moderada", 0xFB40); // Orange + drawButton(10, 120, 110, 25, "Total", 0xF800); // Red +} + +// Draw heart rate measurement screen +void drawHRMeasurementScreen() { + previousScreen = currentScreen; + currentScreen = HR_MEASUREMENT; + ucg.clearScreen(); + + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 15); + ucg.print("Frecuencia"); + ucg.setPrintPos(10, 30); // Next line for "cardiaca" + ucg.print("cardiaca"); + + ucg.setFont(ucg_font_ncenR14_hr); + ucg.setPrintPos(30, 60); // Position "Sensando..." further left + ucg.print("Sensando..."); + + // Purple back button + ucg.setColor(128, 0, 128); + ucg.drawDisc(20, 80, 15, UCG_DRAW_ALL); + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(15, 85); + ucg.print("<"); + + startHeartRateMeasurement(); // Start BPM sensing +} + + + +void startHeartRateMeasurement() { + int attempts = 0; + currentBpm = -1; + + while (attempts < 5 && currentBpm <= 0) { + updateHeartRate(); // Intenta sensar la frecuencia cardÃaca + if (currentBpm > 0) { + drawHRResultScreen(currentBpm); // Muestra el valor si es válido + return; + } + attempts++; + delay(500); // Pausa corta entre intentos + } + + if (currentBpm <= 0) { + drawHRErrorScreen(); // Muestra un mensaje de error si no hay BPM válidos + } +} + +void drawHRResultScreen(float bpm) { + previousScreen = currentScreen; + currentScreen = HR_RESULT; + ucg.clearScreen(); + + // Mostrar "Frecuencia cardiaca" + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 15); + ucg.print("Frecuencia"); + + ucg.setPrintPos(10, 35); + ucg.print("cardiaca"); + + // Mostrar el valor de BPM + ucg.setFont(ucg_font_ncenR24_tr); + ucg.setPrintPos(34, 75); // Ajusta la posición + ucg.print(bpm, 1); // Muestra los BPM con un decimal + + // Mostrar "BPM" debajo del valor + ucg.setFont(ucg_font_ncenR14_hr); + ucg.setPrintPos(45, 100); + ucg.print("BPM"); + + // Botones de navegación + ucg.setColor(128, 0, 128); // Púrpura para los botones + ucg.drawDisc(20, 80, 15, UCG_DRAW_ALL); // Botón izquierdo + ucg.drawDisc(110, 80, 15, UCG_DRAW_ALL); // Botón derecho + + // Flechas en los botones + ucg.setColor(255, 255, 255); // Texto blanco + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(15, 85); // Flecha izquierda + ucg.print("<"); + ucg.setPrintPos(105, 85); // Flecha derecha + ucg.print(">"); +} + +void drawDataSendingScreen() { + previousScreen = currentScreen; + currentScreen = DATA_SENDING; + + ucg.clearScreen(); + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR14_hr); + ucg.setPrintPos(10, 60); ucg.print("Enviando"); + ucg.setPrintPos(10, 80); ucg.print("datos..."); + delay(3000); + sendSurveyDataViaBLE(); +} + + + +void drawHRErrorScreen() { + previousScreen = currentScreen; + currentScreen = HR_ERROR; + ucg.clearScreen(); + + ucg.setColor(255, 0, 0); // Texto rojo para el mensaje de error + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 40); + ucg.print("Error leyendo"); + ucg.setPrintPos(10, 60); + ucg.print("HR"); + + // Botón púrpura para regresar + ucg.setColor(128, 0, 128); // Color púrpura para el botón + ucg.drawDisc(20, 80, 15, UCG_DRAW_ALL); + ucg.setColor(255, 255, 255); // Blanco para el icono del botón + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(15, 85); + ucg.print("<"); +} + + +void drawDataConfirmationScreen() { + previousScreen = currentScreen; + currentScreen = DATA_CONFIRMATION; // Nueva pantalla para confirmar el envÃo de datos especÃficos + ucg.clearScreen(); + + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 20); ucg.print("Esta seguro"); + ucg.setPrintPos(10, 40); ucg.print("de enviar"); + ucg.setPrintPos(10, 60); ucg.print("los datos?"); + + ucg.setColor(255, 0, 0); // Red for the NO button + ucg.drawDisc(40, 100, 20, UCG_DRAW_ALL); + ucg.setColor(255, 255, 255); ucg.setPrintPos(34, 107); ucg.print("X"); + + // Smaller YES button with a check mark + ucg.setColor(0, 0, 255); // Blue + ucg.drawDisc(90, 100, 20, UCG_DRAW_ALL); // Reduced diameter + ucg.setColor(255, 255, 255); // White + + // Draw a thicker check mark + int baseX = 85, baseY = 98; // Base point for the check + // Lines for the lower part of the check + ucg.drawLine(baseX, baseY, baseX + 4, baseY + 4); + ucg.drawLine(baseX, baseY - 1, baseX + 4, baseY + 3); + ucg.drawLine(baseX, baseY + 1, baseX + 4, baseY + 5); + // Lines for the upper part of the check + ucg.drawLine(baseX + 3, baseY + 3, baseX + 12, baseY - 6); + ucg.drawLine(baseX + 3, baseY + 4, baseX + 12, baseY - 5); + ucg.drawLine(baseX + 3, baseY + 5, baseX + 12, baseY - 4); + +} + +void drawRescueConfirmationScreen() { + currentScreen = RESCUE_CONFIRM; + ucg.clearScreen(); + + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(10, 20); ucg.print("Esta seguro"); + ucg.setPrintPos(10, 40); ucg.print("de enviar"); + ucg.setPrintPos(10, 60); ucg.print("los datos?"); + + ucg.setColor(255, 0, 0); // Red for the NO button + ucg.drawDisc(40, 100, 20, UCG_DRAW_ALL); + ucg.setColor(255, 255, 255); ucg.setPrintPos(34, 107); ucg.print("X"); + + // Smaller YES button with a check mark + ucg.setColor(0, 0, 255); // Blue + ucg.drawDisc(90, 100, 20, UCG_DRAW_ALL); // Reduced diameter + ucg.setColor(255, 255, 255); // White + + // Draw a thicker check mark + int baseX = 85, baseY = 98; // Base point for the check + // Lines for the lower part of the check + ucg.drawLine(baseX, baseY, baseX + 4, baseY + 4); + ucg.drawLine(baseX, baseY - 1, baseX + 4, baseY + 3); + ucg.drawLine(baseX, baseY + 1, baseX + 4, baseY + 5); + // Lines for the upper part of the check + ucg.drawLine(baseX + 3, baseY + 3, baseX + 12, baseY - 6); + ucg.drawLine(baseX + 3, baseY + 4, baseX + 12, baseY - 5); + ucg.drawLine(baseX + 3, baseY + 5, baseX + 12, baseY - 4); + +} + + +void drawSendingDataScreen() { + // Save previous screen and set current screen to SENDING_DATA + previousScreen = currentScreen; + currentScreen = SENDING_DATA; + ucg.clearScreen(); // Clear the screen + + // Display "Enviando datos..." message + ucg.setColor(255, 255, 255); // Set text color to white + ucg.setFont(ucg_font_ncenR14_hr); + ucg.setPrintPos(10, 60); + ucg.print("Enviando"); + ucg.setPrintPos(10, 80); + ucg.print("datos..."); + + // Prepare alert message to send over BLE + const char* alertMsg = "Data Sent"; + if (Bluefruit.connected()) { + // Attempt to send BLE notification with data + if (alertCharacteristic.notify(alertMsg, strlen(alertMsg))) { + Serial.println("Alert sent via BLE"); + } else { + Serial.println("Failed to send notification"); + } + } else { + Serial.println("No devices connected."); + } + + delay(3000); // Simulate sending delay + drawSurveySentScreen(); // Show confirmation screen after sending +} + +void drawSurveySentScreen() { + // Save previous screen and set current screen to SURVEY_SENT + previousScreen = currentScreen; + currentScreen = SURVEY_SENT; + ucg.clearScreen(); // Clear the screen + + // Display "Encuesta Enviada" message + ucg.setColor(255, 255, 255); // Set text color to white + ucg.setFont(ucg_font_ncenR14_hr); + ucg.setPrintPos(10, 60); + ucg.print("Encuesta"); + ucg.setPrintPos(10, 80); + ucg.print("Enviada"); + + // Draw purple button on the right side for next action + ucg.setColor(128, 0, 128); // Purple color for the button + ucg.drawDisc(110, 80, 15, UCG_DRAW_ALL); // Draw right button + + // Add arrow on the right button + ucg.setColor(255, 255, 255); // White for arrow + ucg.setFont(ucg_font_ncenR12_tr); + ucg.setPrintPos(105, 85); // Adjust position for the arrow + ucg.print(">"); +} + +void drawHeartRateScreen() { + // Set current screen to HEART_RATE and clear screen + currentScreen = HEART_RATE; + ucg.clearScreen(); // Clear screen before drawing the new view + + // Display "Frecuencia Cardiaca" title + ucg.setColor(255, 255, 255); // White text color + ucg.setFont(ucg_font_ncenR14_hr); // Larger font for title + ucg.setPrintPos(10, 20); + ucg.print("Frecuencia"); + ucg.setPrintPos(10, 35); + ucg.print("Cardiaca"); + + // Draw left navigation button to go back + ucg.setColor(128, 0, 128); // Purple color for the button + ucg.drawDisc(20, 80, 15, UCG_DRAW_ALL); + ucg.setColor(255, 255, 255); // White for the button icon + ucg.setFont(ucg_font_ncenR12_tr); // Smaller font for the icon + ucg.setPrintPos(15, 85); // Adjust position for centering text in the circle + ucg.print("<"); + + // Display heart rate value or placeholder if invalid + ucg.setFont(ucg_font_ncenR24_tr); // Large font for heart rate numbers + ucg.setColor(255, 255, 255); // White text color + ucg.setPrintPos(60, 80); // Adjust position as needed + if (currentBpm >= 0) { + ucg.print(currentBpm); // Display current BPM value + } else { + ucg.print(" -"); // Display dash if BPM is invalid + } + + // Display "BPM" label below heart rate + ucg.setFont(ucg_font_ncenR14_hr); // Smaller font for BPM label + ucg.setPrintPos(60, 100); + ucg.print("BPM"); + + // Draw heart shape below "BPM" text + drawHeart(80, 110); // Call function to draw heart at specified position +} + +void drawHeart(int x, int y) { + // Set color to red for the heart shape + ucg.setColor(255, 0, 0); + + // Draw the top part of the heart using two overlapping circles + ucg.drawDisc(x - 2, y - 2, 4, UCG_DRAW_UPPER_LEFT); + ucg.drawDisc(x - 2, y - 2, 4, UCG_DRAW_UPPER_RIGHT); + ucg.drawDisc(x + 9, y - 2, 4, UCG_DRAW_UPPER_RIGHT); + ucg.drawDisc(x + 9, y - 2, 4, UCG_DRAW_UPPER_LEFT); + + // Draw the bottom part of the heart as a triangle + ucg.drawTriangle(x - 6, y - 2, x + 14, y - 2, x + 4, y + 8); +} + bool checkTouch() { TSPoint p = ts.getPoint(); pinMode(XM, OUTPUT); @@ -230,4 +762,3 @@ void updateHeartRate() { - -- GitLab