fix(sg2002): share VI debug state between processes

This commit is contained in:
watermeko
2026-07-28 06:09:29 +00:00
committed by Guoguo
parent e4d23014ba
commit 774d314ce9
6 changed files with 238 additions and 87 deletions

Binary file not shown.

View File

@@ -0,0 +1,107 @@
#ifndef VI_STATE_SHARED_HPP_
#define VI_STATE_SHARED_HPP_
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
namespace vi_state_shared {
struct State {
uint32_t dev_fps;
uint32_t fps;
uint32_t width_gt;
uint32_t width_ls;
uint32_t height_gt;
uint32_t height_ls;
};
uint8_t refresh();
namespace detail {
static const char path[] = "/dev/shm/nanokvm_vi_state";
static const uint32_t magic = 0x4e4b5649U;
static const uint32_t version = 1U;
struct SharedState {
uint32_t sequence;
uint32_t magic;
uint32_t version;
uint32_t updated_ms;
State state;
};
inline uint32_t monotonic_ms()
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return (uint32_t)((uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000);
}
inline const SharedState *map_reader()
{
static const SharedState *shared = NULL;
if (shared != NULL) {
return shared;
}
int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
return NULL;
}
struct stat stat_buf;
if (fstat(fd, &stat_buf) != 0 || stat_buf.st_size < (off_t)sizeof(*shared)) {
close(fd);
return NULL;
}
void *addr = mmap(NULL, sizeof(*shared), PROT_READ, MAP_SHARED, fd, 0);
close(fd);
if (addr == MAP_FAILED) {
return NULL;
}
shared = (const SharedState *)addr;
return shared;
}
} // namespace detail
inline bool read(State *state, uint32_t max_age_ms)
{
const detail::SharedState *shared = detail::map_reader();
if (shared == NULL) {
return false;
}
for (int attempt = 0; attempt < 3; attempt++) {
uint32_t sequence = __atomic_load_n(&shared->sequence, __ATOMIC_ACQUIRE);
if (sequence & 1U) {
continue;
}
uint32_t magic = __atomic_load_n(&shared->magic, __ATOMIC_RELAXED);
uint32_t version = __atomic_load_n(&shared->version, __ATOMIC_RELAXED);
uint32_t updated_ms = __atomic_load_n(&shared->updated_ms, __ATOMIC_RELAXED);
State value;
value.dev_fps = __atomic_load_n(&shared->state.dev_fps, __ATOMIC_RELAXED);
value.fps = __atomic_load_n(&shared->state.fps, __ATOMIC_RELAXED);
value.width_gt = __atomic_load_n(&shared->state.width_gt, __ATOMIC_RELAXED);
value.width_ls = __atomic_load_n(&shared->state.width_ls, __ATOMIC_RELAXED);
value.height_gt = __atomic_load_n(&shared->state.height_gt, __ATOMIC_RELAXED);
value.height_ls = __atomic_load_n(&shared->state.height_ls, __ATOMIC_RELAXED);
uint32_t final_sequence = __atomic_load_n(&shared->sequence, __ATOMIC_ACQUIRE);
if (sequence == final_sequence && !(final_sequence & 1U) &&
magic == detail::magic && version == detail::version &&
detail::monotonic_ms() - updated_ms <= max_age_ms) {
*state = value;
return true;
}
}
return false;
}
} // namespace vi_state_shared
#endif // VI_STATE_SHARED_HPP_

View File

@@ -10,6 +10,7 @@
* // free 错内存时会炸的问题
*/
#include "kvm_vision.h"
#include "internal/vi_state_shared.hpp"
#define default_venc_chn 1
@@ -205,71 +206,6 @@ void write_res_to_file(uint16_t _width, uint16_t _height)
system("sync");
}
/* return 0 : VI not init;
* return 1 : HDMI and CSI status are normal;
* return 2 : HDMI abnormal;
* return 3 : CSI abnormal: width too small;
* return 4 : CSI abnormal: width too large;
* return 5 : CSI abnormal: height too small;
* return 6 : CSI abnormal: height too large;
* return 7 : CSI abnormal: Unknown reason;
*/
uint8_t get_vi_state()
{
FILE *fp = fopen("/proc/cvitek/vi_dbg", "r");
if (fp == NULL) {
return 0;
}
unsigned int dev_fps = 0;
unsigned int fps = 0;
unsigned int width_gt = 0;
unsigned int width_ls = 0;
unsigned int height_gt = 0;
unsigned int height_ls = 0;
bool have_dev_fps = false;
bool have_fps = false;
char line[256];
char field[32];
unsigned int value;
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%31s : %u", field, &value) != 2) {
continue;
}
if (strcmp(field, "VIDevFPS") == 0) {
dev_fps = value;
have_dev_fps = true;
} else if (strcmp(field, "VIFPS") == 0) {
fps = value;
have_fps = true;
} else if (strcmp(field, "VICsiCh0WidthGTCnt") == 0) {
width_gt = value;
} else if (strcmp(field, "VICsiCh0WidthLSCnt") == 0) {
width_ls = value;
} else if (strcmp(field, "VICsiCh0HeightGTCnt") == 0) {
height_gt = value;
} else if (strcmp(field, "VICsiCh0HeightLSCnt") == 0) {
height_ls = value;
}
}
fclose(fp);
if (!have_dev_fps || !have_fps) {
return 0;
}
if (dev_fps == 0) {
return 2;
}
if (fps != 0) {
return 1;
}
if (width_gt != 0) return 3;
if (width_ls != 0) return 4;
if (height_gt != 0) return 5;
if (height_ls != 0) return 6;
return 7;
}
int set_hdmi_mode(uint8_t _hdmi_mode)
{
if(_hdmi_mode >= 0 && _hdmi_mode <= 2){
@@ -418,7 +354,7 @@ uint8_t auto_try_res()
uint8_t auto_trying_times = 0;
for (auto_trying_times = 0; auto_trying_times < sizeof(hdmi_res_list)/4; auto_trying_times++){
err_code = get_vi_state();
err_code = vi_state_shared::refresh();
switch(err_code){
case 0:
// shouldn't be possible to run here
@@ -457,8 +393,8 @@ uint8_t auto_try_res()
break;
}
}
if (get_vi_state() == 1) return 1;
if (get_vi_state() == 2) return 2;
if (vi_state_shared::refresh() == 1) return 1;
if (vi_state_shared::refresh() == 2) return 2;
else return 0;
}
@@ -1158,6 +1094,7 @@ void* vi_subsystem_detection(void * arg)
// while(!app::need_exit())
uint8_t while_count_detect_res = 0;
uint8_t while_count_publish_vi_state = 0;
while(true)
{
if(kvmv_cfg.try_exit_thread == 1)
@@ -1169,6 +1106,10 @@ void* vi_subsystem_detection(void * arg)
switch (kvmv_cfg.hdmi_mode){
case 0:
while_count_publish_vi_state = (while_count_publish_vi_state + 1)%100;
if (while_count_publish_vi_state == 1) {
vi_state_shared::refresh();
}
// Switching to Mode 0 requires restarting HDMI (effective only for PCIe version)
// Handling of automatic detection situations
if(get_new_hdmi_mode == 1){
@@ -1324,7 +1265,7 @@ void* vi_subsystem_detection(void * arg)
} else if (kvmv_cfg.vi_detect_state == 2){
// Low-frequency detection of HDMI status, no log output
printf("[kvmv] kvmv_cfg.vi_detect_state == 2\n");
err_code = get_vi_state();
err_code = vi_state_shared::refresh();
if (err_code != 1) {
kvmv_cfg.vi_detect_state = 1;
}
@@ -1345,7 +1286,7 @@ void* vi_subsystem_detection(void * arg)
}
// dbg info
err_code = get_vi_state();
err_code = vi_state_shared::refresh();
switch(err_code){
case 0:
debug("[kvmv] VI not init\n");
@@ -1375,7 +1316,7 @@ void* vi_subsystem_detection(void * arg)
}
} else if (kvmv_cfg.vi_detect_state == 2){
// detection of HDMI status, no log output
err_code = get_vi_state();
err_code = vi_state_shared::refresh();
if (err_code != 1) kvmv_cfg.vi_detect_state = 1;
} else {
kvmv_cfg.vi_detect_state = 1;

View File

@@ -0,0 +1,114 @@
#include "internal/vi_state_shared.hpp"
#include <stdio.h>
#include <string.h>
namespace vi_state_shared {
namespace {
detail::SharedState *map_writer()
{
static detail::SharedState *shared = NULL;
if (shared != NULL) {
return shared;
}
int fd = open(detail::path, O_CREAT | O_RDWR | O_CLOEXEC, 0644);
if (fd < 0) {
return NULL;
}
if (ftruncate(fd, sizeof(*shared)) != 0) {
close(fd);
return NULL;
}
void *addr = mmap(NULL, sizeof(*shared), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
close(fd);
if (addr == MAP_FAILED) {
return NULL;
}
shared = (detail::SharedState *)addr;
return shared;
}
void publish(const State &state)
{
detail::SharedState *shared = map_writer();
if (shared == NULL) {
return;
}
uint32_t sequence = __atomic_load_n(&shared->sequence, __ATOMIC_RELAXED) | 1U;
__atomic_store_n(&shared->sequence, sequence, __ATOMIC_SEQ_CST);
__atomic_store_n(&shared->magic, detail::magic, __ATOMIC_RELAXED);
__atomic_store_n(&shared->version, detail::version, __ATOMIC_RELAXED);
__atomic_store_n(&shared->updated_ms, detail::monotonic_ms(), __ATOMIC_RELAXED);
__atomic_store_n(&shared->state.dev_fps, state.dev_fps, __ATOMIC_RELAXED);
__atomic_store_n(&shared->state.fps, state.fps, __ATOMIC_RELAXED);
__atomic_store_n(&shared->state.width_gt, state.width_gt, __ATOMIC_RELAXED);
__atomic_store_n(&shared->state.width_ls, state.width_ls, __ATOMIC_RELAXED);
__atomic_store_n(&shared->state.height_gt, state.height_gt, __ATOMIC_RELAXED);
__atomic_store_n(&shared->state.height_ls, state.height_ls, __ATOMIC_RELAXED);
__atomic_store_n(&shared->sequence, sequence + 1U, __ATOMIC_RELEASE);
}
} // namespace
/* return 0 : VI not init;
* return 1 : HDMI and CSI status are normal;
* return 2 : HDMI abnormal;
* return 3 : CSI abnormal: width too small;
* return 4 : CSI abnormal: width too large;
* return 5 : CSI abnormal: height too small;
* return 6 : CSI abnormal: height too large;
* return 7 : CSI abnormal: Unknown reason;
*/
uint8_t refresh()
{
FILE *fp = fopen("/proc/cvitek/vi_dbg", "r");
if (fp == NULL) {
return 0;
}
State state = {};
bool have_dev_fps = false;
bool have_fps = false;
char line[256];
char field[32];
unsigned int value;
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%31s : %u", field, &value) != 2) {
continue;
}
if (strcmp(field, "VIDevFPS") == 0) {
state.dev_fps = value;
have_dev_fps = true;
} else if (strcmp(field, "VIFPS") == 0) {
state.fps = value;
have_fps = true;
} else if (strcmp(field, "VICsiCh0WidthGTCnt") == 0) {
state.width_gt = value;
} else if (strcmp(field, "VICsiCh0WidthLSCnt") == 0) {
state.width_ls = value;
} else if (strcmp(field, "VICsiCh0HeightGTCnt") == 0) {
state.height_gt = value;
} else if (strcmp(field, "VICsiCh0HeightLSCnt") == 0) {
state.height_ls = value;
}
}
fclose(fp);
if (!have_dev_fps || !have_fps) {
return 0;
}
publish(state);
if (state.dev_fps == 0) return 2;
if (state.fps != 0) return 1;
if (state.width_gt != 0) return 3;
if (state.width_ls != 0) return 4;
if (state.height_gt != 0) return 5;
if (state.height_ls != 0) return 6;
return 7;
}
} // namespace vi_state_shared

View File

@@ -10,7 +10,7 @@ list(APPEND ADD_INCLUDE
"lib/hdmi"
)
list(APPEND ADD_PRIVATE_INCLUDE "")
list(APPEND ADD_PRIVATE_INCLUDE "../../additional/kvm/include")
append_srcs_dir(ADD_SRCS
"src"

View File

@@ -1,5 +1,6 @@
#include "config.h"
#include "system_state.h"
#include "internal/vi_state_shared.hpp"
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
@@ -239,22 +240,10 @@ void kvm_update_hdmi_state()
static uint8_t check_times = 4;
if(++check_times > 5){
check_times = 0;
FILE *fp = fopen("/proc/cvitek/vi_dbg", "r");
if (fp == NULL) {
return;
vi_state_shared::State state;
if (vi_state_shared::read(&state, 3000U)) {
kvm_sys_state.hdmi_state = state.fps == 0 ? 0 : 1;
}
char line[256];
char field[32];
unsigned int value;
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%31s : %u", field, &value) == 2 &&
strcmp(field, "VIFPS") == 0) {
kvm_sys_state.hdmi_state = value == 0 ? 0 : 1;
break;
}
}
fclose(fp);
}
}