diff --git a/include/host_stream/remote_ctrl.h b/include/host_stream/remote_ctrl.h new file mode 100644 index 0000000..919b535 --- /dev/null +++ b/include/host_stream/remote_ctrl.h @@ -0,0 +1,21 @@ +#ifndef REMOTE_CTRL_H +#define REMOTE_CTRL_H + +/* + * remote_ctrl.h — 433MHz SK-RC433A remote control input via GPIO sysfs + * + * gpio65: INPUT — SK-RC433A OUT (interlock mode: HIGH=START, LOW=STOP) + * gpio66: OUTPUT — test LED (blink when START, off when STOP) + */ + +/* Initialize GPIOs and start poll/blink threads. + * Returns 0 on success, -1 on error. */ +int remote_ctrl_init(void); + +/* Stop threads and release GPIO resources. */ +void remote_ctrl_cleanup(void); + +/* Get current remote state: 1=START, 0=STOP. Thread-safe. */ +int remote_ctrl_get_state(void); + +#endif /* REMOTE_CTRL_H */ diff --git a/src/host_stream/kp_firmware.c b/src/host_stream/kp_firmware.c index 6678455..0e08879 100644 --- a/src/host_stream/kp_firmware.c +++ b/src/host_stream/kp_firmware.c @@ -44,6 +44,7 @@ #include "bt_uart.h" #include "can_bus.h" #include "buzzer.h" +#include "remote_ctrl.h" #include "handshake.h" //fifo queue buffer setting @@ -327,6 +328,8 @@ int loadConfig(HOST_STREAM_INIT_OPT_T* pHostStreamInit) can_bus_init(can_spidev, can_speed, (uint32_t)can_id_raw); } buzzer_init(); + if (remote_ctrl_init() != 0) + printf("[FW] WARNING: remote_ctrl_init failed, remote disabled\n"); iniparser_freedict(ini); return 0; @@ -581,6 +584,7 @@ int main (int argc, char* argv[]) EXIT: printf("%s free\n", __func__); + remote_ctrl_cleanup(); free_fec_def_str(); free_stream_init(&HostStreamInit); diff --git a/src/host_stream/remote_ctrl.c b/src/host_stream/remote_ctrl.c new file mode 100644 index 0000000..1ea9238 --- /dev/null +++ b/src/host_stream/remote_ctrl.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include +#include +#include "remote_ctrl.h" + +#define REMOTE_INPUT_GPIO 65 +#define REMOTE_LED_GPIO 66 +#define LED_BLINK_ON_MS 500 +#define LED_BLINK_OFF_MS 500 + +static volatile int s_running = 0; +static volatile int s_remote_start = 0; /* 1=START, 0=STOP */ + +static int s_input_val_fd = -1; /* gpio65 value fd for poll */ +static int s_led_val_fd = -1; /* gpio66 value fd for write */ + +static pthread_t s_poll_tid; +static pthread_t s_led_tid; + +/* ── GPIO sysfs helpers ──────────────────────────────────────────── */ + +static int gpio_setup(int gpio, const char *direction, const char *edge) +{ + char path[64], buf[8]; + int fd; + + /* export */ + fd = open("/sys/class/gpio/export", O_WRONLY); + if (fd >= 0) { + snprintf(buf, sizeof(buf), "%d", gpio); + write(fd, buf, strlen(buf)); + close(fd); + /* EBUSY = already exported, not an error */ + } + + /* direction */ + snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", gpio); + fd = open(path, O_WRONLY); + if (fd < 0) { perror("[RC] direction open"); return -1; } + write(fd, direction, strlen(direction)); + close(fd); + + /* edge (only for input) */ + if (edge) { + snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", gpio); + fd = open(path, O_WRONLY); + if (fd < 0) { perror("[RC] edge open"); return -1; } + write(fd, edge, strlen(edge)); + close(fd); + } + + /* open value fd */ + snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", gpio); + int flags = strcmp(direction, "in") == 0 ? (O_RDONLY | O_NONBLOCK) : O_RDWR; + fd = open(path, flags); + if (fd < 0) perror("[RC] value open"); + return fd; +} + +static void gpio_write(int fd, int value) +{ + if (fd < 0) return; + lseek(fd, 0, SEEK_SET); + write(fd, value ? "1" : "0", 1); +} + +static int gpio_read(int fd) +{ + if (fd < 0) return 0; + char buf[4] = {0}; + lseek(fd, 0, SEEK_SET); + read(fd, buf, 1); + return buf[0] == '1' ? 1 : 0; +} + +/* ── LED blink thread ────────────────────────────────────────────── */ + +static void *led_blink_thread(void *arg) +{ + (void)arg; + printf("[RC] LED blink thread started (gpio%d)\n", REMOTE_LED_GPIO); + + while (s_running) { + if (s_remote_start) { + gpio_write(s_led_val_fd, 1); + usleep(LED_BLINK_ON_MS * 1000); + if (!s_remote_start) { gpio_write(s_led_val_fd, 0); continue; } + gpio_write(s_led_val_fd, 0); + usleep(LED_BLINK_OFF_MS * 1000); + } else { + gpio_write(s_led_val_fd, 0); + usleep(100 * 1000); /* idle: check state every 100ms */ + } + } + + gpio_write(s_led_val_fd, 0); /* ensure LED off on exit */ + printf("[RC] LED blink thread exit\n"); + return NULL; +} + +/* ── Input poll thread ───────────────────────────────────────────── */ + +static void *remote_poll_thread(void *arg) +{ + (void)arg; + struct pollfd pfd; + char dummy[4]; + + pfd.fd = s_input_val_fd; + pfd.events = POLLPRI | POLLERR; + + /* consume initial level so first real edge is not missed */ + lseek(pfd.fd, 0, SEEK_SET); + read(pfd.fd, dummy, sizeof(dummy)); + + s_remote_start = (dummy[0] == '1') ? 1 : 0; + printf("[RC] poll thread started gpio%d initial_state=%s\n", + REMOTE_INPUT_GPIO, s_remote_start ? "START" : "STOP"); + + while (s_running) { + int ret = poll(&pfd, 1, 1000); + if (!s_running) break; + if (!(pfd.revents & POLLPRI)) continue; + + lseek(pfd.fd, 0, SEEK_SET); + read(pfd.fd, dummy, sizeof(dummy)); + + int new_state = (dummy[0] == '1') ? 1 : 0; + if (new_state != s_remote_start) { + s_remote_start = new_state; + printf("[RC] remote state changed: %s\n", + new_state ? "START" : "STOP"); + } + } + + printf("[RC] poll thread exit\n"); + return NULL; +} + +/* ── Public API ──────────────────────────────────────────────────── */ + +int remote_ctrl_init(void) +{ + /* setup input gpio65: direction=in, edge=both */ + s_input_val_fd = gpio_setup(REMOTE_INPUT_GPIO, "in", "both"); + if (s_input_val_fd < 0) { + printf("[RC] ERROR: failed to init input gpio%d\n", REMOTE_INPUT_GPIO); + return -1; + } + + /* setup output gpio66: direction=out, no edge */ + s_led_val_fd = gpio_setup(REMOTE_LED_GPIO, "out", NULL); + if (s_led_val_fd < 0) { + printf("[RC] ERROR: failed to init LED gpio%d\n", REMOTE_LED_GPIO); + close(s_input_val_fd); + s_input_val_fd = -1; + return -1; + } + + s_running = 1; + + if (pthread_create(&s_poll_tid, NULL, remote_poll_thread, NULL) != 0) { + printf("[RC] ERROR: pthread_create poll thread failed\n"); + s_running = 0; + return -1; + } + + if (pthread_create(&s_led_tid, NULL, led_blink_thread, NULL) != 0) { + printf("[RC] ERROR: pthread_create LED thread failed\n"); + s_running = 0; + pthread_join(s_poll_tid, NULL); + return -1; + } + + printf("[RC] remote_ctrl_init OK: input=gpio%d LED=gpio%d\n", + REMOTE_INPUT_GPIO, REMOTE_LED_GPIO); + return 0; +} + +void remote_ctrl_cleanup(void) +{ + s_running = 0; + pthread_join(s_poll_tid, NULL); + pthread_join(s_led_tid, NULL); + + if (s_input_val_fd >= 0) { close(s_input_val_fd); s_input_val_fd = -1; } + if (s_led_val_fd >= 0) { close(s_led_val_fd); s_led_val_fd = -1; } + printf("[RC] remote_ctrl_cleanup done\n"); +} + +int remote_ctrl_get_state(void) +{ + return s_remote_start; +}