迪文科技论坛

 找回密码
 立即注册
搜索
查看: 487|回复: 2

【开源】重磅!基于迪文屏的DE-RTOS第一篇Shell

[复制链接]

15

主题

112

回帖

1104

积分

金牌会员

Rank: 6Rank: 6

积分
1104
QQ
发表于 2023-9-16 15:46:46 | 显示全部楼层 |阅读模式
本帖最后由 二哲科技 于 2023-9-16 15:49 编辑

1、介绍

迪文屏的开发者非常的多,但是迪文没有一个很好的生态系统,像国产RTThread一样,拥有多种组件,多种传感器,能够快速的实现产品开发,为此我设计了一款基于C51的DE-RTOS,希望能成为迪文的操作系统之一。
该系统是参考RTThread的文件结构,也为了后续方便移植RTThread的各种组件和软件包,RTThread的系统框架如下图所示:


2、设计难点

目前基于C51的操作系统不多,RTX51系列是不开源的,所以C51的任务跳转也是比较难实现的,我也在找各种方法,后续还准备设计一款类似STM32CubeMX的图形配置软件,可以直接通过图形化进行外设、组件和软件包的配置,这个软件周期也会比较长,需要先完善DE-RTOS之后再去设计图形化配置软件。下面是STM32CubeMX的软件界面。




3、设计

1)代码设计

需要设计好文件框架,我是直接参考RTThread的文件框架,同时添加上一些迪文和自己的内容,文件框架如下图所示:




接下来就是移植Shell,在移植Shell的时候,其实就移植了一部分的RTThread,这部分移植还是挺复杂的,需要对串口数据进行FIFO的处理,然后再进行解码,根据解码的结果去调用合适的函数。调用函数用到了函数指针,这样就可以根据字符串的内容去执行相关函数,同时还可以传递数据。

大概贴一下Shell函数解析的代码。

  1. void shell_task_entry()
  2. {
  3.     static uint8_t frist_flag = 0;
  4.     char ch = 0;
  5.     int8_t ret = 0;

  6.     if(frist_flag == 0)
  7.     {
  8.         frist_flag = 1;
  9.         shell.echo_mode = 1;
  10.         printf(FINSH_PROMPT);
  11.     }


  12.     //while(1)
  13.     {
  14.         
  15.         ch = de_hw_console_getchar();
  16.         if(ch == 0)
  17.         {
  18.             return;
  19.         }
  20.             
  21.         // printf("%c", ch);

  22.         /*
  23.          * handle control key
  24.          * up key  : 0x1b 0x5b 0x41
  25.          * down key: 0x1b 0x5b 0x42
  26.          * right key:0x1b 0x5b 0x43
  27.          * left key: 0x1b 0x5b 0x44
  28.          */
  29.         if (ch == 0x1b)
  30.         {
  31.             shell.stat = WAIT_SPEC_KEY;
  32.             return;
  33.         }
  34.         else if (shell.stat == WAIT_SPEC_KEY)
  35.         {
  36.             if (ch == 0x5b)
  37.             {
  38.                 shell.stat = WAIT_FUNC_KEY;
  39.                 return;
  40.             }

  41.             shell.stat = WAIT_NORMAL;
  42.         }
  43.         else if (shell.stat == WAIT_FUNC_KEY)
  44.         {
  45.             shell.stat = WAIT_NORMAL;

  46.             if (ch == 0x41) /* up key */
  47.             {
  48. #ifdef FINSH_USING_HISTORY
  49.                 /* prev history */
  50.                 if (shell.current_history > 0)
  51.                     shell.current_history --;
  52.                 else
  53.                 {
  54.                     shell.current_history = 0;
  55.                     return;
  56.                 }

  57.                 /* copy the history command */
  58.                 memcpy(shell.line, &shell.cmd_history[shell.current_history][0],
  59.                        FINSH_CMD_SIZE);
  60.                 shell.line_curpos = shell.line_position = strlen(shell.line);
  61.                 shell_handle_history(&shell);
  62. #endif
  63.                 return;
  64.             }
  65.             else if (ch == 0x42) /* down key */
  66.             {
  67. #ifdef FINSH_USING_HISTORY
  68.                 /* next history */
  69.                 if (shell.current_history < shell.history_count - 1)
  70.                     shell.current_history ++;
  71.                 else
  72.                 {
  73.                     /* set to the end of history */
  74.                     if (shell.history_count != 0)
  75.                         shell.current_history = shell.history_count - 1;
  76.                     else
  77.                         return;
  78.                 }

  79.                 memcpy(shell.line, &shell.cmd_history[shell.current_history][0],
  80.                        FINSH_CMD_SIZE);
  81.                 shell.line_curpos = shell.line_position = strlen(shell.line);
  82.                 shell_handle_history(&shell);
  83. #endif
  84.                 return;
  85.             }
  86.             else if (ch == 0x44) /* left key */
  87.             {
  88.                 if (shell.line_curpos)
  89.                 {
  90.                     printf("\b");
  91.                     shell.line_curpos --;
  92.                 }

  93.                 return;
  94.             }
  95.             else if (ch == 0x43) /* right key */
  96.             {
  97.                 if (shell.line_curpos < shell.line_position)
  98.                 {
  99.                     printf("%c", shell.line[shell.line_curpos]);
  100.                     shell.line_curpos ++;
  101.                 }

  102.                 return;
  103.             }
  104.         }

  105.         /* received null or error */
  106.         if (ch == '\0' || ch == 0xFF) return;
  107.         /* handle tab key */
  108. #ifdef FINSH_USING_SYMTAB
  109.         else if (ch == '\t')
  110.         {
  111.             int i;
  112.             /* move the cursor to the beginning of line */
  113.             for (i = 0; i < shell.line_curpos; i++)
  114.                 printf("\b");

  115.             /* auto complete */
  116.             shell_auto_complete(&shell.line[0]);
  117.             /* re-calculate position */
  118.             shell.line_curpos = shell.line_position = strlen(shell.line);

  119.             return;
  120.         }
  121. #endif
  122.         /* handle backspace key */
  123.         else if (ch == 0x7f || ch == 0x08)
  124.         {
  125.             /* note that shell.line_curpos >= 0 */
  126.             if (shell.line_curpos == 0)
  127.                 return;

  128.             shell.line_position--;
  129.             shell.line_curpos--;

  130.             if (shell.line_position > shell.line_curpos)
  131.             {
  132.                 int i;

  133.                 de_memmove(&shell.line[shell.line_curpos],
  134.                            &shell.line[shell.line_curpos + 1],
  135.                            shell.line_position - shell.line_curpos);
  136.                 shell.line[shell.line_position] = 0;

  137.                 printf("\b%s  \b", &shell.line[shell.line_curpos]);

  138.                 /* move the cursor to the origin position */
  139.                 for (i = shell.line_curpos; i <= shell.line_position; i++)
  140.                     printf("\b");
  141.             }
  142.             else
  143.             {
  144.                 printf("\b \b");
  145.                 shell.line[shell.line_position] = 0;
  146.             }

  147.             return;
  148.         }

  149.         /* handle end of line, break */
  150.         if (ch == '\r' || ch == '\n')
  151.         {
  152. #ifdef FINSH_USING_HISTORY
  153.             shell_push_history(&shell);
  154. #endif

  155. #ifdef FINSH_USING_MSH
  156.             
  157.             shell_screen_append(0, shell.line, shell.line_position);
  158.             if (cmd_is_used() == DE_TRUE)
  159.             {
  160.                 if (shell.echo_mode)
  161.                     printf("\r\n");
  162.                 cmd_exec(shell.line, shell.line_position);
  163.             }
  164.             else
  165. #else
  166.             printf("\r\n");
  167. #endif
  168.             {
  169. #ifndef FINSH_USING_MSH_ONLY
  170.                 /* add ';' and run the command line */
  171.                 shell.line[shell.line_position] = ';';

  172.                 if (shell.line_position != 0)
  173.                     finsh_run_line(&shell.parser, shell.line);
  174.                 else
  175.                     if (shell.echo_mode) printf("\n");
  176. #endif
  177.             }
  178.             printf(FINSH_PROMPT);
  179.             memset(shell.line, 0, sizeof(shell.line));
  180.             shell.line_curpos = shell.line_position = 0;
  181.             return;
  182.         }

  183.         /* it's a large line, discard it */
  184.         if (shell.line_position >= FINSH_CMD_SIZE)
  185.             shell.line_position = 0;

  186.         /* normal character */
  187.         if (shell.line_curpos < shell.line_position)
  188.         {
  189.             int i;

  190.             de_memmove(&shell.line[shell.line_curpos + 1],
  191.                        &shell.line[shell.line_curpos],
  192.                        shell.line_position - shell.line_curpos);
  193.             shell.line[shell.line_curpos] = ch;
  194.             if (shell.echo_mode)
  195.                 printf("%s", &shell.line[shell.line_curpos]);

  196.             /* move the cursor to new position */
  197.             for (i = shell.line_curpos; i < shell.line_position; i++)
  198.                 printf("\b");
  199.         }
  200.         else
  201.         {
  202.             shell.line[shell.line_position] = ch;
  203.             if (shell.echo_mode)
  204.                 printf("%c", ch);
  205.         }

  206.         ch = 0;
  207.         shell.line_position ++;
  208.         shell.line_curpos++;
  209.         if (shell.line_position >= FINSH_CMD_SIZE)
  210.         {
  211.             /* clear command line */
  212.             shell.line_position = 0;
  213.             shell.line_curpos = 0;
  214.         }
  215.     } /* end of device read */
  216. }
复制代码


然后就是判断执行什么函数,如果输入内容错误,则直接返回错误提示。

  1. void cmd_exec(char *cmd_line, uint8_t cmd_len)
  2. {
  3.     if(cmd_len > 0)
  4.     {
  5.         uint8_t i = 0;
  6.         char cmd_line_temp[30] = {0};

  7.         memcpy(cmd_line_temp, cmd_line, cmd_len);
  8.         for(i = 0;i < cmd_cnt;i++)
  9.         {
  10.             if(memcmp(cmd_list[i].name, cmd_line_temp, strlen(cmd_list[i].name)) == 0 && cmd_len >= strlen(cmd_list[i].name))
  11.             {
  12.                 cmd_list[i].function(cmd_line_temp);
  13.                 //printf("ret:%d\r\n", cmd_list[i].function(cmd_line_temp));
  14.                 break;
  15.             }
  16.         }
  17.         if(i == cmd_cnt)
  18.         {
  19.             cmd_error(cmd_line_temp);
  20.         }
  21.     }
  22. }
复制代码



同时我还设计了控制屏幕控件的函数,可以不用阅读【T5L_DGUSII_应用开发指南】就可以对控件进行操作,目前只设计了文本和基本图形中的矩形,后续会完善剩下的,代码如下所示:

  1. void base_graph_rectangle_fill_set(uint16_t addr, base_graph_param_t base_graph_param_temp[], uint8_t len)
  2. {
  3.     uint8_t cmd[252] = {0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x03, 0x20, 0xAA, 0xAA, 0xFF, 0x00};
  4.     uint8_t i = 0;

  5.     if(len > 24)    //一次最多24个数据
  6.         len = 24;

  7.     //图形数量
  8.     cmd[3] = len;

  9.     for(i = 0;i < len;i++)
  10.     {
  11.         cmd[4 + i * 10] = base_graph_param_temp[i].start_x / 256;
  12.         cmd[5 + i * 10] = base_graph_param_temp[i].start_x % 256;
  13.         cmd[6 + i * 10] = base_graph_param_temp[i].start_y / 256;
  14.         cmd[7 + i * 10] = base_graph_param_temp[i].start_y % 256;
  15.         cmd[8 + i * 10] = base_graph_param_temp[i].end_x / 256;
  16.         cmd[9 + i * 10] = base_graph_param_temp[i].end_x % 256;
  17.         cmd[10 + i * 10] = base_graph_param_temp[i].end_y / 256;
  18.         cmd[11 + i * 10] = base_graph_param_temp[i].end_y % 256;
  19.         cmd[12 + i * 10] = base_graph_param_temp[i].color / 256;
  20.         cmd[13 + i * 10] = base_graph_param_temp[i].color % 256;
  21.     }

  22.     cmd[len * 10 + 4] = 0xFF;
  23.     cmd[len * 10 + 5] = 0x00;

  24.     sys_write_vp(addr, cmd, (len * 10 + 6) / 2);
  25.    
  26. }

  27. //文本变量设置
  28. void text_display_value_set(uint16_t addr, uint16_t offset, char *text_data, uint16_t text_len)
  29. {
  30.     sys_write_vp(addr + offset, text_data, text_len);
  31. }

  32. //文本描述设置
  33. void text_display_describe_set(uint16_t addr, uint32_t mask, uint16_t value_addr, int16_t x, int16_t y)
  34. {
  35.     if(mask & TEXT_MASK_VALUE_ADDR == TEXT_MASK_VALUE_ADDR)
  36.     {
  37.         sys_write_vp(addr, (uint8_t *)&value_addr, 1);
  38.     }
  39. }
复制代码



最后还有一个触摸的回调,通过注册按键、添加按键回调来实现按键的触发,保证了系统的分层调用关系。代码如下:

  1. void touch_init(uint16_t touch_addr)
  2. {
  3.     touch_address = touch_addr;
  4. }

  5. void touch_insert(uint16_t touch_value, touch_function_t touch_function_temp)
  6. {
  7.     touch_function[touch_function_cnt] = touch_function_temp;
  8.     touch_values[touch_function_cnt] = touch_value;
  9.     touch_function_cnt++;
  10. }

  11. //用于产生按钮点击扫描信号,放在1ms的定时器中调用即可
  12. void touch_tick()
  13. {
  14.         #define BTN_SCAN_PERIOD                100   //按钮点击事件的扫描周期,单位ms
  15.         static idata uint8_t tick = 0;
  16.        
  17.         tick++;
  18.         if(tick == BTN_SCAN_PERIOD)
  19.         {
  20.                 tick = 0;
  21.                 is_btn_scan = 1;//产生一个按钮点击扫描信号
  22.         }
  23. }

  24. //按钮点击事件扫描并处理
  25. void touch_handler()
  26. {
  27.         uint16_t btn_val;
  28.     uint8_t i = 0;
  29.        
  30.         if(is_btn_scan == 0)//是否有扫描信号,没有的话就啥也不做,直接返回
  31.                 return;
  32.         is_btn_scan = 0;//清除
  33.        
  34.         //1.开始检查是否有按钮按下
  35.         sys_read_vp(touch_address, (uint8_t*)&btn_val, 1);
  36.         if(btn_val == 0)
  37.                 return;
  38.        
  39.         //2.按钮点击事件处理
  40.         for(i = 0;i < touch_function_cnt;i++)
  41.     {
  42.         if(btn_val == touch_values[i])
  43.         touch_function[i]();
  44.     }

  45.         //3.清除按键值
  46.         btn_val = 0;
  47.         sys_write_vp(touch_address, (uint8_t*)&btn_val, 1);
  48. }
复制代码




2)界面设计

界面设计就是简单的显示Shell的输入和输出,不过也用到了一些新技术,通过修改变量地址来实现翻页,这样就非常方便,界面素材只有三张图。




一共就两个界面,首页和显示页,有技术难度的在显示页,可以实现自动翻页和自动换行功能,主要是通过代码实现的,具体如下:

  1. #define PAGE_LINE_MAX   17  //一页最多十七行

  2. uint8_t page_total = 0;         //总页数
  3. uint8_t page_current = 0;       //当前页数
  4. uint8_t last_page_lines = 0;    //最后一页的行数
  5. uint8_t last_page_length = 0;   //最后一页的字符数
  6. uint16_t page_addr = 0x2000;

  7. void display_page_status()
  8. {
  9.     char page_temp[6] = {0};

  10.     page_temp[0] = (page_current + 1) / 10 + '0';
  11.     page_temp[1] = (page_current + 1) % 10 + '0';
  12.     page_temp[2] = '/';
  13.     page_temp[3] = (page_total + 1) / 10 + '0';
  14.     page_temp[4] = (page_total + 1) % 10 + '0';
  15.     text_display_value_set(0x1100, 0, page_temp, 3);
  16. }

  17. void shell_screen_append(uint8_t mode, char *line_data, uint8_t line_len)
  18. {
  19.     char line_temp[100] = {0};
  20.     char line_cnt = 0;
  21.     uint8_t i = 0;
  22.     uint8_t current_line_cnt = 0;

  23.     if(mode == 0)
  24.     {
  25.         memcpy(line_temp, "msh >", 5);
  26.         line_cnt = 5;
  27.     }
  28.     if(page_current != page_total)
  29.     {
  30.         page_current = page_total;
  31.         text_display_describe_set(0x1200, TEXT_MASK_VALUE_ADDR, page_addr + page_current * 0x200, 0, 0);
  32.     }
  33.    
  34.     for(i = 0;i < line_len;i++)
  35.     {
  36.         line_temp[line_cnt++] = line_data[i];
  37.     }

  38.     current_line_cnt = (line_cnt / 25) + 1;
  39.     last_page_lines += (line_cnt / 25) + 1;

  40.     if(last_page_lines > PAGE_LINE_MAX)
  41.     {
  42.         page_total++;
  43.         page_current = page_total;
  44.         last_page_lines = current_line_cnt;
  45.         last_page_length = 0;
  46.         text_display_describe_set(0x1200, TEXT_MASK_VALUE_ADDR, page_addr + page_current * 0x200, 0, 0);
  47.         display_page_status();
  48.     }

  49.     if(line_cnt % 2 == 1)
  50.     {
  51.         if(line_cnt % 25 < 23)
  52.         {
  53.             line_temp[line_cnt++] = ' ';
  54.             line_temp[line_cnt++] = '\r';
  55.             line_temp[line_cnt++] = '\n';
  56.         }
  57.         else if(line_cnt % 25 == 24)
  58.         {
  59.             line_temp[line_cnt++] = ' ';
  60.         }
  61.     }
  62.     else
  63.     {
  64.         if(line_cnt % 25 < 24)
  65.         {
  66.             line_temp[line_cnt++] = '\r';
  67.             line_temp[line_cnt++] = '\n';
  68.         }
  69.     }
  70. //    printf("\r\n%s %d\r\n", line_temp, line_len);
  71.     text_display_value_set(page_addr + page_current * 0x200, last_page_length / 2, line_temp, line_cnt / 2);
  72.     last_page_length += line_cnt;
  73. }

  74. void page_next()
  75. {
  76.     // printf("page_next");
  77.     if(page_current < page_total)
  78.     {
  79.         page_current++;
  80.         text_display_describe_set(0x1200, TEXT_MASK_VALUE_ADDR, page_addr + page_current * 0x200, 0, 0);
  81.         display_page_status();
  82.     }
  83. }

  84. void page_last()
  85. {
  86.     // printf("page_last");
  87.     if(page_current > 0)
  88.     {
  89.         page_current--;
  90.         text_display_describe_set(0x1200, TEXT_MASK_VALUE_ADDR, page_addr + page_current * 0x200, 0, 0);
  91.         display_page_status();
  92.     }
  93. }
复制代码



4、结论

C51移植Shell还是相对麻烦的,因为有些变量是没有的,所以需要通过别的方法来实现。好在整体功能都实现了,后续DE-RTOS希望有更多的开发者一起参与,来完善迪文的操作系统生态,我也会好好维护和升级DE-RTOS。


界面工程:

演示视频:


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
二哲科技,欢迎联系,帮你解决问题,为你提供方案~
VX:erzhekeji
QQ:1002866443
回复

使用道具 举报

9

主题

86

回帖

726

积分

高级会员

Rank: 4

积分
726
发表于 2023-9-16 21:16:39 | 显示全部楼层
好东西必须顶一个。
回复

使用道具 举报

4

主题

134

回帖

2531

积分

金牌会员

Rank: 6Rank: 6

积分
2531
发表于 2023-9-19 09:07:20 | 显示全部楼层
这个必须顶!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|迪文科技论坛 ( 京ICP备05033781号-1 )

GMT+8, 2024-5-13 16:31 , Processed in 0.086884 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表