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
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; }
|