/* --------------------------------------------------------------
Application: 03 - Rev2 - Space Systems Edition
Class: Real Time Systems - Su 2025
Author: [Robert Rosario]
Email: [[email protected]]
Company: [University of Central Florida]
AI Use:
-Logger task output formatting
-Button ISR implementation
-Core pinning structure
---------------------------------------------------------------*/
#include <stdio.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "freertos/semphr.h"
// Hardware Configuration
#define LED_PIN GPIO_NUM_2
#define BUTTON_PIN GPIO_NUM_4
#define LDR_PIN GPIO_NUM_32
#define LDR_ADC_CHANNEL ADC1_CHANNEL_4
// System Parameters
#define LED_BLINK_INTERVAL_MS 1400 // 1.4 second blink
#define CONSOLE_PRINT_INTERVAL_MS 7000
#define SENSOR_READ_INTERVAL_MS 500
#define LOG_BUFFER_SIZE 50
#define SENSOR_THRESHOLD 100
// LDR Calculation Constants (Added for lux calculations)
#define LDR_VOLTAGE_SOURCE 3.3f
#define LDR_FIXED_RESISTOR 10000
#define LDR_LOAD_RESISTOR 50
#define LDR_ADC_MAX 4095
#define LDR_GAMMA 0.7f
// Global Variables
int sensorLog[LOG_BUFFER_SIZE]; // Now stores lux values instead of raw ADC
int logIndex = 0;
int totalReadings = 0;
SemaphoreHandle_t buttonSemaphore;
// Space-themed messages
const char* STATUS_MESSAGES[] = {
"Orbital systems nominal",
"Power levels stable",
"Thermal regulation active",
"Communication link established"
};
// LED Blink Task (Priority 1)
void led_task(void *pvParameters) {
bool led_state = false;
while (1) {
led_state = !led_state;
gpio_set_level(LED_PIN, led_state);
vTaskDelay(pdMS_TO_TICKS(LED_BLINK_INTERVAL_MS / 2));
}
}
// Console Print Task (Priority 1)
void console_print_task(void *pvParameters) {
int message_index = 0;
TickType_t lastWakeTime = xTaskGetTickCount();
while (1) {
printf("\n[SPACE SYSTEMS] %s | Uptime: %lums\n",
STATUS_MESSAGES[message_index],
pdTICKS_TO_MS(xTaskGetTickCount()));
message_index = (message_index + 1) % (sizeof(STATUS_MESSAGES)/sizeof(STATUS_MESSAGES[0]));
vTaskDelayUntil(&lastWakeTime, pdMS_TO_TICKS(CONSOLE_PRINT_INTERVAL_MS));
}
}
// Light Sensor Task (Priority 2) WITH YOUR LUX CALCULATIONS ADDED BACK
void light_sensor_task(void *pvParameters) {
TickType_t lastWakeTime = xTaskGetTickCount();
while (1) {
// Read sensor and convert to lux (YOUR CALCULATION)
int raw = adc1_get_raw(LDR_ADC_CHANNEL);
float voltage = (raw * LDR_VOLTAGE_SOURCE) / LDR_ADC_MAX;
float ldrResistance = (voltage * LDR_FIXED_RESISTOR) / (LDR_VOLTAGE_SOURCE - voltage);
float lux = (LDR_LOAD_RESISTOR * 1000 * powf(10, LDR_GAMMA)) / ldrResistance * (1/LDR_GAMMA);
// Store lux value in circular buffer
sensorLog[logIndex] = (int)lux;
logIndex = (logIndex + 1) % LOG_BUFFER_SIZE;
totalReadings++;
vTaskDelayUntil(&lastWakeTime, pdMS_TO_TICKS(SENSOR_READ_INTERVAL_MS));
}
}
// Button ISR Handler
void IRAM_ATTR button_isr_handler(void* arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(buttonSemaphore, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
// Button-Triggered Logger Task (Priority 3) - Updated for lux values
void logger_task(void *pvParameters) {
while (1) {
// Wait for button press
xSemaphoreTake(buttonSemaphore, portMAX_DELAY);
printf("\n=== SENSOR DATA DUMP ===\n");
// Calculate statistics
int min = INT_MAX, max = 0, sum = 0;
int validReadings = (totalReadings < LOG_BUFFER_SIZE) ? totalReadings : LOG_BUFFER_SIZE;
for (int i = 0; i < validReadings; i++) {
int idx = (logIndex - validReadings + i + LOG_BUFFER_SIZE) % LOG_BUFFER_SIZE;
int lux = sensorLog[idx]; // Now using lux values
if (lux < min) min = lux;
if (lux > max) max = lux;
sum += lux;
}
float avg = (float)sum / validReadings;
// Print compressed log (now in lux units)
printf("Compressed %d readings (in lux):\n", validReadings);
printf("Min: %d, Max: %d, Avg: %.1f\n", min, max, avg);
printf("Threshold crossings: %d/%d (Threshold: %d lux)\n",
(int)(avg > SENSOR_THRESHOLD), validReadings, SENSOR_THRESHOLD);
printf("=== END DUMP ===\n\n");
}
}
void app_main() {
// Initialize hardware
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
// Button setup with interrupt
gpio_reset_pin(BUTTON_PIN);
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);
// ADC setup
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(LDR_ADC_CHANNEL, ADC_ATTEN_DB_11);
// Create semaphore
buttonSemaphore = xSemaphoreCreateBinary();
xSemaphoreTake(buttonSemaphore, 0); // Start with semaphore taken
// Create tasks (all on Core 1)
xTaskCreatePinnedToCore(led_task, "LED_Task", 2048, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(console_print_task, "Console_Task", 2048, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(light_sensor_task, "Sensor_Task", 2048, NULL, 2, NULL, 1);
xTaskCreatePinnedToCore(logger_task, "Logger_Task", 2048, NULL, 3, NULL, 1);
printf("Space Systems Monitor Initialized\n");
}