简体   繁体   English

如何在从 Linux 启动时将 NCurses 输出定向到串行终端?

[英]How to direct NCurses output to a serial terminal on boot from Linux?

Overview概述

I have been writing code to display menus and screens using the ncurses++ library.我一直在编写代码来使用 ncurses++ 库显示菜单和屏幕。 The desired result is to have these menus and screens output across a serial terminal interface.期望的结果是通过串行终端接口输出这些菜单和屏幕。

Current Attempts当前尝试

I can successfully do this using the base C ncurses library using calls.我可以使用调用的基本 C ncurses 库成功地做到这一点。

if( (FDTERM = fopen("/dev/ttyS0", "r+")) != NULL )
{

  if(FDTERM == NULL)
  {
    fprintf(stderr, "Error opening device: %s.\n", ncurses_device); 
  }

  /* Set Screen */
  MY_SCREEN = newterm(NULL, FDTERM, FDTERM);

  if(MY_SCREEN != NULL)
  {
    /* Set the terminal */
    set_term(MY_SCREEN);
  }
}

and for getting this to work in c++ I wrote some intercept.c code to override what the call to ::initscr() in cursesw.cc actually calls to为了让它在 C++ 中工作,我写了一些拦截.c 代码来覆盖在 cursesw.cc 中对 ::initscr() 的调用实际调用的内容

#define ncurses_device  "/dev/ttyS0"

NCURSES_EXPORT(WINDOW *) initscr(void)
{
  WINDOW *result;

pthread_mutex_lock(&CUSTOM_LOCK);

if (!CUSTOM_INITIALIZED)
{
  CUSTOM_INITIALIZED = true;

  if( (FDTERM = fopen(ncurses_device, "r+")) != NULL )
  {

  if(FDTERM == NULL)
  {
    fprintf(stderr, "Error opening device: %s.\n", ncurses_device); 
  }

  /* Set Screen */
  MY_SCREEN = newterm(NULL, FDTERM, FDTERM);

  if(MY_SCREEN != NULL)
  {
    /* Set the terminal */
    set_term(MY_CDU_SCREEN);
  }

  /* def_shell_mode - done in newterm/_nc_setupscreen */
  def_prog_mode();
}
else
{
  CUSTOM_INITIALIZED = true;
  NCURSES_CONST char *name;
  if ((name = getenv("TERM")) == 0 || *name == '\0')
  {
    static char unknown_name[] = "unknown";
    name = unknown_name;
  }

  if (newterm(name, stdout, stdin) == 0)
  {
    fprintf(stderr, "Error opening terminal: %s.\n", name);
    result = NULL;
  }
 }
}
#if NCURSES_SP_FUNCS
#ifdef CURRENT_SCREEN
 NCURSES_SP_NAME(def_prog_mode) (CURRENT_SCREEN);
#else
 NCURSES_SP_NAME(def_prog_mode) (SP);
#endif
#else
 def_prog_mode();
#endif
 result = stdscr;

 pthread_mutex_unlock(&CUSTOM_LOCK);

 return Win(result);
}

The intercept.c allows the device as defined to be used if available.如果可用,intercept.c 允许使用定义的设备。 It also allows initscr() to fall back to the default behavior of using the current terminal.它还允许 initscr() 回退到使用当前终端的默认行为。

This works when used when for debugging, but I feel there has to be a better way to setup NCurses or the environment to direct NCurses output over the desired serial port.这在用于调试时有效,但我觉得必须有更好的方法来设置 NCurses 或环境以将 NCurses 输出定向到所需的串行端口。

The above solution now does not work when executing code on boot as there is not a terminal definition available.由于没有可用的终端定义,因此在启动时执行代码时,上述解决方案现在不起作用。

This is being developed to support both RHEL 7 and 6. Some research seems to point to creating a new environment service using getty, agetty or by editing start-tty.conf as noted ( https://unix.stackexchange.com/a/318647 ).正在开发它以支持 RHEL 7 和 6。一些研究似乎指向使用 getty、agetty 或通过编辑 start-tty.conf 创建一个新的环境服务,如上所述( https://unix.stackexchange.com/a/ 318647 )。

But the other issue is pointing NCurses++ to output to the correct environment.但另一个问题是将 NCurses++ 指向正确的环境输出。 From what I have seen in NCurses source code it appears that the ::initscr() is called by default from cursesw.cc, which makes it harder to just point NCurses to a new environment.从我在 NCurses 源代码中看到的内容来看,::initscr() 似乎是从 cursesw.cc 中默认调用的,这使得将 NCurses 指向新环境变得更加困难。

Questions问题

How do I setup NCurses++ to output to a specified tty?如何设置 NCurses++ 以输出到指定的 tty?

How to properly setup an environment for NCurses to use on system boot?如何正确设置 NCurses 在系统启动时使用的环境?

Update 1:更新 1:

Updated code to do the following:更新代码以执行以下操作:

// Save the current stdin/stdout file descriptors
int saved_stdin = dup(fileno(stdin));
int saved_stdout = dup(fileno(stdout));

// Set the stdin/stdout to the desired device
freopen(ncurses_device, "w+", stdout);
freopen(ncurses_device, "r+", stdin);

// Initialize the NCursesMenu
NCursesMenu *m_pMenu =  new NCursesMenu(m_pMenuItems);

// Restore the saved_stdin/stdout to the correct locations
dup2(saved_stdin, STDIN_FILENO);
dup2(saved_stdout, STDOUT_FILENO);

// Close the saved_stdin/stdout file descriptors
close(saved_stdin);
close(saved_stdout);

This allows NCurses to copy the current FILE* as defined here in newterm , but once the stdin/stdout FILE* is restored to the saved file descriptor the manipulation is lost.这让Ncurses把复制当前FILE *定义这里newterm,但一旦标准输入/输出文件*恢复到保存的文件描述符的操作都将丢失。 If the device is only pointed to the new device it works for NCurses, but all debug/test information is not visible because it is overwritten by NCurses in the current terminal.如果设备仅指向新设备,则它适用于 NCurses,但所有调试/测试信息不可见,因为它被当前终端中的 NCurses 覆盖。

initscr doesn't assume anything about the devices: it uses the current input/output stdin and stdout when initializing (and via newterm , setupterm , it copies the file-descriptors). initscr不对设备做任何假设:它在初始化时使用当前的输入/输出标准输入标准输出(并且通过newtermsetupterm ,它复制文件描述符)。

If your application (or environment/scripting) sets those streams to the device you'd like to connect to, that should be enough for the C++ interface.如果您的应用程序(或环境/脚本)将这些流设置为您想要连接的设备,那么对于 C++ 接口来说应该足够了。 ncurses doesn't use the C+ cout , etc. ncurses 不使用 C+ cout等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM