10. 支持交互式运行

PikaScript支持直接读取字符串运行Python脚本,因此支持交互式运行只需要制作一个串口接收驱动。

10.1. 方案一:按字节读取运行(推荐)

10.1.1. 实现一个阻塞的字节读取函数

交互式运行需要一个读取用户输入字节的底层接口 __platform_getchar() ,这个接口是一个weak函数,用户需要在自己的代码里面也实现一个 __platform_getchar() 来覆盖这个weak函数。 weak 函数原型在 PikaPlatform.c 里面,如果用户没有覆盖,就会在使用交互式运行时报错。

  1. /* PikaPlatform.c */
  2. PIKA_WEAK char __platform_getchar(void) {
  3. __platform_printf("[error]: __platform_getchar need impaltment!\r\n");
  4. while(1){
  5. }
  6. }

用户可以直接在工程的 main.c 里面实现一个__platform_getchar()。 如果平台本身支持 getchar() ,那么可以直接接入平台的 getchar()

  1. /* main.c */
  2. char __platform_getchar(){
  3. return getchar();
  4. }

如果平台不支持,就需要自己实现,注意要实现一个阻塞getchar(),也就是说,当没有串口输入字符时,要在 __platform_getchar() 中等待,有输入时返回一个字符。 例如:

  1. /* main.c */
  2. char __platform_getchar(){
  3. char res = 0;
  4. while(rx_char == 0){
  5. };
  6. res = rx_char;
  7. rx_char = 0;
  8. return res;
  9. }

10.1.2. 启动PikaScript Shell,直接运行pikaScriptShell()即可启动交互运行。

pikaScriptShell() 入口参数是 pika 的根对象,运行 pikaScriptInit() 就能创建一个根对象。

  1. pikaScriptShell(pikaScriptInit());

10.1.3. 示例代码

stm32g070cb: https://gitee.com/Lyon1998/pikascript/blob/master/bsp/stm32g070cb/Booter/main.c

rt-thread: https://gitee.com/Lyon1998/pikascript/blob/master/package/pikaRTThread/rt_pika.c

10.1.4. 注意事项:

10.1.4.1. 内核版本需要不低于v1.3.0

10.1.4.2. 强烈建议使用putty作为串口终端。

_images/1641178790145-2f026e70-4ba1-4e9a-b05f-c602b2bd8cad.png

10.2. 方案二:整行读取运行

obj_run 内核API可以指定一个对象执行脚本,使用这个API可以执行单行或者多行的脚本。 下面以CH32的交互式运行驱动为例,这个交互式运行的支持写在固件的主循环内,在 pikaScriptInit() 初始化脚本执行完毕之后,开始执行。 _images/1638495382112-7d45db4b-c1d5-4573-a06e-7b72140a3abf.webp

10.2.1. 驱动的内容

10.2.1.1. 轮询接收字符,存入缓冲区。

10.2.1.2. 当超过10ms没有新的字符接收时,认为一次接收完成。

使用空闲时间来判断字符串的传输完成就可以支持交互式运行多行脚本了。如果只需要运行单号脚本,则可以使用换行符 '\n'来判断字符串接收结束。在运行单行脚本时,可以不带 '\n' 换行符,多行脚本需要带 '\n' 换行符。"\r\n" 形式的换行符也是支持的。

10.2.1.3. 接收完成后回显接收到的字符串。

10.2.1.4. 使用 obj_run 内核API执行脚本。

指定的对象是 pikaScriptInit() 初始化脚本创建的根对象,执行的内容是接收到的字符串。

10.2.1.5. 清理接收缓冲区。

10.2.2. 2. 注意事项:

10.2.2.1. 内核版本需要不低于v1.2.6

10.2.2.2. 在执行多行脚本时,需要传入完整的代码块

例如:下面的脚本是完整的代码块,尤其需要注意的是第4行,需要有一个缩进为0的行,用来标志代码块的结束。以及最后一行需要有一个空行,这意味着 print('the end') 这行脚本末尾带有换行符。

  1. while a < 10
  2. a = a + 1
  3. print(a)
  4. print('the end')

以下的例子也是可以的

  1. while a < 10
  2. a = a + 1
  3. print(a)

以下的例子是不行的

  1. # 缺少最后的换行符
  2. while a < 10
  3. a = a + 1
  4. print(a)
  1. # 缺少while代码块的内容
  2. while a < 10