2021-08-27 14:39:49 +08:00
|
|
|
|
## 3.Pikascript标准开发流程
|
|
|
|
|
|
2021-08-27 14:22:03 +08:00
|
|
|
|
本篇文档将会介绍基于PikaScript开发的标准流程,这个标准流程将会涵盖大部分情况下会用到的PikaScript相关技术。
|
|
|
|
|
|
2021-08-27 14:42:02 +08:00
|
|
|
|
我们依然以keil的仿真工程为例,如果还没有获得仿真工程,请参考[1.三分钟快速上手](1.三分钟快速上手.md)
|
2021-08-25 16:07:07 +08:00
|
|
|
|
|
2021-08-27 16:28:23 +08:00
|
|
|
|
## (1). 使用已有的PikaScript类包
|
2021-08-27 14:49:18 +08:00
|
|
|
|
|
2021-08-27 16:30:18 +08:00
|
|
|
|
### a) PikaScript类包与包接口
|
2021-08-27 19:01:32 +08:00
|
|
|
|
我们打开pikascript文件夹,发现文件夹根目录下除了main.py,还有Device.py,PikaObj.py和PikaStdLib.py,这三个.py文件分别对应三个PikaScript***类包***(class package),简称***包***(package),每个.py文件本身称为***包接口***(package interface)。一个类包中可以包含若干个相关性较强的类。
|
2021-08-27 14:50:53 +08:00
|
|
|
|
|
2021-08-27 14:49:18 +08:00
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131083885-a78befe9-7aee-4bae-84cc-86c81eef7622.png)
|
|
|
|
|
|
2021-08-27 15:59:16 +08:00
|
|
|
|
每一个PikaScript***类包***由***包接口***和***包实现***(package implement)两部分组成。
|
2021-08-27 14:50:53 +08:00
|
|
|
|
|
2021-08-27 15:59:16 +08:00
|
|
|
|
我们先打开Device.py查看一下内容,在后续的文档中我们会称Device.py为***Device包接口***。
|
2021-08-27 14:49:18 +08:00
|
|
|
|
|
2021-08-27 14:54:42 +08:00
|
|
|
|
以下就是Device.py的全部内容。
|
|
|
|
|
|
2021-08-27 14:54:07 +08:00
|
|
|
|
``` python
|
2021-08-27 14:54:18 +08:00
|
|
|
|
# Device.py
|
2021-08-27 14:54:07 +08:00
|
|
|
|
from PikaObj import *
|
|
|
|
|
|
|
|
|
|
class LED(TinyObj):
|
|
|
|
|
def on():
|
|
|
|
|
pass
|
|
|
|
|
def off():
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
class Uart(TinyObj):
|
|
|
|
|
def send(data:str):
|
|
|
|
|
pass
|
|
|
|
|
def setName(name:str):
|
|
|
|
|
pass
|
|
|
|
|
def printName():
|
|
|
|
|
pass
|
|
|
|
|
```
|
2021-08-27 14:57:45 +08:00
|
|
|
|
|
2021-08-27 14:59:33 +08:00
|
|
|
|
可以看到,Device.py中使用pyhon标准语法定义了两个类,分别是`LED`类和`Uart`类,这两个类都继承自```TinyObj```。
|
2021-08-27 14:57:45 +08:00
|
|
|
|
|
2021-08-27 15:02:23 +08:00
|
|
|
|
LED类中定义了两个方法,分别是`on()`方法和`off()`方法,而`Uart`类则定义了`send(data:str)`方法、`setName(name:str)`方法和`printName()`方法。
|
|
|
|
|
|
2021-08-27 15:58:43 +08:00
|
|
|
|
可以看到,这些方法都有一个特点,与其说这是方法的***定义***,不如说是方法的***声明***,因为所有的方法实现都pass掉了,都没有写实现。而且方法的入口参数都是带有***类型声明***的。比如`data:str`就表示一个`data`参数,参数类型为`str`即字符串类型。
|
2021-08-27 15:02:23 +08:00
|
|
|
|
|
2021-08-27 16:02:44 +08:00
|
|
|
|
这是因为这个包的包实现是由C语言编写的,也就是说,PikaScript的所有类包,都是使用python语法编写声明,而使用C语言编写实现。PikaScript的类包开发是一种***面向接口***编程的***混合编程***技术。
|
2021-08-27 16:01:53 +08:00
|
|
|
|
|
2021-08-27 16:10:08 +08:00
|
|
|
|
然而在使用已有的类包时,是不需要了解包实现的,只需要了解包接口,即可使用这个类包。
|
|
|
|
|
|
2021-08-27 16:30:18 +08:00
|
|
|
|
### b) 导入并调用包
|
2021-08-27 16:10:08 +08:00
|
|
|
|
|
|
|
|
|
下面我们看一下如何使用这个类包。
|
|
|
|
|
|
|
|
|
|
我们打开工程中的main.py,见名知意,这个文件是PikaScript的入口文件。
|
|
|
|
|
|
|
|
|
|
main.py的内容如下
|
|
|
|
|
|
|
|
|
|
``` python
|
|
|
|
|
# main.py
|
|
|
|
|
from PikaObj import *
|
|
|
|
|
import Device
|
|
|
|
|
import PikaStdLib
|
|
|
|
|
|
|
|
|
|
led = Device.LED()
|
|
|
|
|
uart = Device.Uart()
|
|
|
|
|
mem = PikaStdLib.MemChecker()
|
|
|
|
|
|
|
|
|
|
print('hello wrold')
|
|
|
|
|
uart.setName('com1')
|
|
|
|
|
uart.send('My name is:')
|
|
|
|
|
uart.printName()
|
|
|
|
|
print('mem used max:')
|
|
|
|
|
mem.max()
|
|
|
|
|
print('mem used now:')
|
|
|
|
|
mem.now()
|
|
|
|
|
```
|
|
|
|
|
|
2021-08-27 16:13:49 +08:00
|
|
|
|
导入一个已经编写好的类包是非常简单的,比如导入Device包,只需要`import Device`即可,要注意的是所有的.py文件应当放在pikascript文件架的根目录下。
|
2021-08-27 16:10:08 +08:00
|
|
|
|
|
2021-08-27 16:13:49 +08:00
|
|
|
|
然后使用Device中的LED类新建对象,只需要写一句`uart = Device.Uart()`即可,这表示新建一个`uart`对象,这个对象的类是Device包中的Uart类。
|
|
|
|
|
|
|
|
|
|
调用方法则使用`uart.setName('com')`这种形式,这都是Python的标准语法,不需要过多介绍。
|
2021-08-27 16:16:01 +08:00
|
|
|
|
|
|
|
|
|
在main.py中写好包的调用后,双击rust-msc-v0.5.0.exe即可预编译PikaScript工程,预编译的输出文件在pikascrip-api文件夹内。
|
|
|
|
|
|
2021-08-27 16:20:08 +08:00
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131095540-46b38726-8fda-4b10-94f1-5af31ae7a792.png)
|
2021-08-27 16:16:01 +08:00
|
|
|
|
|
2021-08-27 16:20:08 +08:00
|
|
|
|
pika预编译器会为导入的包生成.h声明文件和-api.c构造器文件。文件名以包名开头,每个类对应一个.h文件和一个-api.c文件。
|
2021-08-27 16:16:01 +08:00
|
|
|
|
|
2021-08-27 16:20:08 +08:00
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131096295-8b1b2161-cb59-45e6-92f3-eb2cf79a47f7.png)
|
2021-08-27 16:24:22 +08:00
|
|
|
|
|
|
|
|
|
而PikaMain-api.c和PikaMain.h则是对应了一个特殊的类,这个类是PikaScript的主类,由main.py编译而成。
|
2021-08-27 16:26:04 +08:00
|
|
|
|
|
2021-08-27 16:24:22 +08:00
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131096521-569e30a0-876e-4bb5-bfd3-0c01b6b8a38f.png)
|
|
|
|
|
|
|
|
|
|
pikaScript.c和pikaScript.h则是根据main.py编译出的初始化函数,运行初始化函数时,会自动执行启动脚本。
|
2021-08-27 16:26:04 +08:00
|
|
|
|
|
2021-08-27 16:24:22 +08:00
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131096760-20592a84-bbc1-4b61-a57f-299183983adf.png)
|
|
|
|
|
|
2021-08-27 16:26:55 +08:00
|
|
|
|
在现在的main.py中,启动脚本是写在最外层的方法调用,也就是:
|
2021-08-27 16:25:14 +08:00
|
|
|
|
``` python
|
2021-08-27 16:24:22 +08:00
|
|
|
|
print('hello wrold')
|
|
|
|
|
uart.setName('com1')
|
|
|
|
|
uart.send('My name is:')
|
|
|
|
|
uart.printName()
|
|
|
|
|
print('mem used max:')
|
|
|
|
|
mem.max()
|
|
|
|
|
print('mem used now:')
|
|
|
|
|
mem.now()
|
|
|
|
|
```
|
2021-08-27 16:25:14 +08:00
|
|
|
|
|
|
|
|
|
编译出的pikaScriptInit()初始化函数对应的是:
|
|
|
|
|
|
|
|
|
|
``` c
|
|
|
|
|
PikaObj * pikaScriptInit(){
|
|
|
|
|
PikaObj * pikaMain = newRootObj("pikaMain", New_PikaMain);
|
|
|
|
|
obj_run(pikaMain, "print('hello wrold')");
|
|
|
|
|
obj_run(pikaMain, "uart.setName('com1')");
|
|
|
|
|
obj_run(pikaMain, "uart.send('My name is:')");
|
|
|
|
|
obj_run(pikaMain, "uart.printName()");
|
|
|
|
|
obj_run(pikaMain, "print('mem used max:')");
|
|
|
|
|
obj_run(pikaMain, "mem.max()");
|
|
|
|
|
obj_run(pikaMain, "print('mem used now:')");
|
|
|
|
|
obj_run(pikaMain, "mem.now()");
|
|
|
|
|
return pikaMain;
|
|
|
|
|
}
|
|
|
|
|
```
|
2021-08-27 16:28:23 +08:00
|
|
|
|
|
2021-08-27 16:28:37 +08:00
|
|
|
|
## (2) 编写新的PikaScript类包
|
2021-08-27 19:01:32 +08:00
|
|
|
|
|
2021-08-27 19:09:09 +08:00
|
|
|
|
### a)新建包接口
|
2021-08-27 19:01:32 +08:00
|
|
|
|
|
|
|
|
|
编写一个新的类包,首先需要编写包接口文件,比如编写一个数学计算类包Math,第一步是编写Math.py,包名首字母应当大写。
|
|
|
|
|
|
2021-08-27 19:11:35 +08:00
|
|
|
|
如果要从PikaScript基本类中创建新的类,则需要import PikaObj类包,导入PikaObj类包应使用`from PikaObj import *`的引入方式,实际上Pika预编译器是不会编译使用`form`语法导入的包的,这样写只是为了获得python编辑器的只能语法提示,PikaObj是内置于Pika运行时内核的。。
|
2021-08-27 19:01:32 +08:00
|
|
|
|
|
|
|
|
|
``` python
|
|
|
|
|
# Math.py
|
|
|
|
|
from PikaObj import *
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
我们可以打开PikaObj.py文件查看里面的类接口
|
|
|
|
|
|
|
|
|
|
``` python
|
|
|
|
|
class TinyObj:
|
|
|
|
|
pass
|
|
|
|
|
class BaseObj(TinyObj):
|
|
|
|
|
pass
|
|
|
|
|
def print(val: any):
|
|
|
|
|
pass
|
|
|
|
|
def set(argPath: str, val: any):
|
|
|
|
|
pass
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
可以看到里面有`TinyObj`和`BaseObj`两个类,这两个类是由PikaScript内核实现的基本类,TinyObj是没有任何功能的最基本的类,内存占用最少,`BaseObj`和`TinyObj`相似,但是`BaseObj`可以挂载子对象。
|
|
|
|
|
|
|
|
|
|
`print(val: any)`表示输入参数为泛型的函数,`set(argPath:str, val:any)`也是泛型函数,这两个函数由内核实现,PikaScript类包目前还不支持自定义泛型函数。
|
|
|
|
|
|
2021-08-27 19:09:09 +08:00
|
|
|
|
### b)编写类接口
|
2021-08-27 19:01:32 +08:00
|
|
|
|
|
2021-08-27 19:06:42 +08:00
|
|
|
|
现在我们可以在Math.py里面新建类了,比如我们要新建一个`Adder`类来实现相关的加法运算,我们就可以在Math.py里面添加Adder类,为了节省内存,Adder类从TinyObj基类中继承。
|
|
|
|
|
|
|
|
|
|
然后我们希望Adder可以为整形、浮点型数据提供加法运算,那么就可以添加addInt方法和addFloat方法。
|
2021-08-27 19:01:32 +08:00
|
|
|
|
|
|
|
|
|
``` python
|
|
|
|
|
# Math.py
|
2021-08-27 19:06:42 +08:00
|
|
|
|
class Adder(TinyObj):
|
2021-08-27 19:12:33 +08:00
|
|
|
|
def byInt(a:int, b:int)->int:
|
2021-08-27 19:13:08 +08:00
|
|
|
|
pass
|
2021-08-27 19:12:33 +08:00
|
|
|
|
def byFloat(a:float, b:float)->float:
|
2021-08-27 19:13:08 +08:00
|
|
|
|
pass
|
2021-08-27 19:01:32 +08:00
|
|
|
|
```
|
|
|
|
|
|
2021-08-27 19:06:42 +08:00
|
|
|
|
上面的一段代码中我们定义了`Adder`类,并添加了两个方法的声明,`byInt(a:int,b:int)->int`表示方法名为byInt,输入参数为`a`和`b`,`a`和`b`的类型都是`int`型,而返回值也是`int`型,返回值由`->int`来确定,这都是python的标准语法,是带类型声明的写法。
|
2021-08-27 19:04:22 +08:00
|
|
|
|
|
2021-08-27 19:06:42 +08:00
|
|
|
|
我们再向math.py里面添加一个Multiplier类,用来实现乘法,Multiplier的写法如下所示,Multiplier类同样从`TinyObj`基类中继承:
|
2021-08-27 19:04:22 +08:00
|
|
|
|
|
|
|
|
|
``` python
|
|
|
|
|
# Math.py
|
2021-08-27 19:06:42 +08:00
|
|
|
|
class Multiplier(TinyObj):
|
2021-08-27 19:12:33 +08:00
|
|
|
|
def byInt(a:int, b:int)->int:
|
2021-08-27 19:13:08 +08:00
|
|
|
|
pass
|
2021-08-27 19:12:33 +08:00
|
|
|
|
def byFloat(a:float, b:float)->float:
|
2021-08-27 19:13:08 +08:00
|
|
|
|
pass
|
2021-08-27 19:04:22 +08:00
|
|
|
|
```
|
2021-08-27 19:09:09 +08:00
|
|
|
|
到此类接口就编写完成了。我们在main.py中引入Math包,这样Pika预编译器就会去编译Math类包了。
|
|
|
|
|
|
2021-08-27 19:16:11 +08:00
|
|
|
|
```
|
|
|
|
|
# main.py
|
|
|
|
|
import Math
|
|
|
|
|
```
|
|
|
|
|
|
2021-08-27 19:15:32 +08:00
|
|
|
|
双击运行pika预编译器。
|
|
|
|
|
|
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131119247-ae25276e-f7c9-49ef-81e1-dbddcaffdf6c.png)
|
|
|
|
|
|
|
|
|
|
打开pikascript-api文件夹可以发现,我们新编写的类包接口已经可以被编译出来了。
|
|
|
|
|
|
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131119310-99564d6a-d570-4375-9c01-c2d7cde74655.png)
|
|
|
|
|
|
2021-08-27 19:09:09 +08:00
|
|
|
|
|
2021-08-27 19:24:04 +08:00
|
|
|
|
### c)编写类的实现
|
|
|
|
|
|
|
|
|
|
我们把刚刚新编译出的两个-api.c文件添加到工程,然后编译一下试试。
|
|
|
|
|
|
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131119636-3c3d52ce-a7c2-48a4-beb4-5498dfd4f279.png)
|
|
|
|
|
|
|
|
|
|
发现编译报错了,提示是有四个函数没有找到定义。
|
|
|
|
|
|
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131119786-823a96e3-7ab3-45f8-8c7c-282ba9b7b863.png)
|
|
|
|
|
|
|
|
|
|
这是正常的,因为我们之前并没有为Math包的类编写实现,下面我们就来编写这些类的实现。
|
|
|
|
|
|
|
|
|
|
为了包管理的方便,我们把实现文件都放在pikascript-lib文件夹下,
|
|
|
|
|
|
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131120029-81c9b91f-2669-40cf-86da-78d72bce81c8.png)
|
|
|
|
|
|
|
|
|
|
在pikascript-lib文件夹下,新建一个Math文件夹,用来放Math包的实现代码。
|
|
|
|
|
|
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131120240-a4001fa4-1fd2-4b6b-82a2-191834ed781b.png)
|
2021-08-27 19:27:04 +08:00
|
|
|
|
|
2021-08-27 19:27:48 +08:00
|
|
|
|
然后在Math文件夹下新建.c文件,建议用"包名_类名.c"的命名方式为每一个类新建一个.c文件,提高代码的清晰性。
|
2021-08-27 19:27:32 +08:00
|
|
|
|
|
|
|
|
|
![image](https://user-images.githubusercontent.com/88232613/131120619-45ae3520-7b63-434b-8831-5b4d9f900cad.png)
|
2021-08-27 19:31:54 +08:00
|
|
|
|
|
|
|
|
|
然后我们在这两个.c文件里面编写类的方法实现。那么问题来了,我们如何知道应当编写哪些实现呢?
|
|
|
|
|
|
|
|
|
|
这个很简单,我们打开Math_Multiplier.h和Math_Adder.h就可以发现,我们需要编写的实现函数已经被声明好了。
|
|
|
|
|
|
|
|
|
|
``` c
|
|
|
|
|
/* Math_Multiplier.h */
|
|
|
|
|
/* ******************************** */
|
|
|
|
|
/* Warning! Don't modify this file! */
|
|
|
|
|
/* ******************************** */
|
|
|
|
|
#ifndef __Math_Multiplier__H
|
|
|
|
|
#define __Math_Multiplier__H
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include "PikaObj.h"
|
|
|
|
|
|
|
|
|
|
PikaObj *New_Math_Multiplier(Args *args);
|
|
|
|
|
|
|
|
|
|
float Math_Multiplier_byFloat(PikaObj *self, float a, float b);
|
|
|
|
|
int Math_Multiplier_byInt(PikaObj *self, int a, int b);
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
```
|
2021-08-27 19:32:48 +08:00
|
|
|
|
|
|
|
|
|
``` c
|
|
|
|
|
/* Math_Adder.h */
|
|
|
|
|
/* ******************************** */
|
|
|
|
|
/* Warning! Don't modify this file! */
|
|
|
|
|
/* ******************************** */
|
|
|
|
|
#ifndef __Math_Adder__H
|
|
|
|
|
#define __Math_Adder__H
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include "PikaObj.h"
|
|
|
|
|
|
|
|
|
|
PikaObj *New_Math_Adder(Args *args);
|
|
|
|
|
|
|
|
|
|
float Math_Adder_byFloat(PikaObj *self, float a, float b);
|
|
|
|
|
int Math_Adder_byInt(PikaObj *self, int a, int b);
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
```
|
2021-08-27 19:36:04 +08:00
|
|
|
|
|
|
|
|
|
然后我们直接在Math_Adder.c和Math_Multipler.c里面去实现这两个函数就ok了。
|
|
|
|
|
|
|
|
|
|
``` c
|
|
|
|
|
/* Math_Adder.c */
|
|
|
|
|
#include "pikaScript.h"
|
|
|
|
|
|
|
|
|
|
float Math_Adder_byFloat(PikaObj *self, float a, float b)
|
|
|
|
|
{
|
|
|
|
|
return a + b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Math_Adder_byInt(PikaObj *self, int a, int b)
|
|
|
|
|
{
|
|
|
|
|
return a + b;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
``` c
|
|
|
|
|
/* Math_Multipler.c */
|
|
|
|
|
#include "pikaScript.h"
|
|
|
|
|
|
|
|
|
|
float Math_Multiplier_byFloat(PikaObj *self, float a, float b)
|
|
|
|
|
{
|
|
|
|
|
return a * b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Math_Multiplier_byInt(PikaObj *self, int a, int b)
|
|
|
|
|
{
|
|
|
|
|
return a * b;
|
|
|
|
|
}
|
|
|
|
|
```
|
2021-08-27 19:39:39 +08:00
|
|
|
|
|
|
|
|
|
这时,再编译项目,就可以通过了。
|