Files
SC-F001/main/sensors.c
Thaddeus Hughes 49e728ec2b storage overhaul
needs tested tho
2026-01-06 17:01:50 -06:00

196 lines
6.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "sensors.h"
#include "i2c.h"
#include "esp_log.h"
#include "esp_task_wdt.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "storage.h"
// make the compiler shut up about casting an int to a void
#define INT2VOIDP(i) (void*)(uintptr_t)(i)
static const char* TAG = "SENS";
uint8_t sensor_pins[N_SENSORS] = {GPIO_NUM_27, GPIO_NUM_14};
volatile int32_t sensor_count[N_SENSORS] = {0};
static volatile uint64_t sensor_last_isr_time[N_SENSORS] = {0};
static volatile bool sensor_stable_state[N_SENSORS] = {false};
static QueueHandle_t sensor_event_queue = NULL;
// Safety sensor debouncing
static volatile bool safety_tripped = false;
static volatile uint64_t safety_low_start_time = 0;
static volatile uint64_t safety_high_start_time = 0;
#define SAFETY_TRIP_DEBOUNCE_US get_param_value_t(PARAM_SAFETY_BREAK_US).u32
#define SAFETY_UNTRIP_DEBOUNCE_US get_param_value_t(PARAM_SAFETY_BREAK_US).u32
#define DEBOUNCE_TIME_US 2000 // 2 ms debounce (adjust per switch)
#define DEBOUNCE_TICKS pdMS_TO_TICKS(DEBOUNCE_TIME_MS)
typedef struct {
uint8_t sensor_id;
bool level;
} sensor_event_t;
// ISR: Minimal work just record timestamp and forward to queue
static void IRAM_ATTR sensor_isr_handler(void* arg) {
uint32_t gpio_num = (uint32_t)arg;
uint8_t i;
for (i = 0; i < N_SENSORS; i++) {
if (sensor_pins[i] == gpio_num) break;
}
if (i == N_SENSORS) return;
uint64_t now = esp_timer_get_time();
sensor_last_isr_time[i] = now;
sensor_event_t evt = {.sensor_id = i, .level = !gpio_get_level(gpio_num)};
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(sensor_event_queue, &evt, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR();
}
// Debounce task: Processes queue, updates state & count
static void sensor_debounce_task(void* param) {
esp_task_wdt_add(NULL);
sensor_event_t evt;
//static uint64_t last_processed_time[N_SENSORS] = {0};
static bool last_raw_state[N_SENSORS] = {false};
// Initialize stable state
for (uint8_t i = 0; i < N_SENSORS; i++) {
bool level = !gpio_get_level(sensor_pins[i]);
sensor_stable_state[i] = level;
last_raw_state[i] = level;
//last_processed_time[i] = esp_timer_get_time();
}
// Initialize safety sensor
bool safety_current = !gpio_get_level(sensor_pins[SENSOR_SAFETY]);
if (safety_current) {
safety_low_start_time = esp_timer_get_time();
safety_high_start_time = 0;
} else {
safety_low_start_time = 0;
safety_high_start_time = esp_timer_get_time();
}
uint8_t i = 0;
while (1) {
if (xQueueReceive(sensor_event_queue, &evt, pdMS_TO_TICKS(10)) == pdTRUE) {
i = evt.sensor_id;
ESP_LOGI("SENS", "EVENT %d", i);
bool current_raw = !gpio_get_level(sensor_pins[i]);
sensor_stable_state[i] = current_raw;
if (current_raw && !last_raw_state[i]){
ESP_LOGI("SENS", "FALLING");
sensor_count[i]++;
}
if (!current_raw && last_raw_state[i]){
ESP_LOGI("SENS", "RISING");
sensor_count[i]++;
}
last_raw_state[i] = current_raw;
}
// Handle safety sensor debouncing with asymmetric timing
bool safety_current = !gpio_get_level(sensor_pins[SENSOR_SAFETY]);
uint64_t now = esp_timer_get_time();
if (safety_current) {
// Safety sensor is LOW (active)
if (safety_low_start_time == 0) {
// First time going low, start timing
safety_low_start_time = now;
safety_high_start_time = 0;
ESP_LOGI(TAG, "Safety sensor went LOW, starting trip timer");
} else if (!safety_tripped && (now - safety_low_start_time >= SAFETY_TRIP_DEBOUNCE_US)) {
// Been low for 200ms, trip the safety
safety_tripped = true;
i2c_set_safety_status(false);
ESP_LOGW(TAG, "SAFETY TRIPPED - Relays disabled");
}
} else {
// Safety sensor is HIGH (inactive)
if (safety_high_start_time == 0) {
// First time going high, start timing
safety_high_start_time = now;
safety_low_start_time = 0;
ESP_LOGI(TAG, "Safety sensor went HIGH, starting un-trip timer");
} else if (safety_tripped && (now - safety_high_start_time >= SAFETY_UNTRIP_DEBOUNCE_US)) {
// Been high for 300ms, un-trip the safety
safety_tripped = false;
i2c_set_safety_status(true);
ESP_LOGI(TAG, "SAFETY CLEARED - Relays enabled");
}
}
esp_task_wdt_reset();
}
}
esp_err_t sensors_init() {
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << sensor_pins[0]) | (1ULL << sensor_pins[1]),
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_ANYEDGE,
};
ESP_ERROR_CHECK(gpio_config(&io_conf));
sensor_event_queue = xQueueCreate(16, sizeof(sensor_event_t));
if (!sensor_event_queue) {
ESP_LOGE(TAG, "Failed to create sensor queue");
return ESP_FAIL;
}
// Install ISR service
ESP_ERROR_CHECK(gpio_install_isr_service(0));
for (uint8_t i = 0; i < N_SENSORS; i++) {
ESP_ERROR_CHECK(gpio_isr_handler_add(sensor_pins[i], sensor_isr_handler, INT2VOIDP(sensor_pins[i])));
sensor_stable_state[i] = !gpio_get_level(sensor_pins[i]);
}
xTaskCreate(sensor_debounce_task, "SENSORS", 3072, NULL, 6, NULL);
return ESP_OK;
}
esp_err_t sensors_stop() {
for (uint8_t i = 0; i < N_SENSORS; i++) {
gpio_isr_handler_remove(sensor_pins[i]);
}
gpio_uninstall_isr_service();
vQueueDelete(sensor_event_queue);
return ESP_OK;
}
// Public API
bool get_sensor(sensor_t i) {
return sensor_stable_state[i];
}
bool get_safety_sensor(void) {
return !safety_tripped; // Returns true if safe, false if tripped
}
int32_t get_sensor_counter(sensor_t i) {
return sensor_count[i];
}
void set_sensor_counter(sensor_t i, int32_t to) {
sensor_count[i] = to;
}