分类 未分类 下的文章
Javascript On MCU
命令行读取注册表键值
reg query HKEY_CLASSES_ROOT\.xlsx
Uibot使用Python扩展
官方原文: 【插件开发】使用 Python 扩展 UiBot 的功能
主要步骤
- 在
uibot
安装目录下面的extend\python
中放置xxx.py
文件即可在uibot
中使用import xxx
引入定义的函数使用. - 官方包在安装目录的
lib\site-packages
下, 如果不够用就需要自己复制粘贴过来. 当然更棒的方法是用pip直接装到这个目录下, 加上--target=
即可:Pip install gooey --target="D:\myprog\UiBot Creator Community 5.5.0 (x64)\lib\site-packages"
两者传参和返回值的测试
- 所以如果在py中定义了新的函数, 或者修改了形参数量需要在uibot中调用, 则需要重启creator. 因为py中def的函数名和形参是在启动creator的时候加载的, 然而函数体是实时从py函数体中调用的.
- py返回值中, int/float/string/list/dict/tuple类型都能正确识别,请知tuple是被当做list识别的. 但
type
类型不能识别, 所以不能return type(1)
, 需要转为string:str()
- py形参中, 从uibot串入的int/float/str/list/dict都能正确识别.
- py中的
print
并不能输出到uibot的输出窗口. - python的内置库和第三方库都是不能直接'import'的, 需要写个py中转一下
从Uibot注入Python代码直接运行 (简版)
定义一个中转py,命名为run.py
, 如下:
def e(func, runfunc):
exec(func)
return eval(runfunc)
第一个参数由exec()执行,没有返回值, 适合定义函数. 第二个参数由eval执行, 有返回值, 适合运行函数.
在uibot中直接运行python代码, 例如:
Import Run
Log.Info(Run.e("def add(a, b):\n return a+b", "add(1,2)"))
将会返回3
这样就不需要对uibot开开关关的了, 可以直接调试. 另外也不需要再跑到extend\python
中去更新py文件.
从Uibot注入Python代码直接运行 (强化版)
上面的简版无法从Uibot中读取变量, 下面这个版本则解决这个问题
# p = { # params
# g:{}, # eval(,g,)
# l:{}, # eval(,,l)
# f:['functionName1', 'functionName2'...], # function names from exec()
#}
def e(func, runfunc, p):
exec(func)
if 'g' in p:
if 'f' in p:
for fn in p['f']:
p['g'][fn] = eval(fn)
if 'l' in p:
return eval(runfunc, p['g'], p['l'])
return eval(runfunc, p['g'])
return eval(runfunc)
解释: 增加了一个参数p, 用于给eval输入Uibot的变量. eval支持globals和locals变量的输入, 这儿都给用上了, 分别是p['g']
和p['l']
. 按eval
要求p['g']
必须是一个dict,也即是{}
要注意的是, 输入的变量会冲掉以前的变量, 也就是在exec
中定义的函数名也会被globals完全替代掉, 所以如果要用globals就必须重新在globals中引入函数名, 所以又增加了p['f']
来输入函数名字符串的数组, 并将其用eval(fn)
转换为真正的函数地址,输入给p['g']
必须要注意的是python的dict的子元素key的引用必须用数组形式加引号如p['f']
, 这有时候显然不如js方便p.f
在uibot中直接运行python代码:
ret= Run.e('def add(a,b):\n return a+b', 'add(x,y)',{'f':['add'], 'g':{'x':1,'y':2}} )
Log.Info(ret)
显示-1
从Uibot注入Python代码直接运行 (强化版V2.0)
然而上面这样的调用方式还是很麻烦, 有没有更加简单的?
然而不管怎么试, 都没有办法做到直接在Uibot里面运行add(1,2)
这样的形式, 从Python返回的函数指针到了Uibot里只被认作一个普通的python对象, 如果用Type查看, 居然还是String类型, 而不是function类型.
曲线救国的方式, 在res目录下新建三个文件, 分别是:
func.py
def add(a, b):
return a + b
runfunc.py
add(a1, a2)
p.json
{
"f": ["add"],
"g": {"a1": 1, "a2":2},
"l": {}
}
然后新建一个公共流程块命名为pub, 内容如下:
/*
语法糖, 可以让Uibot实时调用func.py中动态定义的函数, 如add, 形式为:
run.e("add", [1,2])
funcName: string,
funcParam: arr.
*/
Function e(sFuncName, arrFuncParam)
Import run
sFunc = File.Read(@res"func.py","auto")
sRunFunc = sFuncName & "("
dictP = {"f": [sFuncName],
"g": {} }
//组装成 funcName(a1,a2,a3...)这样的形式
For i=1 To Len(arrFuncParam)
sRunFunc = sRunFunc & 'a' &CStr(i)
dictP['g']['a' &CStr(i)] = arrFuncParam[i-1]
If Len(arrFuncParam) = i
sRunFunc = sRunFunc & ')'
Else
sRunFunc = sRunFunc & ','
End If
Next
Return Run.e(sFunc, sRunFunc, dictP )
End Function
/*
直接运行在func.py, runfunc.py p.json中定义的函数及参数
*/
Function py()
Import run
sFunc = File.Read(@res"func.py","auto")
sRunFunc = File.Read(@res"runfunc.py","auto")
dictP = JSON.Parse(File.Read(@res"p.json","auto"))
Return Run.e(sFunc, sRunFunc, dictP )
End Function
这样在普通的流程块里就可以这样调用了:
pub.e("add",[1,2])
虽然和add(1,2)
有些差距, 但怎么说都舒服多了不是. 也可以完全从文件调用:
pub.py()
Uibot和python怎么分工?
- 我觉得Uibot对界面的处理使强项, 对逻辑处理就要差很多了, 这部分用python似乎更好.
- 另外Python库很丰富, 可以扩展出很多应用.
- Uibot对用户输入的界面也比较弱. Python中有一个Gooey看起来要好用的多.
uiBot认证过程
- 初级认证考试, 70分理论30分编程, 60分过. 然后申请证书.
- 中级认证考试, 70分理论30分编程, 60分过. 然后申请证书.
- 有中级证书后, 申请开发者认证, 再上传一个编程题.
- 通过开发者认证后,会有客服加QQ联系, 然后询问高级认证的证书获取方式;
- 客服让加另一个QQ, 联系后得知的认证方式如下:
您好,非常感谢您对UB Store的支持,参与高级认证的要求如下: 1、必须是已经入驻UB Store开放平台的开发者,开放平台地址:https://docs.qq.com/doc/DSkNqRmhFeE5weXJ0?pub=1&dver=2.1.0 2、必须有至少一个机器人上传至UB Store商店,机器人上传指南:https://forum.uibot.com.cn/thread-7191.htm
如已达到要求,请提供工作室名称和认证电话号码
gdb调试
参考
GDB调试工具
GDB程序启动和断点设置
GDB观察和捕捉断点
GDB条件断点
GDB单步调试程序
GDB断点调试详解
GDB查看变量值 print和display
GDB禁用删除断点
GDB调试多线程程序
GDB non-stop模式
GDB后台调试命令
GDB调试多进程程序
GDB反向调试
GDB信号处理
GDB查看栈信息
GDB编辑、搜索源码以及在线帮助
准备
首先, gdb 调试的必须是gcc -g
编译出来的.-g
是将必要的符号和源码编入了.
gcc -g xxxxx.c xxxx.c
对生成的a.exe
编译
进入
运行
gdb a.exe
进入gdb命令行. 常见命令如下, 大多数命令都支持首字母简写:
|名称|意义|
--|--
run|运行
list|列出源码
break 函数名/文件名:行号 [if varname=value] | 插入断点
info break|显示断点
delete n |删除第n个断点
disable n | 禁用第n个断点
enable n| 启用第n个断点
print varname|显示变量
set var varname=value |设置变量
next|执行到下一句
next n|执行到下n句
step|执行进入
return [value]|函数强制返回
finish |执行到当前函数返回处
until linenum|执行到行号
jump linenum|跳转到行号
C语言编程的坑
好久没有写过C, 下面总结下一些坑, 填坑的过程不仅感慨js/python大法好啊!
enum与typedef enum
enum 定义类型后, 再定义变量前面还要把enum加上, 否则会报错
enum TTT{A, B, C};
enum TTT ttt; //不能写作 TTT ttt;
但这个很烦人不是么, typedef的作用就来了:
typedef enum _TTT{A, B, C}TTT;
TTT ttt; //再没有讨厌的enum了
enum定义的变量至少占1个int字节
注意上面enum定义的变量至少占1个int字节,最多占1个longlong字节, 具体是编译器根据enum中的最大值确定的. 在某些RAM捉襟见肘的MCU上(比如51上只有128字节), 1int = 2byte, 真的是大大的浪费. 这时候还不如用#define
大法...
#define A 0
#define B 1
#define C 2
全局变量在哪儿定义?在哪儿声明?
首先定义的方式是: int g = 0;
(必须初始化)
声明的方式是加extern
, 如: extern int g;
全局变量必须且只能在.c
中定义(且初始化), 必须且只能在.h
中声明. 当然如果其他.c文件不需要使用这个全局变量的话, 就不需要在.h中extern
它.
原因1: 全面变量在.h
中定义的话, .h
文件的相互引用一定会造成编译器报错重复定义. 而且似乎用#ifndef
大法也没有用;
原因2: 全局变量在.c
中声明的话, 如果不同的.c
文件都要使用的时候, 声明很可能重复且不一致,造成编译器报警.
#define
, enum
, typedef
, 函数在哪儿声明?
我感觉, 如果是要让其他C程序使用的, 就在.h
中声明, 否则, 就在本.c
文件前面声明, 虽然这样c文件前面会很啰嗦...
这样在.c
中声明的部分就像是private的, 在.h
中声明的部分就像是public的.
C语言单元测试库CuTest的使用
CuTest官网
下面讲的是基于Windows平台的编译工具cl.exe
(Visual Studio附带)的测试方式.
准备
首先建立一个test
文件夹, 将CuTest.h
和CuTest.c
丢进去;
创建入口,加入测试集
- 在这个目录下建立
AllTests.c
文件, 作为测试的入口文件, 并且将所有测试集(TestSuite)加入到测试中, 如下:#include <stdio.h> #include "CuTest.h"
CuSuite *StrUtilGetSuite(); //声明测试集, 还可以声明多个
void RunAllTests(void)
{
CuString output = CuStringNew();
CuSuite suite = CuSuiteNew();
CuSuiteAddSuite(suite, StrUtilGetSuite()); //加入测试集
CuSuiteRun(suite);
CuSuiteSummary(suite, output);
CuSuiteDetails(suite, output);
printf("%s\n", output->buffer);
}
int main(void)
{
RunAllTests();
}
一般就是上面有注释的两句需要修改或者添加.
## 创建单元测试文件和测试集
假如被测试的函数是`getKey()`, 在`maintask.c`这个文件中, 并且`maintask.c`有一个对应头文件`maintask.h`
创建这个文件的测试文件`testMaintask.c`,如下:
```c
#include "maintask.h"
#include "CuTest.h"
void testGetKey(CuTest *tc) //创建单个测试
{
// 测试信息, 测试条件
CuAssert(tc, "Test getKey()", getKey());
}
CuSuite *testSuite1() //创建测试集
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, testGetKey); //加入单个测试
return suite;
}
加入stub头文件
比如在maintask.c
中, 除了自身对应的头文件外, 还有其他头文件,如wm_include.h
, 但这些头文件涉及的整个系统, 还有很多其他函数, 我不想加入, 而是想把其中有的函数打桩掉. 那么, 在test
目录下新建这个头文件wm_include.h
,作为打桩文件, 里面自行加入要打桩的函数即可.
编译和运行测试(基于cl.exe)
如果test
目录是和maintask.c
待测文件同一级, 其头文件maintask.h
在这一级, 而wm_include.h
在test
中, 那么需要有cl
的/I
参数将这两个目录包含进来. 如/I.\ /I..\
,注意/I
带的目录后面是没有空格的.
cl /I..\ /I.\ ..\maintask.c Alltests.c CuTest.c testMaintask.c
将会输出:
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.16.27032.1 版
版权所有(C) Microsoft Corporation。保留所有权利。
maintask.c
Alltests.c
CuTest.c
testMaintask.c
正在生成代码...
Microsoft (R) Incremental Linker Version 14.16.27032.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:maintask.exe
maintask.obj
Alltests.obj
CuTest.obj
testMaintask.obj
运行maintask.exe
即可看到测试结果.
编译和运行测试(基于gcc.exe)
如果test
目录是和maintask.c
待测文件同一级, 其头文件maintask.h
在这一级, 而wm_include.h
在test
中, 那么需要有gcc
的-I
参数将这两个目录包含进来. 如-I..`,注意-I
带的目录后面是没有空格的. 要包含当前目录, 不知为何-I.\
不能使用, 必须要先退上一级再下来一级才可以, 如-I..\test\
另外, 加上-g
可以方便gdb
进行调试.
gcc -I..\ -I..\test\ ..\maintask.c Alltests.c CuTest.c testMaintask.c
如果gcc
编译没有任何问题,那么它什么都不会输出, 然后产生一个a.exe
的文件.
不过gcc
的代码检查要比cl
强度高很多.
运行a.exe
即可看到测试结果.
状态机
i2c七宗罪
micropython入门与坑
坑1
用PIN模拟做时序是万万不能的, 在w601上执行一个pin的0/1转换就需要50us, 做一个utime.sleep_us(1)
也需要50us,在us级的时序是无法做的,差不多要到ms级的时序才有可能. 这在很多芯片需要自定义时序的时候就没法子了.
网上说可以打包C库供MicroPython调用.
mpip.install()
支持mpip.install进行额外的库安装,不过就是不知道在哪儿搜索可用的库.
i2c/iic入门
w601编译micropython
坑1
除了按官方指导外, 似乎mpy-cross
目录下需要单独make
一次, 否则会报错找不到mpy-cross
.
参考: http://bbs.eeworld.com.cn/thread-579242-1-1.html
坑2
必须使用说明书中推荐的arm-none-eabi-gcc 4.9版本, 而不要用最新的版本(目前是10.x版了).用新版本编译出来的固件会增大不少,导致1M flash里面放不下.
如果已经用高版本arm-none-eabi-gcc编译过, 需要make clean
一次后再次make
PL2303串口转USB驱动千万不要用官网的
如果用了官网的, 就会在设备管理器
中出现PL2303HXA自2012已停产,请联系供货商
, 解决方案是使用旧驱动.
驱动要使用2008年的旧驱动才行, 如果已经安装了新驱动, 重新运行安装程序, 选择将驱动remove
掉.
旧驱动参考:解决"PL2303HXA自2012已停产,请联系供货商" USB不识别的问题
考虑钉钉/企业微信与camunda结合,各种文章
重点是钉钉吧~
钉钉 - 弹性计算OOS审批流程自动化运维, 这儿与钉钉的主要结合是通过群助手机器人Webhook向钉钉推送消息.
Camunda - Alert Notification Webhooks
Python与Camunda结合: External task/script task