From 2f471aeae61da6e67da4e86ed9aa13891b48a005 Mon Sep 17 00:00:00 2001 From: Caril <caril.martinez@cti.espol.edu.ec> Date: Mon, 28 Oct 2024 16:21:05 -0500 Subject: [PATCH] Updates --- firmware/nest_main.ino | 347 ------------------------------- firmware/nest_main/nest_main.ino | 233 +++++++++++++++++++++ 2 files changed, 233 insertions(+), 347 deletions(-) delete mode 100644 firmware/nest_main.ino create mode 100644 firmware/nest_main/nest_main.ino diff --git a/firmware/nest_main.ino b/firmware/nest_main.ino deleted file mode 100644 index c1d00a0..0000000 --- a/firmware/nest_main.ino +++ /dev/null @@ -1,347 +0,0 @@ -#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 - -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, 300); - -// Global variables for the screen state -enum Screen { MAIN_MENU, RESCUE_CONFIRM, SENDING_DATA, SURVEY_SENT, HEART_RATE }; -Screen currentScreen = MAIN_MENU; - -int currentBpm = -1; // Initialized to -1 to indicate 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 the 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); - -void setup(void) { - - pinMode(OXI_INT, INPUT); // pin 18 connects to the interrupt output pin of the MAX30102 - - Serial.begin(115200); - while (!Serial); // Wait for the serial port to be ready for debugging - - maxim_max30102_init(); // Initialize the MAX30102 - 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(); // Initially draw the main screen -} - -void loop(void) { - bool isTouched = checkTouch(); // This returns true if the screen was touched - - if (currentScreen == HEART_RATE && !isTouched) { - updateHeartRate(); // Only update if we are on the heart rate screen and no touch was detected - } - - delay(100); // Small delay to avoid too fast refreshing -} - -void setupBLE() { - Bluefruit.begin(); - Bluefruit.Periph.setConnectCallback(connect_callback); - Bluefruit.Periph.setDisconnectCallback(disconnect_callback); - Bluefruit.setName("NEST Device"); - - // Initialize the service - customService.begin(); - - // Initialize the characteristic - alertCharacteristic.setProperties(CHR_PROPS_NOTIFY); - alertCharacteristic.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); - alertCharacteristic.setFixedLen(20); - alertCharacteristic.begin(); - - startAdvertising(); -} - -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 -} - -void connect_callback(uint16_t conn_handle) { - Serial.println("Device Connected!"); -} - -void disconnect_callback(uint16_t conn_handle, uint8_t reason) { - Serial.println("Device Disconnected!"); -} - -void drawInterface() { - 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, "Pain Diary", 0x2104); - drawButton(5, 75, 118, 36, "Rescue", 0x2104); - drawButton(5, 120, 118, 36, "Monitoring", 0x2104); -} - -void drawRescueConfirmationScreen() { - currentScreen = RESCUE_CONFIRM; - ucg.clearScreen(); - - ucg.setColor(255, 255, 255); - ucg.setFont(ucg_font_ncenR12_tr); - ucg.setPrintPos(10, 20); ucg.print("Are you sure"); - ucg.setPrintPos(10, 40); ucg.print("you want to"); - ucg.setPrintPos(10, 60); ucg.print("send data"); - - 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() { - currentScreen = SENDING_DATA; - ucg.clearScreen(); - ucg.setColor(255, 255, 255); - ucg.setFont(ucg_font_ncenR14_hr); - ucg.setPrintPos(10, 60); ucg.print("Sending"); - ucg.setPrintPos(10, 80); ucg.print("data..."); - - const char* alertMsg = "Data Sent"; - if (Bluefruit.connected()) { - 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 some processing - drawSurveySentScreen(); // Call the screen for survey sent -} - -void drawSurveySentScreen() { - currentScreen = SURVEY_SENT; // Set the correct state - ucg.clearScreen(); - ucg.setColor(255, 255, 255); - ucg.setFont(ucg_font_ncenR14_hr); - ucg.setPrintPos(10, 60); - ucg.print("Survey"); - ucg.setPrintPos(10, 80); - ucg.print("Sent"); -} - -void drawHeartRateScreen() { - currentScreen = HEART_RATE; // Make sure to add this to the screen enum - ucg.clearScreen(); // Clear the screen before drawing the new view - - ucg.setColor(255, 255, 255); // White for the text - ucg.setFont(ucg_font_ncenR14_hr); // Large font for the title - ucg.setPrintPos(10, 20); // Adjust position as needed - ucg.print("Heart"); - ucg.setPrintPos(10, 35); // Adjust position as needed - ucg.print("Rate"); - - // Draw a 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); // Change to a smaller font for the icon - ucg.setPrintPos(15, 85); // Adjust to center the text in the circle - ucg.print("<"); - - // Draw the heart rate value - ucg.setFont(ucg_font_ncenR24_tr); // Large font for the numbers - ucg.setColor(255, 255, 255); // White - ucg.setPrintPos(60, 80); // Adjust as needed - - if (currentBpm >= 0) { - ucg.print(currentBpm); // Show the current BPM value - } else { - ucg.print(" -"); // Show a dash if BPM is invalid - } - - ucg.setFont(ucg_font_ncenR14_hr); // Smaller font for "BPM" - ucg.setPrintPos(60, 100); // Adjust as needed - ucg.print("BPM"); - - // Draw a small heart below "BPM" - drawHeart(80, 110); // Adjust coordinates as needed -} - -void drawHeart(int x, int y) { - ucg.setColor(255, 0, 0); // Red color for the heart - - // Draw the top of the heart as two red circles - // Make sure the circles slightly overlap the triangle - ucg.drawDisc(x - 2, y - 2, 4, UCG_DRAW_UPPER_LEFT); // Adjust position for better blending - ucg.drawDisc(x - 2, y - 2, 4, UCG_DRAW_UPPER_RIGHT); // Adjust position for better blending - ucg.drawDisc(x + 9, y - 2, 4, UCG_DRAW_UPPER_RIGHT); // Adjust position for better blending - ucg.drawDisc(x + 9, y - 2, 4, UCG_DRAW_UPPER_LEFT); // Adjust position for better blending - - // 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); - pinMode(YP, OUTPUT); - bool screenTouched = false; - - if (p.z > ts.pressureThreshhold) { - int x = map(p.x, TS_MINX, TS_MAXX, 0, 128); - int y = map(p.y, TS_MINY, TS_MAXY, 0, 160); - screenTouched = true; // The screen was touched - - switch(currentScreen) { - case MAIN_MENU: - if (y > 30 && y < 66) { // "Pain Diary" button - // Implement what should happen if "Pain Diary" is selected - } else if (y > 75 && y < 111) { // "Rescue" button - drawRescueConfirmationScreen(); - } else if (y > 120 && y < 156) { // "Monitoring" button - drawHeartRateScreen(); - } - break; - - case RESCUE_CONFIRM: - if (x > 20 && x < 60 && y > 80 && y < 120) { // NO button - drawInterface(); // Go back to the main menu - } else if (x > 70 && x < 110 && y > 80 && y < 120) { // YES button - drawSendingDataScreen(); // Go to "Sending data..." - } - break; - - case SENDING_DATA: - // Hold the screen until any part is touched, then go back to the menu - drawInterface(); - break; - - case SURVEY_SENT: - // Return to the main menu with any screen touch - drawInterface(); - break; - - case HEART_RATE: - if (x > 20 && x < 60 && y > 80 && y < 120) { // Back button area on the "Heart Rate" screen - drawInterface(); // Go back to the main menu - } - break; - - default: - // You can add more cases if there are more screens - break; - } - } - return screenTouched; -} - -void drawButton(int x, int y, int w, int h, const char* text, uint16_t color) { - ucg.setColor(255, 255, 255); - ucg.drawRBox(x, y, w, h, 5); - ucg.setColor(color >> 8, color & 0xFF, color & 0xFF); - ucg.drawRBox(x + 2, y + 2, w - 4, h - 4, 5); - ucg.setColor(255, 255, 255); - ucg.setFont(ucg_font_6x10_tr); - int textX = x + (w - ucg.getStrWidth(text)) / 2; - int textY = y + h / 2 + 3; - ucg.setPrintPos(textX, textY); - ucg.print(text); -} - -void updateHeartRate() { - static unsigned long lastUpdateTime = 0; // Save the last time the reading was updated - int32_t n_heart_rate; // Variable to store heart rate value - int8_t ch_hr_valid; // Indicator if heart rate reading is valid - float n_spo2, ratio, correl; // Additional variables used in calculation - int8_t ch_spo2_valid; // Validity indicator for oxygen saturation - int32_t i; - - for(i = 0; i < BUFFER_SIZE; i++) { - while (digitalRead(OXI_INT) == 1); // Wait until the interrupt pin asserts - maxim_max30102_read_fifo((aun_red_buffer + i), (aun_ir_buffer + i)); // Read from MAX30102 FIFO - } - - // Calculate heart rate and oxygen saturation - rf_heart_rate_and_oxygen_saturation(aun_ir_buffer, BUFFER_SIZE, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid, &ratio, &correl); - - if (ch_hr_valid) { - currentBpm = n_heart_rate; - } else { - currentBpm = -1; // If reading is invalid, set to -1 - } - - if (currentScreen == HEART_RATE) { - ucg.setColor(0, 0, 0); // Assuming the background is black - ucg.drawBox(40, 50, 80, 35); // Adjust dimensions to fully cover the number and text - - ucg.setColor(255, 255, 255); // White - ucg.setFont(ucg_font_ncenR24_tr); - ucg.setPrintPos(60, 80); // Adjust as needed - - if (currentBpm >= 0) { - ucg.print(currentBpm); - } else { - ucg.print(" -"); - } - } -} - - - diff --git a/firmware/nest_main/nest_main.ino b/firmware/nest_main/nest_main.ino new file mode 100644 index 0000000..1fd83ec --- /dev/null +++ b/firmware/nest_main/nest_main.ino @@ -0,0 +1,233 @@ +bool checkTouch() { + TSPoint p = ts.getPoint(); + pinMode(XM, OUTPUT); + pinMode(YP, OUTPUT); + bool screenTouched = false; + + // Check if screen was touched by pressure threshold + if (p.z > ts.pressureThreshhold) { + int x = map(p.x, TS_MINX, TS_MAXX, 0, 128); + int y = map(p.y, TS_MINY, TS_MAXY, 0, 160); + screenTouched = true; + + // Switch case for handling different screens based on the current screen state + switch (currentScreen) { + case MAIN_MENU: + if (y > 30 && y < 66) { + drawPainDiaryScreen(); // Open Pain Diary screen + } else if (y > 75 && y < 111) { + drawRescueConfirmationScreen(); + } else if (y > 120 && y < 156) { + drawHeartRateScreen(); + } + break; + + case PAIN_DIARY: + // Select pain intensity level and proceed accordingly + if (y > 40 && y < 70) { + Serial.println("Ausencia de dolor seleccionada"); + selectedPainLevel = 0; // No pain + drawInterface(); + } else if (y > 80 && y < 110) { + Serial.println("Dolor leve seleccionado"); + selectedPainLevel = 1; // Mild pain + drawPainDescriptionScreen(); // Proceed to pain description screen + } else if (y > 120 && y < 150) { + Serial.println("Dolor moderado seleccionado"); + selectedPainLevel = 2; // Moderate pain + drawPainDescriptionScreen(); + } else if (y > 160 && y < 190) { + Serial.println("Dolor severo seleccionado"); + selectedPainLevel = 3; // Severe pain + drawPainDescriptionScreen(); + } + break; + + case PAIN_DESCRIPTION: + // Select type of pain description and proceed to daily limitation screen + if (y > 40 && y < 70) { + painDescription = 0; // Changing intensity + drawDailyLimitationScreen(); + } else if (y > 80 && y < 110) { + painDescription = 1; // Constant intensity + drawDailyLimitationScreen(); + } else if (y > 120 && y < 150) { + painDescription = 2; // Stabbing pain + drawDailyLimitationScreen(); + } else if (y > 160 && y < 190) { + painDescription = 3; // Pain when standing + drawDailyLimitationScreen(); + } + break; + + case RESCUE_CONFIRM: + // Confirm or cancel rescue operation + if (x > 20 && x < 60 && y > 80 && y < 120) { + drawInterface(); + } else if (x > 70 && x < 110 && y > 80 && y < 120) { + drawSendingDataScreen(); + } + break; + + case SENDING_DATA: + drawInterface(); // Return to main interface after sending data + break; + + case SURVEY_SENT: + if (x > 80 && x < 120 && y > 80 && y < 100) + drawInterface(); + break; + + case HEART_RATE: + if (x > 20 && x < 60 && y > 80 && y < 120) { + drawInterface(); + } + break; + + case DAILY_LIMITATION: + // Select daily limitation level and start HR measurement screen + if (y > 40 && y < 70) { + dailyLimitation = 0; // No limitation + } else if (y > 80 && y < 110) { + dailyLimitation = 1; // Slightly limiting + } else if (y > 120 && y < 150) { + dailyLimitation = 2; // Moderate limitation + } else if (y > 160 && y < 190) { + dailyLimitation = 3; // Total limitation + } + drawHRMeasurementScreen(); // Proceed to "Measuring HR" screen + break; + + case HR_MEASUREMENT: + if (x > 20 && x < 60 && y > 80 && y < 120) { // Coordinates for purple button + goToPreviousScreen(); // Go back to the previous screen + } + break; + + case HR_ERROR: + if (x > 20 && x < 60 && y > 80 && y < 120) { // Coordinates for purple button in error screen + drawHRMeasurementScreen(); // Retry HR measurement screen + } + break; + + case HR_RESULT: + if (x > 20 && x < 60 && y > 80 && y < 120) { // Left button + drawHRMeasurementScreen(); // Return to HR measurement screen + } else if (x > 80 && x < 120 && y > 80 && y < 120) { // Right button + drawDataConfirmationScreen(); // Proceed to data confirmation screen + } + break; + + case DATA_CONFIRMATION: + // Confirm or cancel data sending + if (x > 20 && x < 60 && y > 80 && y < 120) { + drawInterface(); + } else if (x > 70 && x < 110 && y > 80 && y < 120) { + drawDataSendingScreen(); + } + break; + + default: + break; + } + } + return screenTouched; +} + + +void sendSurveyDataViaBLE() { + // Compile survey data and BPM for BLE transmission + String dataToSend = "BPM: " + String(currentBpm) + + ", Intensidad: " + String(selectedPainLevel) + + ", Descripción: " + String(painDescription) + + ", Limitación: " + String(dailyLimitation); + + const char* alertMsg = dataToSend.c_str(); // Convert data to BLE-compatible format + + if (Bluefruit.connected()) { + // Attempt to send BLE notification with data + if (alertCharacteristic.notify(alertMsg, strlen(alertMsg))) { + Serial.println("Datos de encuesta enviados vÃa BLE"); + drawSurveySentScreen(); // Show "Survey Sent" screen after sending + } else { + Serial.println("Error al enviar los datos de la encuesta"); + drawSurveySentScreen(); // Show "Survey Sent" screen after sending + } + } else { + Serial.println("No hay dispositivos conectados."); + drawSurveySentScreen(); // Show "Survey Sent" screen after sending + } +} + + +void drawButton(int x, int y, int w, int h, const char* text, uint16_t color) { + ucg.setColor(255, 255, 255); // Draw white border for button + ucg.drawRBox(x, y, w, h, 5); + + // Convert RGB565 color to RGB888 + uint8_t r = (color >> 11) & 0x1F; + uint8_t g = (color >> 5) & 0x3F; + uint8_t b = color & 0x1F; + + // Scale color values to 0-255 + r = (r * 255) / 31; + g = (g * 255) / 63; + b = (b * 255) / 31; + + // Set and draw button color with rounded corners + ucg.setColor(r, g, b); + ucg.drawRBox(x + 2, y + 2, w - 4, h - 4, 5); + + // Draw button text in white + ucg.setColor(255, 255, 255); + ucg.setFont(ucg_font_6x10_tr); + int textX = x + (w - ucg.getStrWidth(text)) / 2; + int textY = y + h / 2 + 3; + ucg.setPrintPos(textX, textY); + ucg.print(text); +} + + +void updateHeartRate() { + static unsigned long lastUpdateTime = 0; + int32_t n_heart_rate; + int8_t ch_hr_valid; + float n_spo2, ratio, correl; + int8_t ch_spo2_valid; + int32_t i; + + // Read data from MAX30102 sensor + for (i = 0; i < BUFFER_SIZE; i++) { + while (digitalRead(OXI_INT) == 1); + maxim_max30102_read_fifo((aun_red_buffer + i), (aun_ir_buffer + i)); + } + + // Process heart rate and oxygen saturation data + rf_heart_rate_and_oxygen_saturation(aun_ir_buffer, BUFFER_SIZE, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid, &ratio, &correl); + + if (ch_hr_valid) { + currentBpm = n_heart_rate; + } else { + currentBpm = -1; + } + + // Update display if on the HEART_RATE screen + if (currentScreen == HEART_RATE) { + ucg.setColor(0, 0, 0); // Black to clear previous reading + ucg.drawBox(40, 50, 80, 35); + + ucg.setColor(255, 255, 255); // White for new BPM reading + ucg.setFont(ucg_font_ncenR24_tr); + ucg.setPrintPos(60, 80); + + if (currentBpm >= 0) { + ucg.print(currentBpm); // Display current BPM + } else { + ucg.print(" -"); // Display dash if BPM is invalid + } + } +} + + + + -- GitLab