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

时间:2018-10-03 22:34:07

标签: c linux ncurses curses

概述

我一直在使用ncurses ++库编写代码来显示菜单和屏幕。理想的结果是通过串行终端接口输出这些菜单和屏幕。

当前尝试

我可以使用调用的基础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);
  }
}

为了使它在c ++中工作,我编写了一些intercept.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);
}

intercept.c允许使用定义的设备(如果有)。它  还允许initscr()退回到使用当前终端的默认行为。

当用于调试时,此方法有效,但我觉得必须有一种更好的方法来设置NCurses或环境,以通过所需的串行端口定向NCurses输出。

由于没有可用的终端定义,上述解决方案现在在引导时执行代码时不起作用。

正在开发它以同时支持RHEL 7和RHEL7。一些研究似乎指向使用getty,agetty或通过编辑start-tty.conf来创建新的环境服务(如https://unix.stackexchange.com/a/318647)。

但是另一个问题是将NCurses ++指向正确的环境。根据我在NCurses源代码中看到的内容,似乎默认情况下从cursesw.cc调用:: initscr(),这使得将NCurses指向新环境变得更加困难。

问题

如何设置NCurses ++以输出到指定的tty?

如何正确设置NCurses在系统启动时使用的环境?

更新1:

更新的代码可以执行以下操作:

// 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);

这允许NCurses复制 newterm 中定义的here的当前FILE *,但是一旦将stdin / stdout FILE *恢复到保存的文件描述符中,操作就会丢失。如果该设备仅指向新设备,则可用于NCurses,但所有调试/测试信息均不可见,因为它已被当前终端中的NCurses覆盖。

1 个答案:

答案 0 :(得分:1)

class CreateTypeControlAccesses < ActiveRecord::Migration def change create_table :type_control_accesses do |t| t.string :name t.timestamps null: false end end end 对设备没有任何假设:初始化时会使用 current 输入/输出 stdin stdout (并通过initscrnewterm复制文件描述符)。

如果您的应用程序(或环境/脚本)将这些流设置为您要连接的设备,则对于C ++接口应该足够了。 ncurses不使用C + cout 等。