查看: 1527|回复: 0

[评测分享] 【Telink-泰凌微电子 B91通用开发套件】(二)FreeRtos 适配SHELL

[复制链接]
  • TA的每日心情
    奋斗
    昨天 19:39
  • 签到天数: 127 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2023-10-18 20:55:22 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 andeyqi 于 2023-10-18 22:40 编辑

    1.简介

       MCU 开发项目中经常会使用RTOS,FreeRtos 是个使用比较广泛的RTOS,B91 的sdk 里面已经适配了freertos 的demo 工程,这就意味着我们不需要做额外的适配工作就可以把FreeRtos 跑起来,SDK的demo 工程如下,demo 程序创建了连个task去翻转板上的led,我们打开如下工程烧录后会发现板上的LED 按照期望的方式闪烁显示了说明RTOS 的任务已经正常调度运行起来了。

    freertos.png


    在开发调试过程中经常会需要触发某些测试函数来验证功能是否正常工作,这时候我们可以在代码中写死测试函数不过这样不是很灵活,我们可以在项目中实现个shell,通过shell命令触发对应的函数这样就会方便很多,可以在程序异常的时候通过命令查看特定的运行状态,那开始我们今天的主题适配shell。

    2.UART 适配

    2.1 串口驱动适配
      
      本次shell 的适配物理层使用的是uart 设备,要想适配shell 首先要将物理层适配好,对于串口的驱动我们实际也是不需要单独自己从0编写,sdk里的uart_demo 示例程序已经可以串口输出数据和回显接收到的字符,我们只需要把如下文件加入到工程编译并在main 函数内调用对应的user_init函数即可完成uart 的串口适配,至此我们没有额外对应一行代码已经完成了freertos的适配和uart 的驱动适配,真有种真香的感觉。
    uartdemo.png

    user_init.png

    因为shell 的输出使用的是标准的printf 函数,串口驱动已经适配好了我们只要把串口的输出和printf的底层以来的实现绑定起来即可完成printf 函数的功能,sdk 使用的是gcc的编译环境printf 的底层实现依赖函数为_write 函数,我们在该函数内调用uart 的输出函数即可完成printf函数的对接,对应实现代码如下:
    1. #include "uart.h"
    2. __attribute__((used)) int _write(int fd, const unsigned char *buf, int size)
    3. {
    4.     (void) fd;
    5.     int    i;
    6.     for (i = 0; i < size; i++){
    7.         uart_send_byte(UART0,buf[i]);
    8.     }
    9.     return i;
    10. }
    复制代码
    至此我们只是写入以上代码就可以在工程里使用printf 函数了,我们可以在每个task 内追加打印来验证printf 函数的功能在task 内添加如下打印函数:

    task_printf.png

    task_log.png
    log 已经按照预测的方式输出了,同时也再次验证freertos 已经被正常的调度起来了。

    2.2 添加 shell

    shell 是作为一个任务接口解析串口命令输出信息和使用者交互,本地创建shell 任务,shell 的实现细节在此就不过多描述了,shell任务的代码块如下。
    shell.png

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include "littleshell.h"
    5. #include <stdint.h>
    6. #include <stdbool.h>
    7. #include "FreeRTOS.h"
    8. #include "task.h"
    9. #include "usart_adapter.h"

    10. #define PRINTF printf
    11. #define CONSOLE_FROME "#"
    12. #define NEW_LINE      "\r\n"

    13. #define MSG(msg)  UART_Transmit(1,msg,strlen(msg))

    14. #pragma section="FSymTab"

    15. static struct littleshell_syscall * _syscall_table_begin = NULL;
    16. static struct littleshell_syscall * _syscall_table_end = NULL;

    17. static struct little_shell _shell;
    18. static struct little_shell * shell = &_shell;

    19. uint8_t uartgetchar(uint8_t* pdata);

    20. unsigned int hello(char argc,char ** argv)
    21. {
    22.     PRINTF("hello word.\r\n");
    23.     return 1;
    24. }

    25. const struct littleshell_syscall shell_cmd[] =
    26. {
    27.                 {"hello","test hello",hello},
    28.                 {"hello1","test hello",hello}
    29. };


    30. void littleshell_system_function_init(const void* begin, const void* end)
    31. {
    32.     _syscall_table_begin = (struct littleshell_syscall*) shell_cmd;
    33.     _syscall_table_end = (struct littleshell_syscall*) shell_cmd+(sizeof(shell_cmd)/sizeof(shell_cmd[0]));
    34. }


    35. void littleshell_system_init(void)
    36. {
    37. #if defined (__ICCARM__)
    38.     littleshell_system_function_init(__section_begin("FSymTab"),
    39.                                __section_end("FSymTab"));
    40. #elif defined (__GNUC__)
    41.     extern const int __fsymtab_start;
    42.     extern const int __fsymtab_end;
    43.     littleshell_system_function_init(&__fsymtab_start, &__fsymtab_end);
    44. #endif
    45. }

    46. struct littleshell_syscall* littleshell_syscall_lookup(const char* name)
    47. {
    48.     struct littleshell_syscall* index;

    49.     for (index = _syscall_table_begin; index < _syscall_table_end; index++)
    50.     {
    51.         if (strcmp(index->name, name) == 0)
    52.             return index;
    53.     }
    54.     return NULL;
    55. }

    56. static int str_common(const char *str1, const char *str2)
    57. {
    58.     const char *str = str1;

    59.     while ((*str != 0) && (*str2 != 0) && (*str == *str2))
    60.     {
    61.         str ++;
    62.         str2 ++;
    63.     }

    64.     return (str - str1);
    65. }

    66. static void shell_auto_complete(char *prefix)
    67. {
    68.     struct littleshell_syscall* index;
    69.     const char *name_ptr, *cmd_name;
    70.     int length, min_length;

    71.     min_length = 0;
    72.     name_ptr = NULL;
    73.    
    74.     PRINTF(NEW_LINE);
    75.     if (*prefix == '\0')
    76.     {
    77. #if ( LTSHELL_USING_SHOW_HELP == 1 )
    78.         PRINTF("shell commands:"NEW_LINE);
    79.         for (index = _syscall_table_begin; index < _syscall_table_end; index++)
    80.         {
    81.             PRINTF("%s - %s"NEW_LINE, index->name, index->desc);
    82.         }
    83. #endif
    84.         PRINTF("%s%s", CONSOLE_FROME, prefix);
    85.         return;
    86.     }

    87.     for (index = _syscall_table_begin; index < _syscall_table_end; index++)
    88.     {
    89.         if (strncmp(index->name, prefix,strlen(prefix)) == 0)
    90.         {
    91.             cmd_name = index->name;
    92.             if(min_length == 0)
    93.             {
    94.                  /* set name_ptr */
    95.                  name_ptr = cmd_name;
    96.                  /* set initial length */
    97.                  min_length = strlen(name_ptr);
    98.             }
    99.             length =str_common(name_ptr, cmd_name);
    100.             if (length < min_length)
    101.                 min_length = length;
    102.             PRINTF("%s"NEW_LINE, cmd_name);
    103.         }
    104.     }
    105.     /* auto complete string */
    106.     if (name_ptr != NULL)
    107.     {
    108.         strncpy(prefix, name_ptr, min_length);
    109.     }
    110.     PRINTF("%s%s", CONSOLE_FROME, prefix);
    111.     return ;
    112. }
    113.    
    114. /*** Parse command line
    115. * return pointer to start of new command line
    116. */
    117. static void littleshell_parse_args(const char *cmd, struct littleshell_arg *arg)
    118. {
    119.     char *p;

    120.     if (arg) {
    121.         arg->argc = 0;
    122.         if (cmd) {
    123.             p = arg->_buf;
    124.             while (*cmd && arg->argc < MAX_CLI_ARGS_NUM && (p - arg->_buf < MAX_CLI_ARGS_BUF_LEN)) {
    125.                 while(*cmd && (*cmd == ' ' || *cmd == '\t'))/* Ignore spaces and backspace */
    126.                     cmd++;

    127.                 arg->argv[arg->argc] = p;/* Write command point values */
    128.                 while (*cmd && (*cmd != ' ' && *cmd != '\t') && (p - arg->_buf < MAX_CLI_ARGS_BUF_LEN)) {/* Write command buffer */                     
    129.                         *p++ = *cmd++;
    130.                 }
    131.                 *p++ = '\0';

    132.                 if (*(arg->argv[arg->argc]) == '\0') /* anomaly detection */
    133.                     break;
    134.                 arg->argc++;
    135.             }
    136.         }
    137.     }
    138. }
    139.    
    140. /*** filter out leading and tailing spaces, discard comments
    141. * return pointer to start of new command line
    142. */
    143.    
    144. int littleshell_interpret(const char *line)
    145. {
    146.     struct littleshell_arg arg = {0};
    147. //  const struct cli_command *cmd;

    148.     struct littleshell_syscall* fun_index = NULL;
    149.     littleshell_parse_args(line, &arg);

    150.     fun_index = littleshell_syscall_lookup(arg.argv[0]);
    151.     if(fun_index)
    152.     {
    153.         fun_index->func(arg.argc,arg.argv);
    154.     }
    155.     //PRINTF("[%d][%s]\n",arg.argc,arg._buf);
    156.     return 0;
    157. }

    158.    
    159. /*** filter out leading and tailing spaces, discard comments
    160. * return pointer to start of new command line
    161. */
    162. static char * littleshell_process_line(char *p)
    163. {
    164.     char *s;
    165.     char *x;

    166.     if (!p)
    167.         return NULL;
    168.     // skip leading spaces
    169.     while (p && (*p == ' ' || *p == '\t'))
    170.         p++;
    171.     for (s = x = p; *p; x++, p++) {
    172.         switch(*p) {
    173.         case '\\':
    174.             p++;
    175.             if (*p) {
    176.                 switch(*p) {
    177.                 case 'n':
    178.                     *x = '\n';
    179.                     break;
    180.                 case 'r':
    181.                     *x = '\r';
    182.                     break;
    183.                 case 't':
    184.                     *x = '\t';
    185.                     break;
    186.                 case 'b':
    187.                     *x = '\b';
    188.                     break;
    189.                 default:
    190.                     if (*p >= '0' && *p <= '9')
    191.                         *x = *p - '0';
    192.                     else
    193.                         *x = *p;
    194.                     break;
    195.                 }
    196.             }
    197.             break;
    198.         default:
    199.             if (*p == '\r' || *p == '\n' || *p == '#') *p = '\0';
    200.             *x = *p;
    201.             break;
    202.         }
    203.         if (*p == 0)
    204.             break;
    205.     }
    206.     // trim tailing spaces
    207.     p--;
    208.     while (p > s && (*p == ' ' || *p == '\t'))
    209.         *p-- = '\0';
    210.     return s;
    211. }   

    212. #ifdef LTSHELL_USING_HISTORY

    213. static void shell_handle_history(struct little_shell *shell)
    214. {

    215.     PRINTF("\033[2K\r");
    216.     PRINTF("%s%s", CONSOLE_FROME, shell->line);
    217. }

    218. static void shell_push_history(struct little_shell *shell)
    219. {
    220.     if (shell->line_position != 0)
    221.     {
    222.         /* push history */
    223.         if (shell->history_count >= MAX_HISTROY_NUMS)
    224.         {
    225.             /* if current cmd is same as last cmd, don't push */
    226.             if (memcmp(&shell->cmd_history[MAX_HISTROY_NUMS - 1], shell->line, MAX_CLI_ARGS_BUF_LEN))
    227.             {
    228.                 /* move history */
    229.                 int index;
    230.                 for (index = 0; index < MAX_HISTROY_NUMS - 1; index ++)
    231.                 {
    232.                     memcpy(&shell->cmd_history[index][0],
    233.                            &shell->cmd_history[index + 1][0], MAX_CLI_ARGS_BUF_LEN);
    234.                 }
    235.                 memset(&shell->cmd_history[index][0], 0, MAX_CLI_ARGS_BUF_LEN);
    236.                 memcpy(&shell->cmd_history[index][0], shell->line, shell->line_position);

    237.                 /* it's the maximum history */
    238.                 shell->history_count = MAX_HISTROY_NUMS;
    239.             }
    240.         }
    241.         else
    242.         {
    243.             /* if current cmd is same as last cmd, don't push */
    244.             if (shell->history_count == 0 || memcmp(&shell->cmd_history[shell->history_count - 1], shell->line, MAX_CLI_ARGS_BUF_LEN))
    245.             {
    246.                 shell->current_history = shell->history_count;
    247.                 memset(&shell->cmd_history[shell->history_count][0], 0, MAX_CLI_ARGS_BUF_LEN);
    248.                 memcpy(&shell->cmd_history[shell->history_count][0], shell->line, shell->line_position);

    249.                 /* increase count and set current history position */
    250.                 shell->history_count ++;
    251.             }
    252.         }
    253.     }
    254.     shell->current_history = shell->history_count;
    255. }

    256. #endif
    257. /*** read a line datas from command line.
    258. */

    259. void littleshell_main_entry(void *pvParameters)
    260. {
    261.     char *p;
    262.     littleshell_system_init();
    263.    
    264.     PRINTF("%s",CONSOLE_FROME);
    265.     while(1)
    266.     {   
    267.         uint8_t ch = 100;
    268.         //if (linelen >= sizeof(line))
    269.         //    continue;
    270.         if((shell_uart_getchar(&ch)) != 0)
    271.         {
    272.             /*
    273.              * handle control key
    274.              * up key  : 0x1b 0x5b 0x41
    275.              * down key: 0x1b 0x5b 0x42
    276.              * right key:0x1b 0x5b 0x43
    277.              * left key: 0x1b 0x5b 0x44
    278.              */
    279.             if (ch == 0x1b)
    280.             {
    281.                 shell->stat = WAIT_SPEC_KEY;
    282.                 continue;
    283.             }
    284.             else if (shell->stat == WAIT_SPEC_KEY)
    285.             {
    286.                 if (ch == 0x5b)
    287.                 {
    288.                     shell->stat = WAIT_FUNC_KEY;
    289.                     continue;
    290.                 }
    291.    
    292.                 shell->stat = WAIT_NORMAL;
    293.             }
    294.             else if (shell->stat == WAIT_FUNC_KEY)
    295.             {
    296.                 shell->stat = WAIT_NORMAL;
    297.    
    298.                 if (ch == 0x41) /* up key */
    299.                 {
    300. #ifdef  LTSHELL_USING_HISTORY
    301.                     /* prev history */
    302.                     if (shell->current_history > 0)
    303.                         shell->current_history --;
    304.                     else
    305.                     {
    306.                         shell->current_history = 0;
    307.                         continue;
    308.                     }
    309.    
    310.                     /* copy the history command */
    311.                     memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
    312.                            MAX_CLI_ARGS_BUF_LEN);
    313.                     shell->line_curpos = shell->line_position = strlen(shell->line);
    314.                     shell_handle_history(shell);
    315. #endif
    316.                     continue;
    317.                 }
    318.                 else if (ch == 0x42) /* down key */
    319.                 {
    320. #ifdef LTSHELL_USING_HISTORY
    321.                     /* next history */
    322.                     if (shell->current_history < shell->history_count - 1)
    323.                         shell->current_history ++;
    324.                     else
    325.                     {
    326.                         /* set to the end of history */
    327.                         if (shell->history_count != 0)
    328.                             shell->current_history = shell->history_count - 1;
    329.                         else
    330.                             continue;
    331.                     }
    332.    
    333.                     memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
    334.                            MAX_CLI_ARGS_BUF_LEN);
    335.                     shell->line_curpos = shell->line_position = strlen(shell->line);
    336.                     shell_handle_history(shell);
    337. #endif
    338.                     continue;
    339.                 }
    340.                 else if (ch == 0x44) /* left key */
    341.                 {
    342.                     if (shell->line_curpos)
    343.                     {
    344.                         PRINTF("\b");
    345.                         shell->line_curpos --;
    346.                     }
    347.    
    348.                     continue;
    349.                 }
    350.                 else if (ch == 0x43) /* right key */
    351.                 {
    352.                     if (shell->line_curpos < shell->line_position)
    353.                     {
    354.                         PRINTF("%c", shell->line[shell->line_curpos]);
    355.                         shell->line_curpos ++;
    356.                     }
    357.    
    358.                     continue;
    359.                 }
    360.             }

    361.             /* received null or error */
    362.             if (ch == '\0' || ch == 0xFF) continue;
    363.             /* handle tab key */
    364.             else if (ch == '\t')
    365.             {
    366.                 int i;
    367.                 /* move the cursor to the beginning of line */
    368.                 for (i = 0; i < shell->line_curpos; i++)
    369.                     PRINTF("\b");

    370.                 /* auto complete */
    371.                 shell_auto_complete(&shell->line[0]);
    372.                 /* re-calculate position */
    373.                 shell->line_curpos = shell->line_position = strlen(shell->line);

    374.                 continue;
    375.             }
    376.             /* handle backspace key */
    377.             else if (ch == 0x7f || ch == 0x08)
    378.             {
    379.                 /* note that shell->line_curpos >= 0 */
    380.                 if (shell->line_curpos == 0)
    381.                     continue;

    382.                 shell->line_position--;
    383.                 shell->line_curpos--;

    384.                 if (shell->line_position > shell->line_curpos)
    385.                 {
    386.                     int i;

    387.                     memmove(&shell->line[shell->line_curpos],
    388.                                &shell->line[shell->line_curpos + 1],
    389.                                shell->line_position - shell->line_curpos);
    390.                     shell->line[shell->line_position] = 0;

    391.                     PRINTF("\b%s  \b", &shell->line[shell->line_curpos]);

    392.                     /* move the cursor to the origin position */
    393.                     for (i = shell->line_curpos; i <= shell->line_position; i++)
    394.                         PRINTF("\b");
    395.                 }
    396.                 else
    397.                 {
    398.                     PRINTF("\b \b");
    399.                     shell->line[shell->line_position] = 0;
    400.                 }

    401.                 continue;
    402.             }

    403.             /* handle end of line, break */
    404.             if (ch == '\r' || ch == '\n')
    405.             {
    406.                 if (shell->line_position != 0)
    407.                 {
    408.                     shell_push_history(shell);
    409.                     p = littleshell_process_line(shell->line);
    410.                     if (*p)
    411.                     {
    412.                         PRINTF(NEW_LINE);

    413.                         littleshell_interpret(p);
    414.                         //PRINTF("[%s]\n",p);
    415.                         //TODO deal with strings,end of deal echo console string
    416.                         
    417.                     }
    418.                 }
    419.                 PRINTF(NEW_LINE);
    420.                 PRINTF(CONSOLE_FROME);

    421.                 memset(shell->line, 0, sizeof(shell->line));
    422.                 shell->line_curpos = shell->line_position = 0;
    423.                 continue;
    424.             }

    425.             /* it's a large line, discard it */
    426.             if (shell->line_position >= MAX_CLI_ARGS_BUF_LEN)
    427.                 shell->line_position = 0;

    428.             /* normal character */
    429.             if (shell->line_curpos < shell->line_position)
    430.             {
    431.                 int i;

    432.                 memmove(&shell->line[shell->line_curpos + 1],
    433.                            &shell->line[shell->line_curpos],
    434.                            shell->line_position - shell->line_curpos);
    435.                 shell->line[shell->line_curpos] = ch;
    436.                 PRINTF("%s", &shell->line[shell->line_curpos]);

    437.                 /* move the cursor to new position */
    438.                 for (i = shell->line_curpos; i < shell->line_position; i++)
    439.                     PRINTF("\b");
    440.             }
    441.             else
    442.             {
    443.                 shell->line[shell->line_position] = ch;
    444.                 PRINTF("%c", ch);
    445.             }

    446.             ch = 0;
    447.             shell->line_position ++;
    448.             shell->line_curpos++;
    449.             if (shell->line_position >= MAX_CLI_ARGS_BUF_LEN)
    450.             {
    451.                 /* clear command line */
    452.                 shell->line_position = 0;
    453.                 shell->line_curpos = 0;
    454.             }   
    455.         }
    456.         else
    457.         {
    458.             vTaskDelay(100);
    459.         }
    460.     }   
    461. }


    复制代码

    3 测试验证

    为了验证shell 的工作状态本地追加led 命令用于控制led 的点亮熄灭,led on/off 打开/关闭led,对应代码如下:
    1. unsigned int led(char argc,char ** argv)
    2. {
    3.         /*init gpio*/
    4.         reg_gpio_pb_oen &= ~ GPIO_PB7;
    5.         reg_gpio_pb_oen &= ~ GPIO_PB4;

    6.         if(argc != 2)
    7.                 return 1;

    8.         if(strcmp(argv[1],"on") == 0)
    9.         {
    10.                 reg_gpio_pb_out |= GPIO_PB7;
    11.                 reg_gpio_pb_out |= GPIO_PB4;
    12.         }
    13.         else if(strcmp(argv[1],"off") == 0)
    14.         {
    15.                 reg_gpio_pb_out &= ~GPIO_PB7;
    16.                 reg_gpio_pb_out &= ~GPIO_PB4;
    17.         }

    18.         return 0;
    19. };
    复制代码

    串口输入led on/off 已经实现了led 的点亮熄灭控制符合预期效果如下,后续就可以实现测试命令使用串口和板子进行交互。


    18d4e706e4ae23eb9184e94a92e3d4fe[00-00-00--00-00-18].gif

    ==================资料分割线==================
    官方的sdk文档及文档整理至如下路径,里面的所有资料也都可以从官方的wiki获取


























    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-5-15 02:06 , Processed in 0.122620 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.