mirror of
https://github.com/sipeed/NanoKVM.git
synced 2026-09-11 00:22:56 -05:00
fix(sg2002): share VI debug state between processes
This commit is contained in:
Binary file not shown.
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
114
support/sg2002/additional/kvm/src/vi_state_shared.cpp
Normal file
114
support/sg2002/additional/kvm/src/vi_state_shared.cpp
Normal 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
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user