// ctrl_flags.c — runtime feature toggle (UDS) + model mapping // 기존 구조/이름 유지. 경고(-Werror=pedantic, -Werror=conversion) 회피 적용. #include "ctrl_flags.h" #include #include #include #include #include #include #include #include #include #include // ======================== 설정 ======================== #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; }