/* --------------------------------------------------------------
Application: 02
Release Type: Baseline Multitask Skeleton Starter Code
Class: Real Time Systems - Su 2025
AI Use: Commented inline
---------------------------------------------------------------*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include <math.h>
#define LDR_PIN GPIO_NUM_32
#define LDR_ADC_CHANNEL ADC1_CHANNEL_4
#define LED_PIN GPIO_NUM_2 // Using GPIO2 for the LED
#define AVG_WINDOW 10
#define SENSOR_THRESHOLD 500
// Task to blink an LED at 2 Hz (500 ms period: 250 ms ON, 250 ms OFF)
void blink_task(void *pvParameters) {
bool led_status = false;
TickType_t currentTime = pdTICKS_TO_MS( xTaskGetTickCount() );
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
while (1) {
currentTime = pdTICKS_TO_MS( xTaskGetTickCount() );
gpio_set_level(LED_PIN, 1); //TODO: Set LED pin high or low based on led_status flag;
led_status = led_status; //TODO: toggle state for next loop
// printf("LED Cycle %s @ %lu\n", led_status ? "ON" : "OFF", currentTime);
vTaskDelay(pdMS_TO_TICKS(500)); // Delay for 500 ms using MS to Ticks Function vs alternative which is MS / ticks per ms
gpio_set_level(LED_PIN, 0);
vTaskDelay(pdMS_TO_TICKS(500));
}
vTaskDelete(NULL); // We'll never get here; tasks run forever
}
// Task to print a message every 10000 ms (10 seconds)
void print_task(void *pvParameters) {
TickType_t currentTime = pdTICKS_TO_MS( xTaskGetTickCount() );
TickType_t previousTime = 0;
while (1) {
previousTime = currentTime;
currentTime = pdTICKS_TO_MS( xTaskGetTickCount() );
// Prints a periodic message based on a thematic area. Output a timestamp (ms) and period (ms)
//printf("I'm up and running @ time %lu [period = %lu]!\n",currentTime, currentTime-previousTime);
printf("SECURITY SYSTEM ONLINE @ time %lu [period = %lu]!\n",currentTime, currentTime-previousTime); //Theme customization
vTaskDelay(pdMS_TO_TICKS(1000)); // Delay for 1000 ms
}
vTaskDelete(NULL); // We'll never get here; tasks run forever
}
void sensor_task(void *pvParameters) {
//TODO110 Configure ADC (12-bit width, 0-3.3V range with 11dB attenuation)
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(LDR_ADC_CHANNEL, ADC_ATTEN_DB_11); //could be ADC_ATTEN_DB_11
// Variables to compute LUX
int raw;
float Vmeasure = 0.;
float Rmeasure = 0.;
float lux = 0.;
// Variables for moving average
int luxreadings[AVG_WINDOW] = {0};
int idx = 0;
float sum = 0;
//TODO11a consider where AVG_WINDOW is defined, it could be here, or global value
//See TODO 99
// Pre-fill the readings array with an initial sample to avoid startup anomaly
for(int i = 0; i < AVG_WINDOW; ++i) {
raw = adc1_get_raw(LDR_ADC_CHANNEL);
Vmeasure = raw/(4096*3.3); //TODO11b correct this with the equation seen earlier
Rmeasure = (2000*Vmeasure)/(1-(Vmeasure/3.3)); //TODO11c correct this with the equation seen earlier
lux = pow((pow(50*10000*10, 0.7)/Rmeasure), 1/0.7); //TODO11d correct this with the equation seen earlier
luxreadings[i] = lux;
sum += luxreadings[i];
}
const TickType_t periodTicks = pdMS_TO_TICKS(500); // e.g. 500 ms period
TickType_t lastWakeTime = xTaskGetTickCount(); // initialize last wake time
while (1) {
// Read current sensor value
raw = adc1_get_raw(LDR_ADC_CHANNEL);
//printf("**raw **: Sensor %d\n", raw);
// Compute LUX
Vmeasure = raw/(4096*3.3); //TODO11e correct this with the equation seen earlier
Rmeasure = (2000*Vmeasure)/(1-(Vmeasure/3.3)); //TODO11f correct this with the equation seen earlier
lux = pow((pow(50*10000*10, 0.7)/Rmeasure), 1/0.7); //TODO11g correct this with the equation seen earlier
// Update moving average buffer
sum -= luxreadings[idx]; // remove oldest value from sum
luxreadings[idx] = lux; // place new reading
sum += lux; // add new value to sum
idx = (idx + 1) % AVG_WINDOW;
int avg = sum / AVG_WINDOW; // compute average
//TODO11h Check threshold and print alert if exceeded or below based on context
if (avg >= SENSOR_THRESHOLD) { //if avg goes above 500, alert
//printf("**Alert**: Sensor average %d exceeds threshold %d!\n ", avg, SENSOR_THRESHOLD);
printf("**ALERT**: SECURITY BREACH: Sensor average %d exceeds threshold %d!\n ", avg, SENSOR_THRESHOLD); // Theme customization
} else {
//TODO11i
// (you could print the avg value for debugging)
//printf("avg = %d\n", avg);
}
//TODO11j: Print out time period [to help with answering Eng/Analysis quetionst (hint check Application Solution #1 )
vTaskDelayUntil(&lastWakeTime, periodTicks);
//https://wokwi.com/projects/430683087703949313
//TODO11k Replace vTaskDelay with vTaskDelayUntil with parameters &lastWakeTime and periodTicks
// vTaskDelay(periodTicks);
}
}
void app_main() {
// Initialize LED GPIO
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
gpio_reset_pin(LDR_PIN);
gpio_set_direction(LDR_PIN, GPIO_MODE_INPUT);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(LDR_ADC_CHANNEL, ADC_ATTEN_DB_11);
// Instantiate/ Create tasks:
// . pointer to task function,
// . descriptive name, [has a max length; located in the FREERTOS_CONFIG.H]
// . stack depth,
// . parameters [optional] = NULL
// . priority [0 = low],
// . pointer referencing this created task [optional] = NULL
// Learn more here https://www.freertos.org/Documentation/02-Kernel/04-API-references/01-Task-creation/01-xTaskCreate
xTaskCreatePinnedToCore(sensor_task, "Sensor Task", 4096, NULL, 1, NULL,1);
xTaskCreatePinnedToCore(blink_task, "Blink Task", 2048, NULL, 3, NULL, 1);
xTaskCreatePinnedToCore(print_task, "Print Task", 2048, NULL, 2, NULL, 1);
//Setting different priorities: xTaskCreate(print_task, "Print Task", 2048, NULL, 2, NULL);
}