mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 08:41:13 -07:00
129 lines
3.8 KiB
C
129 lines
3.8 KiB
C
/*
|
|
* forgefixture relays (see relays.h).
|
|
*
|
|
* The safety argument lives here: the lid and interlock contacts are
|
|
* normally closed and the button contact normally open, so a line that
|
|
* is low leaves the machine exactly as it is without the fixture. Every
|
|
* line is driven low first thing at boot, after any reset, and by
|
|
* relays_release(); the button is only ever pulsed, its end set by a
|
|
* one-shot timer that is armed before the line goes high.
|
|
*
|
|
* Copyright 2026 514 LLC d/b/a OpenGlow
|
|
* Written by Scott Wiederhold
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
#include "relays.h"
|
|
|
|
#include "driver/gpio.h"
|
|
#include "esp_log.h"
|
|
#include "esp_timer.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/semphr.h"
|
|
|
|
static const char *TAG = "relays";
|
|
|
|
static const gpio_num_t GPIOS[CH_COUNT] = {RELAY_GPIO_LID, RELAY_GPIO_INTERLOCK, RELAY_GPIO_BUTTON};
|
|
|
|
static SemaphoreHandle_t s_lock;
|
|
static esp_timer_handle_t s_pulse_end;
|
|
static bool s_energized[CH_COUNT];
|
|
static bool s_pulsing;
|
|
|
|
static void drive(channel_t ch, bool level)
|
|
{
|
|
gpio_set_level(GPIOS[ch], level ? 1 : 0);
|
|
s_energized[ch] = level;
|
|
}
|
|
|
|
static void pulse_end(void *arg)
|
|
{
|
|
(void)arg;
|
|
xSemaphoreTake(s_lock, portMAX_DELAY);
|
|
drive(CH_BUTTON, false);
|
|
s_pulsing = false;
|
|
xSemaphoreGive(s_lock);
|
|
ESP_LOGI(TAG, "button released");
|
|
}
|
|
|
|
void relays_init(void)
|
|
{
|
|
/* Low before the pins become outputs: the DevKit's pull state at
|
|
* reset is not a relay's idea of off. */
|
|
for (int i = 0; i < CH_COUNT; i++) {
|
|
gpio_reset_pin(GPIOS[i]);
|
|
gpio_set_level(GPIOS[i], 0);
|
|
gpio_set_direction(GPIOS[i], GPIO_MODE_OUTPUT);
|
|
gpio_set_level(GPIOS[i], 0);
|
|
s_energized[i] = false;
|
|
}
|
|
gpio_reset_pin(ENABLE_GPIO_BUTTON);
|
|
gpio_set_direction(ENABLE_GPIO_BUTTON, GPIO_MODE_INPUT);
|
|
gpio_set_pull_mode(ENABLE_GPIO_BUTTON, GPIO_PULLUP_ONLY);
|
|
|
|
s_lock = xSemaphoreCreateMutex();
|
|
const esp_timer_create_args_t args = {
|
|
.callback = pulse_end,
|
|
.name = "button-pulse",
|
|
};
|
|
ESP_ERROR_CHECK(esp_timer_create(&args, &s_pulse_end));
|
|
ESP_LOGI(TAG, "lid GPIO%d, interlock GPIO%d, button GPIO%d (enable jumper GPIO%d): all released",
|
|
RELAY_GPIO_LID, RELAY_GPIO_INTERLOCK, RELAY_GPIO_BUTTON, ENABLE_GPIO_BUTTON);
|
|
}
|
|
|
|
static bool button_enabled(void)
|
|
{
|
|
return gpio_get_level(ENABLE_GPIO_BUTTON) == 0;
|
|
}
|
|
|
|
esp_err_t relays_set_loop(channel_t ch, bool energize)
|
|
{
|
|
if (ch != CH_LID && ch != CH_INTERLOCK)
|
|
return ESP_ERR_INVALID_ARG;
|
|
xSemaphoreTake(s_lock, portMAX_DELAY);
|
|
drive(ch, energize);
|
|
xSemaphoreGive(s_lock);
|
|
ESP_LOGI(TAG, "%s %s", policy_channel_name(ch), policy_state_name(ch, energize));
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t relays_pulse_button(int ms)
|
|
{
|
|
if (!button_enabled())
|
|
return ESP_ERR_NOT_ALLOWED;
|
|
xSemaphoreTake(s_lock, portMAX_DELAY);
|
|
if (s_pulsing) {
|
|
xSemaphoreGive(s_lock);
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
s_pulsing = true;
|
|
/* The end is armed before the line rises. */
|
|
ESP_ERROR_CHECK(esp_timer_start_once(s_pulse_end, (uint64_t)ms * 1000ULL));
|
|
drive(CH_BUTTON, true);
|
|
xSemaphoreGive(s_lock);
|
|
ESP_LOGI(TAG, "button pressed for %d ms", ms);
|
|
return ESP_OK;
|
|
}
|
|
|
|
void relays_release(void)
|
|
{
|
|
xSemaphoreTake(s_lock, portMAX_DELAY);
|
|
esp_timer_stop(s_pulse_end); /* harmless when not running */
|
|
for (int i = 0; i < CH_COUNT; i++)
|
|
drive((channel_t)i, false);
|
|
s_pulsing = false;
|
|
xSemaphoreGive(s_lock);
|
|
ESP_LOGI(TAG, "all released");
|
|
}
|
|
|
|
relays_state_t relays_state(void)
|
|
{
|
|
relays_state_t st;
|
|
xSemaphoreTake(s_lock, portMAX_DELAY);
|
|
for (int i = 0; i < CH_COUNT; i++)
|
|
st.energized[i] = s_energized[i];
|
|
st.button_pulsing = s_pulsing;
|
|
xSemaphoreGive(s_lock);
|
|
st.button_enabled = button_enabled();
|
|
return st;
|
|
}
|