rtos开发总结

由于工作需要,使用到rtos,现将遇到的问题总结如下:很多东西先记在这里,后面有空整理

1.实现类似于linux shell的交互工具。

实现基本思路是初始化一个shell线程,然后接收用户的输入,然后parse用户的命令。当然,支持的命令需要提前实现,比如要实现ls的命令,需要实现ls命令的函数,然后该函数注册到一个数组中,当接收到用户输入ls命令时,遍历函数数组中的注册函数,找到相应的命令,然后执行。
1.首先利用.lds.S文件指定一块存储空间,用来存放struct数组,该struct中存放了每个命令的name,description,function address。每个命令注册一个struct,放置在指定的内存的地方。

//每个命令的struct的定义
#define SECTION(x) __attribute__((section(x)))//将指定的变量放置在x指定的段地址上。
typedef int (*sh_func)(int argc, char **argv);//函数指针。要实现的shell命令的函数就要定义为该样式。
struct sh_func_call//每个命令的struct。每个命令都需要初始化一个该struct,然后放到上面section指定的地址。
{
  const char *name;
  const char *desc;
  ant_sh_func func;
  const char *reserved;
};
/*这里就是定义了一个宏,当实现了一个shell命令,就利用这个宏来声明一下,这个宏就会自动声明一个该函数对应的struct,放置到指定的内存位置,后面接收到shell的命令名字,就去该地址去匹配,匹配到之后就可以利用存储的函数指针调用该命令对应的函数。*/
#define FUNCTION_EXPORT_ALIAS(function, alias, description)                     \
  const char __sh_func_##alias##_name[] = #alias;                         \
  const char __sh_func_##alias##_desc[] = description;                    \
  const struct sh_func_call __sh_func_call_##alias SECTION("AMBSyscallTab") =  \
  {                                   \
    __sh_func_##alias##_name,   \
    __sh_func_##alias##_desc,   \
    (sh_func)&function     \    //这里的&可以要,也可以不要。c语言都允许。
  };
#define FUNCTION_EXPORT(function, description) \
  FUNCTION_EXPORT_ALIAS(function, function, description)
//example
static int print_hello(int argc, char **argv)
{
  for (int i = 0; i < argc; ++i) {
    printk("arg[%d]: %s\n", i, argv[i]);
  }
  return 0;
}
FUNCTION_EXPORT(print_hello, "This function can print hello")

2.定义好了上面的基础之后,就要定义一个线程的主函数,暂时先使用一个线程实现shell功能(最终需要多线程,就是shell为一个主线程,当接收到命令之后,要另起一个线程来执行这个命令,主线程要等待执行线程的结果,并且能根据用户的命令来终止执行线程。)
首先定义一个shell的context,用来指定该shell的一些功能,比如read和write函数是从串口来获取和打印到串口还是从telnet获取或打印到telnet。还要存放该shell接收到的命令名称,该命令的参数等信息,因为是利用c语言来实现,所以很多函数都需要传入该context。

typedef int (*console_read_write_func)(char *buf, int size);
struct sh_context
{
  int line_pos;
  char line[512];

  int x;
  int y;

  int argc;
  char *argv[128];
  ant_console_read_write_func read;
  ant_console_read_write_func write;
};

然后定义线程主函数

static struct sh_context antshell_context;
static void tx_task_toy(void)//在系统初始函数中调用此函数,就会创建一个shell线程。
{
  shell_context.read = uart_read;//指定read函数使用uart_read函数,即从串口read
  shell_context.write = uart_write;//打印到串口
//创建shell线程。
  if (KAL_TaskCreate(&task0, "ant_shell", KAL_TASK_LOWEST_PRIORITY - 2,
                         shell_task, (unsigned int)&shell_context,
                         task0_stack, 8192, KAL_AUTO_START)) {
    printk("%s: Bug !!!", __func__);
    return;
  }
  return;
}
//shell线程的主函数
void shell_task(unsigned int arg)
{
  struct sh_context *context = (struct sh_context*)arg;//传入context
  sh_show_welcome(context);//显示一个欢迎内容
  while (1) {
    int ch = sh_read_char(context);//读取命令字符。
    sh_parse_input(ch, context);//parse命令字符,
  }
}
//根据用户在串口输入的命令,去上面section指定的内存区域去匹配对应的命令,找到后,执行对应的函数。
void sh_parse_input(char ch, struct sh_context *context)
{
  if (ch == '\r') { //end of the line
    context->line[context->line_pos] = '\0';
    context->line_pos = 0;
    sh_print(context, "\r\n");
    if (sh_parse_args(context) > 0) {
      struct sh_syscall *syscall = 0;

      if ((syscall = find_sh_syscall(context->argv[0])) != 0) {//寻找对应的命令
        syscall->func(context->argc, context->argv);//找到对应的命令,执行其函数
      } else {
        sh_print(context, "%s: command not found\r\n", context->argv[0]);//没找到命令。
      }
      sh_show_prompt(context, 0);
    } else {
      sh_show_prompt(context, 0);
    }
  } else if (ch >= 32 && ch <= 126) { //visible characters
    sh_print(context, "%c", ch);
    context->line[context->line_pos++] = ch;
  }
}

实现控制字符:
1. 0x7f为回退键的键值,操作为sh_print(context, “\b \b”); \b就是回退操作,一个\b只是回退光标, \b \b(中间有空格)为回退一个光标然后打印出空格,然后再回退回来,这样才能实现backtrace的作用。
2.键盘上的控制键对应的字符:可以参考下面的连接。一般为3到4个字符表示,开头是0x1B
http://blog.csdn.net/sumless/article/details/1037809

二:一些开发注意的要点:

1.因为创建thread需要指定线程运行所需要的堆栈,可以用数组来当堆栈,这样虽然简单,但非常不灵活,一般使用threadx提供的两种内存管理资源:内存字节池和内存池块。它们可以被定义到任何地方,但一般建议放在全局。

你可能感兴趣的:(rtos)