You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
5.4 KiB

7 months ago
// ctrl_flags.c — runtime feature toggle (UDS) + model mapping
// 기존 구조/이름 유지. 경고(-Werror=pedantic, -Werror=conversion) 회피 적용.
#include "ctrl_flags.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <unistd.h>
// ======================== 설정 ========================
#define CTRL_SOCK_PATH "/tmp/ctrl_feat.sock"
// ======================== 전역 ========================
uint32_t g_feat_mask = 0;
// 내부 모델 비트(고정)
typedef enum {
NETWORK_OBJDET = 0,
NETWORK_ABNORM = 1,
NETWORK_FIRE = 2,
NETWORK_LPR = 3,
NETWORK_FACE = 4,
NETWORK_COUNT
} ctrl_model_e;
static const uint32_t k_feat2model[FEAT__COUNT] = {
/* FEAT_OBJDET */ BIT(NETWORK_OBJDET),
/* FEAT_ABNORM */ BIT(NETWORK_OBJDET) | BIT(NETWORK_ABNORM),
/* FEAT_CROWD */ BIT(NETWORK_OBJDET),
/* FEAT_FIRE */ BIT(NETWORK_FIRE),
/* FEAT_LPR */ BIT(NETWORK_OBJDET) | BIT(NETWORK_LPR),
/* FEAT_FACEATTR */ BIT(NETWORK_OBJDET) | BIT(NETWORK_FACE),
/* FEAT_VIPTRACK */ BIT(NETWORK_OBJDET) | BIT(NETWORK_FACE)
};
// ======================== 공개 API ========================
uint32_t ctrl_active_models_acquire(void){
uint32_t f = g_feat_mask;
uint32_t m = 0;
for (int i = 0; i < (int)FEAT__COUNT; i++){
if (f & BIT(i)) m |= k_feat2model[i];
}
return m;
}
uint32_t ctrl_active_features_peek(void){
return g_feat_mask;
}
void ctrl_feature_on(ctrl_feat_e f){
g_feat_mask |= BIT(f);
}
void ctrl_feature_off(ctrl_feat_e f){
g_feat_mask &= ~BIT(f);
}
void ctrl_feature_all_off(void){
g_feat_mask = 0;
}
// ======================== UDS 제어부 ========================
// dprintf 대체(버퍼 → write_all)
static ssize_t write_all_ctrl(int fd, const void* buf, size_t n){
const char* p = (const char*)buf; size_t sent = 0;
while (sent < n){
ssize_t r = write(fd, p + sent, n - sent);
if (r < 0){ if (errno == EINTR) continue; return r; }
if (r == 0) break;
sent += (size_t)r;
}
return (ssize_t)sent;
}
static void sendf(int fd, const char* fmt, ...){
char b[128];
va_list ap; va_start(ap, fmt);
int n = vsnprintf(b, sizeof(b), fmt, ap);
va_end(ap);
if (n < 0) return;
size_t len = (size_t)((n >= (int)sizeof(b)) ? (int)sizeof(b)-1 : n);
(void)write_all_ctrl(fd, b, len);
}
// "OBJDET" 등 문자열 → enum
static int feat_from_str(const char* s, ctrl_feat_e* out){
if (!s || !out) return -1;
char t[32] = {0};
int n = 0;
while (s[n] && n < (int)sizeof(t) - 1){
t[n] = (char)toupper((unsigned char)s[n]); // -Wconversion 회피
n++;
}
if (!strcmp(t,"OBJDET")) *out = FEAT_OBJDET;
else if (!strcmp(t,"ABNORM")) *out = FEAT_ABNORM;
else if (!strcmp(t,"CROWD")) *out = FEAT_CROWD;
else if (!strcmp(t,"FIRE")) *out = FEAT_FIRE;
else if (!strcmp(t,"LPR")) *out = FEAT_LPR;
else if (!strcmp(t,"FACEATTR")) *out = FEAT_FACEATTR;
else if (!strcmp(t,"VIPTRACK")) *out = FEAT_VIPTRACK;
else return -1;
return 0;
}
static void reply_status(int cfd){
uint32_t f = g_feat_mask;
uint32_t m = ctrl_active_models_acquire();
sendf(cfd, "FEAT_MASK=0x%08X MODELS=0x%08X\n", f, m);
}
static void handle_line(int cfd, char* line){
while (*line==' ' || *line=='\t') line++;
char cmd[32] = {0}, arg[32] = {0};
(void)sscanf(line, "%31s %31s", cmd, arg);
for (int i=0; cmd[i]; ++i) cmd[i] = (char)toupper((unsigned char)cmd[i]);
if (!strcmp(cmd,"ON")){
ctrl_feat_e f; if (feat_from_str(arg, &f) == 0){
g_feat_mask |= BIT(f);
reply_status(cfd); return;
}
sendf(cfd, "ERR unknown feature\n"); return;
}
if (!strcmp(cmd,"OFF")){
ctrl_feat_e f; if (feat_from_str(arg, &f) == 0){
g_feat_mask &= ~BIT(f);
reply_status(cfd); return;
}
sendf(cfd, "ERR unknown feature\n"); return;
}
if (!strcmp(cmd,"ALL_OFF")){
g_feat_mask = 0;
reply_status(cfd); return;
}
if (!strcmp(cmd,"MASK")){
unsigned v = 0;
if (sscanf(arg, "%x", &v) == 1){
g_feat_mask = v;
reply_status(cfd); return;
}
sendf(cfd, "ERR bad mask\n"); return;
}
if (!strcmp(cmd,"STATUS")){ reply_status(cfd); return; }
sendf(cfd, "ERR unknown cmd\n");
}
static void* ctrl_uds_thread(void*){
(void)sizeof(NETWORK_COUNT); // unused 경고 방지용 no-op
unlink(CTRL_SOCK_PATH);
int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd < 0) return NULL;
struct sockaddr_un sa;
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX; // 지정초기화 금지 → 대입
strncpy(sa.sun_path, CTRL_SOCK_PATH, sizeof(sa.sun_path)-1);
if (bind(sfd, (struct sockaddr*)&sa, sizeof(sa)) < 0) { close(sfd); return NULL; }
(void)chmod(CTRL_SOCK_PATH, 0777);
if (listen(sfd, 4) < 0) { close(sfd); return NULL; }
for(;;){
int cfd = accept(sfd, NULL, NULL);
if (cfd < 0){
if (errno == EINTR) continue;
if (errno == EBADF) break;
continue;
}
char buf[128];
ssize_t rn = read(cfd, buf, sizeof(buf)-1); // ssize_t 사용
if (rn > 0){ buf[rn] = 0; handle_line(cfd, buf); }
close(cfd);
}
close(sfd);
unlink(CTRL_SOCK_PATH);
return NULL;
}
int ctrl_uds_start(void){
pthread_t th;
int rc = pthread_create(&th, NULL, ctrl_uds_thread, NULL);
if (rc != 0) return -1;
pthread_detach(th);
return 0;
}
uint32_t ctrl_feat_mask_snapshot(void){ return g_feat_mask; }