/*--------------------------------------------------------------
Application: 03 - Space Systems Edition
Class: Real Time Systems - Su 2025
Author: [Robert Rosario]
Email: [[email protected]]
Company: [University of Central Florida]
AI Use:
- Interrupt handler structure
- Semaphore-based synchronization logic
- Circular buffer implementation
---------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_log.h"
#define LED_PIN GPIO_NUM_2 // Spacecraft status indicator
#define LDR_PIN GPIO_NUM_32 // Stellar light sensor
#define LDR_ADC_CHANNEL ADC1_CHANNEL_4
#define AVG_WINDOW 10 // Sensor smoothing samples
#define SENSOR_THRESHOLD 100 // Lux threshold for space/daylight transition
const char* DARK_MESSAGES[] = {
"Stellar observation optimal - telescope alignment engaged",
"Cosmic radiation nominal - dark matter analysis in progress",
"Orbital night cycle entered - solar panels inactive",
"Deep space conditions detected - switching to infrared sensors"
};
const char* LIGHT_MESSAGES[] = {
"Solar illumination detected - photovoltaic arrays active",
"Daylight conditions - thermal shielding engaged",
"Orbital sunrise - commencing solar observation protocol",
"Direct sunlight exposure - activating coolant systems"
};
void led_task(void *pvParameters) {
bool led_status = false;
while (1) {
led_status = !led_status;
gpio_set_level(LED_PIN, led_status);
vTaskDelay(pdMS_TO_TICKS(500)); // Beacon flash (1Hz)
}
vTaskDelete(NULL);
}
void print_status_task(void *pvParameters) {
TickType_t lastWakeTime = xTaskGetTickCount();
while (1) {
printf("[SPACE SYSTEMS] Station keeping nominal @ %lums\n",
pdTICKS_TO_MS(xTaskGetTickCount()));
vTaskDelayUntil(&lastWakeTime, pdMS_TO_TICKS(1000));
}
vTaskDelete(NULL);
}
void sensor_task(void *pvParameters) {
const float Vsource = 3.3;
const int Rfixed = 10000;
const int ADC_MAX = 4095;
// Precompute constant for Lux calculation (50 * 1000 * 10^0.7)
const double LUX_CONSTANT = 50 * 1000 * pow(10, 0.7);
// Precompute exponent (1/0.7 ≈ 1.42857)
const double LUX_EXPONENT = 1.0 / 0.7;
int raw;
float Vmeasure, Rmeasure;
double lux; // Changed to double for better precision
int luxreadings[AVG_WINDOW] = {0};
int idx = 0;
float sum = 0;
TickType_t lastWakeTime = xTaskGetTickCount();
// Initialize moving average buffer
for(int i = 0; i < AVG_WINDOW; i++) {
raw = adc1_get_raw(LDR_ADC_CHANNEL);
Vmeasure = (raw * Vsource) / ADC_MAX;
Rmeasure = (Vmeasure * Rfixed) / (Vsource - Vmeasure);
// CORRECTED LUX CALCULATION
lux = pow(LUX_CONSTANT / Rmeasure, LUX_EXPONENT);
luxreadings[i] = (int)lux;
sum += luxreadings[i];
}
while (1) {
raw = adc1_get_raw(LDR_ADC_CHANNEL);
Vmeasure = (raw * Vsource) / ADC_MAX;
Rmeasure = (Vmeasure * Rfixed) / (Vsource - Vmeasure);
// CORRECTED LUX CALCULATION
lux = pow(LUX_CONSTANT / Rmeasure, LUX_EXPONENT);
// Update moving average
sum -= luxreadings[idx];
luxreadings[idx] = (int)lux;
sum += luxreadings[idx];
idx = (idx + 1) % AVG_WINDOW;
int avg_lux = (int)(sum / AVG_WINDOW);
// Threshold detection
const char* status = avg_lux < SENSOR_THRESHOLD ? "DARK" : "LIGHT";
ESP_LOGI(TAG, "Environment status: %s - Lux: %d", status, avg_lux);
// Store raw sensor value in log (protected by mutex)
if (xSemaphoreTake(xLogMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
sensor_log[log_index] = raw;
log_index = (log_index + 1) % LOG_BUFFER_SIZE;
total_readings++;
xSemaphoreGive(xLogMutex);
}
vTaskDelayUntil(&lastWakeTime, pdMS_TO_TICKS(SENSOR_PERIOD_MS));
}
vTaskDelete(NULL);
}
void app_main() {
// Initialize LED GPIO
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
// TODO4: INITIALIZED LDR PIN (ADC channels don't need GPIO direction set)
// Note: ADC pins are configured through ADC functions, not GPIO
// TODO5: CONFIGURED ADC width
adc1_config_width(ADC_WIDTH_BIT_12);
// TODO6: CONFIGURED ADC attenuation
adc1_config_channel_atten(LDR_ADC_CHANNEL, ADC_ATTEN_DB_11);
// TODO7: PINNED tasks to core 1
xTaskCreatePinnedToCore(led_task, "STAR_BEACON", 2048, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(print_status_task, "STATUS", 2048, NULL, 2, NULL, 1);
// TODO12: ADDED sensor task with higher priority
xTaskCreatePinnedToCore(sensor_task, "STELLAR_SENSOR", 4096, NULL, 3, NULL, 1);
}