feat(buzzer): add GPIO64 buzzer module with pattern-based alerts
New buzzer.h/buzzer.c: background pthread drives gpio64 with three patterns (GRASS 500/500ms, ALERT 300/200ms, COLLISION 100/100ms). Integrated into fire_collision_warning(), fire_alert(), and grass state machine in event_recorder.c; buzzer_init() called after can_bus_init() in kp_firmware.c. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fd54f5cc0b
commit
286291fcfd
23
include/host_stream/buzzer.h
Normal file
23
include/host_stream/buzzer.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* buzzer.h — GPIO-driven buzzer control (gpio64)
|
||||
*
|
||||
* Background thread plays a continuous pattern until changed.
|
||||
* Pattern priority (highest wins): COLLISION > ALERT > GRASS > OFF
|
||||
* Callers set the desired pattern; the module handles GPIO toggling.
|
||||
*/
|
||||
|
||||
#ifndef BUZZER_H
|
||||
#define BUZZER_H
|
||||
|
||||
typedef enum {
|
||||
BUZZER_PATTERN_OFF = 0,
|
||||
BUZZER_PATTERN_GRASS = 1, /* 500ms on / 500ms off */
|
||||
BUZZER_PATTERN_ALERT = 2, /* 300ms on / 200ms off */
|
||||
BUZZER_PATTERN_COLLISION = 3, /* 100ms on / 100ms off */
|
||||
} buzzer_pattern_t;
|
||||
|
||||
int buzzer_init(void);
|
||||
void buzzer_set_pattern(buzzer_pattern_t pattern);
|
||||
void buzzer_close(void);
|
||||
|
||||
#endif /* BUZZER_H */
|
||||
151
src/host_stream/buzzer.c
Normal file
151
src/host_stream/buzzer.c
Normal file
@ -0,0 +1,151 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include "buzzer.h"
|
||||
|
||||
#define BUZZER_GPIO 64
|
||||
|
||||
static volatile buzzer_pattern_t s_pattern = BUZZER_PATTERN_OFF;
|
||||
static volatile int s_running = 0;
|
||||
static pthread_t s_tid;
|
||||
static pthread_mutex_t s_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t s_cond = PTHREAD_COND_INITIALIZER;
|
||||
static int s_gpio_fd = -1;
|
||||
|
||||
static void buzzer_gpio_write(int val)
|
||||
{
|
||||
if (s_gpio_fd < 0) return;
|
||||
lseek(s_gpio_fd, 0, SEEK_SET);
|
||||
write(s_gpio_fd, val ? "1" : "0", 1);
|
||||
}
|
||||
|
||||
static int buzzer_gpio_init(void)
|
||||
{
|
||||
char path[64], buf[8];
|
||||
int fd;
|
||||
|
||||
fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
snprintf(buf, sizeof(buf), "%d", BUZZER_GPIO);
|
||||
write(fd, buf, strlen(buf)); /* EBUSY = already exported, ok */
|
||||
close(fd);
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", BUZZER_GPIO);
|
||||
fd = open(path, O_WRONLY);
|
||||
if (fd < 0) { perror("[BUZ] direction open"); return -1; }
|
||||
write(fd, "out", 3);
|
||||
close(fd);
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", BUZZER_GPIO);
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < 0) { perror("[BUZ] value open"); return -1; }
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void msleep(int ms)
|
||||
{
|
||||
struct timespec ts = { ms / 1000, (ms % 1000) * 1000000L };
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
static void cond_timedwait_ms(int ms)
|
||||
{
|
||||
struct timespec abs;
|
||||
clock_gettime(CLOCK_REALTIME, &abs);
|
||||
abs.tv_sec += ms / 1000;
|
||||
abs.tv_nsec += (ms % 1000) * 1000000L;
|
||||
if (abs.tv_nsec >= 1000000000L) { abs.tv_sec++; abs.tv_nsec -= 1000000000L; }
|
||||
pthread_cond_timedwait(&s_cond, &s_mtx, &abs);
|
||||
}
|
||||
|
||||
static void *buzzer_thread(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
printf("[BUZ] thread started gpio%d\n", BUZZER_GPIO);
|
||||
|
||||
pthread_mutex_lock(&s_mtx);
|
||||
while (s_running) {
|
||||
buzzer_pattern_t pat = s_pattern;
|
||||
pthread_mutex_unlock(&s_mtx);
|
||||
|
||||
switch (pat) {
|
||||
case BUZZER_PATTERN_GRASS:
|
||||
buzzer_gpio_write(1);
|
||||
msleep(500);
|
||||
buzzer_gpio_write(0);
|
||||
pthread_mutex_lock(&s_mtx);
|
||||
if (s_pattern == pat) cond_timedwait_ms(500);
|
||||
break;
|
||||
|
||||
case BUZZER_PATTERN_ALERT:
|
||||
buzzer_gpio_write(1);
|
||||
msleep(300);
|
||||
buzzer_gpio_write(0);
|
||||
pthread_mutex_lock(&s_mtx);
|
||||
if (s_pattern == pat) cond_timedwait_ms(200);
|
||||
break;
|
||||
|
||||
case BUZZER_PATTERN_COLLISION:
|
||||
buzzer_gpio_write(1);
|
||||
msleep(100);
|
||||
buzzer_gpio_write(0);
|
||||
pthread_mutex_lock(&s_mtx);
|
||||
if (s_pattern == pat) cond_timedwait_ms(100);
|
||||
break;
|
||||
|
||||
default: /* BUZZER_PATTERN_OFF */
|
||||
buzzer_gpio_write(0);
|
||||
pthread_mutex_lock(&s_mtx);
|
||||
if (s_pattern == BUZZER_PATTERN_OFF)
|
||||
pthread_cond_wait(&s_cond, &s_mtx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&s_mtx);
|
||||
|
||||
buzzer_gpio_write(0);
|
||||
printf("[BUZ] thread exit\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int buzzer_init(void)
|
||||
{
|
||||
s_gpio_fd = buzzer_gpio_init();
|
||||
if (s_gpio_fd < 0)
|
||||
printf("[BUZ] WARNING: gpio init failed, buzzer disabled\n");
|
||||
|
||||
s_running = 1;
|
||||
if (pthread_create(&s_tid, NULL, buzzer_thread, NULL) != 0) {
|
||||
perror("[BUZ] pthread_create");
|
||||
s_running = 0;
|
||||
return -1;
|
||||
}
|
||||
pthread_setname_np(s_tid, "buzzer");
|
||||
printf("[BUZ] init done gpio%d\n", BUZZER_GPIO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void buzzer_set_pattern(buzzer_pattern_t pattern)
|
||||
{
|
||||
pthread_mutex_lock(&s_mtx);
|
||||
if (s_pattern != pattern) {
|
||||
s_pattern = pattern;
|
||||
pthread_cond_signal(&s_cond);
|
||||
}
|
||||
pthread_mutex_unlock(&s_mtx);
|
||||
}
|
||||
|
||||
void buzzer_close(void)
|
||||
{
|
||||
pthread_mutex_lock(&s_mtx);
|
||||
s_running = 0;
|
||||
pthread_cond_signal(&s_cond);
|
||||
pthread_mutex_unlock(&s_mtx);
|
||||
pthread_join(s_tid, NULL);
|
||||
if (s_gpio_fd >= 0) { close(s_gpio_fd); s_gpio_fd = -1; }
|
||||
}
|
||||
@ -41,6 +41,7 @@
|
||||
#include "event_recorder.h"
|
||||
#include "bt_uart.h"
|
||||
#include "can_bus.h"
|
||||
#include "buzzer.h"
|
||||
#include "stdc_post_process.h" /* THR_*_COLLISION constants */
|
||||
|
||||
/* ── External (from kdp2_host_stream.c) ──────────────────────────────────── */
|
||||
@ -440,6 +441,7 @@ void fire_collision_warning(int level, const char *type)
|
||||
.keepalive_interval_ms = 0 };
|
||||
can_bus_send_control_cmd(&ctrl);
|
||||
printf("[EVT-CAN] collision_warning speed=%d (level=%d)\n", speed, level);
|
||||
buzzer_set_pattern(level ? BUZZER_PATTERN_COLLISION : BUZZER_PATTERN_OFF);
|
||||
}
|
||||
bt_uart_send_json(json);
|
||||
printf("[EVT] collision_warning level=%d type=%s\n", level, type ? type : "null");
|
||||
@ -471,6 +473,7 @@ static void fire_alert(int left_level, const char *left_type,
|
||||
.keepalive_interval_ms = 0 };
|
||||
can_bus_send_control_cmd(&ctrl);
|
||||
printf("[EVT-CAN] alert speed=%d (left=%d right=%d)\n", speed, left_level, right_level);
|
||||
buzzer_set_pattern((left_level || right_level) ? BUZZER_PATTERN_ALERT : BUZZER_PATTERN_OFF);
|
||||
}
|
||||
bt_uart_send_json(json);
|
||||
printf("[EVT] alert left=%d(%s) right=%d(%s)\n",
|
||||
@ -694,6 +697,7 @@ void event_recorder_update(const stdc_analysis_t *ana)
|
||||
grass_enter_level(1);
|
||||
speed_val = SPEED_LIMIT_STOP;
|
||||
msg_send("/tmp/canbus/c0/command.fifo", "host_stream", "setSpeed",&speed_val, sizeof(speed_val), 0);
|
||||
buzzer_set_pattern(BUZZER_PATTERN_GRASS);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -708,11 +712,14 @@ void event_recorder_update(const stdc_analysis_t *ana)
|
||||
grass_enter_level(2);
|
||||
speed_val = SPEED_LIMIT_STOP;
|
||||
msg_send("/tmp/canbus/c0/command.fifo", "host_stream", "setSpeed",&speed_val, sizeof(speed_val), 0);
|
||||
buzzer_set_pattern(BUZZER_PATTERN_GRASS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
speed_val = SPEED_LIMIT_NORMAL;
|
||||
msg_send("/tmp/canbus/c0/command.fifo", "host_stream", "setSpeed",&speed_val, sizeof(speed_val), 0);
|
||||
if (!g_last_collision_warning && !g_last_left_alert && !g_last_right_alert)
|
||||
buzzer_set_pattern(BUZZER_PATTERN_OFF);
|
||||
if (elapsed_ms_tv(&g_grass.t_last_active) >= GRASS_EXIT_HYSTERESIS_MS) {
|
||||
g_grass.state = GRASS_DONE;
|
||||
gettimeofday(&g_grass.t_done, NULL);
|
||||
@ -742,6 +749,8 @@ void event_recorder_update(const stdc_analysis_t *ana)
|
||||
} else {
|
||||
speed_val = SPEED_LIMIT_NORMAL;
|
||||
msg_send("/tmp/canbus/c0/command.fifo", "host_stream", "setSpeed",&speed_val, sizeof(speed_val), 0);
|
||||
if (!g_last_collision_warning && !g_last_left_alert && !g_last_right_alert)
|
||||
buzzer_set_pattern(BUZZER_PATTERN_OFF);
|
||||
if (elapsed_ms_tv(&g_grass.t_last_active) >= GRASS_EXIT_HYSTERESIS_MS) {
|
||||
g_grass.state = GRASS_DONE;
|
||||
gettimeofday(&g_grass.t_done, NULL);
|
||||
@ -761,9 +770,12 @@ void event_recorder_update(const stdc_analysis_t *ana)
|
||||
gettimeofday(&g_grass.t_last_active, NULL);
|
||||
speed_val = SPEED_LIMIT_STOP;
|
||||
msg_send("/tmp/canbus/c0/command.fifo", "host_stream", "setSpeed",&speed_val, sizeof(speed_val), 0);
|
||||
buzzer_set_pattern(BUZZER_PATTERN_GRASS);
|
||||
} else {
|
||||
speed_val = SPEED_LIMIT_NORMAL;
|
||||
msg_send("/tmp/canbus/c0/command.fifo", "host_stream", "setSpeed",&speed_val, sizeof(speed_val), 0);
|
||||
if (!g_last_collision_warning && !g_last_left_alert && !g_last_right_alert)
|
||||
buzzer_set_pattern(BUZZER_PATTERN_OFF);
|
||||
if (elapsed_ms_tv(&g_grass.t_last_active) >= GRASS_EXIT_HYSTERESIS_MS) {
|
||||
g_grass.state = GRASS_DONE;
|
||||
gettimeofday(&g_grass.t_done, NULL);
|
||||
@ -784,6 +796,8 @@ void event_recorder_update(const stdc_analysis_t *ana)
|
||||
* (keepalive in can_bus.c also maintains this every 200ms). */
|
||||
speed_val = SPEED_LIMIT_NORMAL;
|
||||
msg_send("/tmp/canbus/c0/command.fifo", "host_stream", "setSpeed",&speed_val, sizeof(speed_val), 0);
|
||||
if (!g_last_collision_warning && !g_last_left_alert && !g_last_right_alert)
|
||||
buzzer_set_pattern(BUZZER_PATTERN_OFF);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
#include "event_recorder.h"
|
||||
#include "bt_uart.h"
|
||||
#include "can_bus.h"
|
||||
#include "buzzer.h"
|
||||
#include "handshake.h"
|
||||
|
||||
//fifo queue buffer setting
|
||||
@ -297,6 +298,7 @@ int loadConfig(HOST_STREAM_INIT_OPT_T* pHostStreamInit)
|
||||
if (can_enable)
|
||||
can_bus_init(can_spidev, can_speed, (uint32_t)can_id_raw);
|
||||
}
|
||||
buzzer_init();
|
||||
|
||||
iniparser_freedict(ini);
|
||||
return 0;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user