// Alexander Barrass al855321 5346980
// Application 3
// RTS Summer 2025 EEE 4775
// AI Use: Deepseek in line comments
// --------------------------------------
// Basic #includes for this application
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <driver/gpio.h>
#include <driver/adc.h>
// Pin setup, LED pin 2, Button pin 4, used base example configuration
#define LED_PIN GPIO_NUM_2
#define BUTTON_PIN GPIO_NUM_4
#define LIGHT_SENSOR ADC1_CHANNEL_0
// Smallest log size seems easiest to implement, helped with comparing projects with other students
#define LOG_SIZE 50
SemaphoreHandle_t xButtonSem; //Binary Semaphore declarations
SemaphoreHandle_t xLogMutex;
int lightReadings[LOG_SIZE];
int readingIndex = 0;
int readingsCount = 0;
// ISR button response, based on example code
void IRAM_ATTR button_isr_handler(void* arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xButtonSem, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
// LED Blink Task system uptime monitor
void LedBlinkTask(void *pvParameters) {
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
while(1) {
gpio_set_level(LED_PIN, 1);
vTaskDelay(pdMS_TO_TICKS(1400)); //1400ms tick time to toggle every 1.4s
gpio_set_level(LED_PIN, 0);
vTaskDelay(pdMS_TO_TICKS(1400));
}
}
// Print task runs every 7s to update light sensor reading
void Print_Task(void *pvParameters) {
while(1) {
printf("[Anomaly Containment Monitor] System SECURE - Anomaly emitted light level: %d\n",
lightReadings[(readingIndex - 1 + LOG_SIZE) % LOG_SIZE]);
vTaskDelay(pdMS_TO_TICKS(7000));
}
}
// Light Sensor Task updates the value for our report to display, will be integrated to check eventually
// Deepseek AI assisted me with my own iteration of this task, specifically with Mutex protection on the log
void Sensor_Task(void *pvParameters) {
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(LIGHT_SENSOR, ADC_ATTEN_DB_11);
while(1) {
int reading = adc1_get_raw(LIGHT_SENSOR);
if (xSemaphoreTake(xLogMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
lightReadings[readingIndex] = reading;
readingIndex = (readingIndex + 1) % LOG_SIZE;
if (readingsCount < LOG_SIZE) readingsCount++;
xSemaphoreGive(xLogMutex);
}
vTaskDelay(pdMS_TO_TICKS(200));
}
}
// Logger Task will process our data upon request from button press
void Logger_Task(void *pvParameters) {
while(1) {
// blocks till button press
xSemaphoreTake(xButtonSem, portMAX_DELAY);
// Acknowledge button press
printf("\nCONTAINMENT SYSTEM UPDATE LOG INITIALIZED\n");
//setting sizes and defining measurable values like count
int min = 4096, max = 0, sum = 0;
int currentReadings[LOG_SIZE];
int count = 0;
if (xSemaphoreTake(xLogMutex, pdMS_TO_TICKS(200)) == pdTRUE) {
count = readingsCount;
for (int i = 0; i < count; i++) {
currentReadings[i] = lightReadings[i];
}
xSemaphoreGive(xLogMutex);
}
// sums the readings
for (int i = 0; i < count; i++) {
if (currentReadings[i] < min) min = currentReadings[i];
if (currentReadings[i] > max) max = currentReadings[i];
sum += currentReadings[i];
}
// Print report when button pressed
printf("Security Test Light Report:\n");
printf("Samples: %d, Mininum: %d - Maximum: %d\n", count,min,max);
printf("Average: %.1f\n", (float)sum / count);
printf("\nEND OF LOG UPDATE\n\n");
}
}
void app_main() {
// Initialize button with interrupt
// Pin setup local
gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLUP_ONLY);
gpio_set_intr_type(BUTTON_PIN, GPIO_INTR_NEGEDGE);
gpio_install_isr_service(0);
gpio_isr_handler_add(BUTTON_PIN, button_isr_handler, NULL);
// Synchonization
xButtonSem = xSemaphoreCreateBinary();
xLogMutex = xSemaphoreCreateMutex();
xTaskCreatePinnedToCore(LedBlinkTask, "Uptime", 2048, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(Print_Task, "Print", 4096, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(Sensor_Task, "Sensor", 4096, NULL, 2, NULL, 1);
xTaskCreatePinnedToCore(Logger_Task, "Logger", 4096, NULL, 3, NULL, 1);
// Take semaphore initially so Logger_Task blocks
xSemaphoreTake(xButtonSem, 0);
}