该流程对于功能单一或者功能变更极少的场景是比较友好的,但是对于设备应用层变更比较多或者公板方案开发应用的场景,上述场景显的有些累赘。那么有什么方式可以解决呢??
对于设备应用层变更比较多或者公板方案开发应用的场景,可能因为应用层稍微修改一下就要出固件版本验证,这对于版本管理,时间周期,固件质量都是比较不友好的。那么我们如何避免这些问题??
那么有什么方式呢??答案是有的,如:使用动态模块或者胶水语言(JerryScript,PikaScript)
上述两种方式都是可以使固件跟应用分离,是的应用的变更不会引起固件的变更,这对于固件的稳定性来说更加有保障。只需要测试单独的应用程序。
动态模块 | 胶水语言 | |
---|---|---|
API问题 | 运行固件需要特殊处理,需要将API导出 | 通过对应的引擎编写API导出模块 |
应用形式 | 应用程序需要通过固件编译出对应的ELF文件 | 胶水语言无需编译,直接可通过对应引擎加载运行 |
JerryScript | PikaScript | |
---|---|---|
资源占用 | RAM <= 64KB, Flash <= 200KB | RAM <= 4KB, Flash <= 32KB |
语言 | JavaScript | Python |
地域 | 海外 | 中国 |
维护情况 | 停止维护 | 持续维护 |
开发对象 | 懂得前端的人员也可以接手嵌入式应用开发 | 需要熟悉python语言 |
开发难度 | 一般 | 一般 |
使用情况 | UI厂商都是用,柿饼,ACE | 相对较少 |
物联网设备在CPU性能和内存空间方面皆存在严格受限,在使用V8引擎这类大型引擎时难免存在诸多不便。在此背景下,JerryScript引擎诞生了。JerryScript是由三星开发的一款炙手可热的轻量级引擎,其目的是让JavaScript开发者能够更好地构建物联网应用,
JerryScript是一个轻量级的JavaScript引擎,用于资源受限的设备,如微控制器。它可以在RAM小于64KB、闪存小于200KB的设备上运行。
英文 | 中文 | 链接 |
---|---|---|
Getting Started | 入门 | https://github.com/jerryscript-project/jerryscript/blob/master/docs/00.GETTING-STARTED.md |
Configuration | 配置 | https://github.com/jerryscript-project/jerryscript/blob/master/docs/01.CONFIGURATION.md |
API Reference | API参考 | https://github.com/jerryscript-project/jerryscript/blob/master/docs/02.API-REFERENCE.md |
API Example | API示例 | https://github.com/jerryscript-project/jerryscript/blob/master/docs/03.API-EXAMPLE.md |
Internals | 内部构件 | https://github.com/jerryscript-project/jerryscript/blob/master/docs/04.INTERNALS.md |
Migration Guide | 迁移指南 | https://github.com/jerryscript-project/jerryscript/blob/master/docs/16.MIGRATION-GUIDE.md |
目前很多UI厂商都在基于JerryScript作为引擎搭建UI框架,比如像RT-THREAD,OpenHarmony等厂商。而且JerryScript被默认作为第三方组件的形式存在。所以我将以RT-THREAD作为我的开发环境描述JavaScript如何在单片机中运行。
RT-THREAD中已经拥有JerryScript软件包,所以我们需要下载对应软件包即可:
RT-THREAAD的JerryScript已经适配好了,如console打印等,所以我们也不用关心,直接使用。需要包含两个头文件:#include
JerryScript引擎启动流程(初始化):
int main(void)
{/* JERRY_ENABLE_EXTERNAL_CONTEXT */jerry_port_set_default_context(jerry_create_context(PKG_JMEM_HEAP_SIZE * 1024, context_alloc, NULL));/* Initialize engine */jerry_init(JERRY_INIT_EMPTY);js_util_init();return RT_EOK;
}
char *script_test = " var rice = \"Rice JerryScript\"\r\n"" console.log(\"hello!!\", rice);\r\n"" console.log(\"hello JerryScript run ok!!\"); \r\n";void js_parse_test(void)
{jerry_value_t parsed_code = jerry_parse (NULL, 0, (jerry_char_t *)script_test,rt_strlen (script_test), JERRY_PARSE_NO_OPTS);if (jerry_value_is_error(parsed_code)){rt_kprintf("jerry parse failed!\n");}else{jerry_value_t ret2 = jerry_run(parsed_code);rt_kprintf("%s : jerry_run ret=%d\n", __func__, ret2);}
}
MSH_CMD_EXPORT(js_parse_test, js_parse_test);
int mnt_init(void)
{ if (dfs_mount("W25Q256", "/", "elm", 0, 0) == 0){LOG_I("W25Q256 mount successful!");}else{LOG_E("W25Q256 mount failed!");dfs_mkfs("elm", "W25Q256");if (dfs_mount("W25Q256", "/", "elm", 0, 0) == 0){LOG_I("W25Q256 mount successful!");}}return 0;
}
INIT_ENV_EXPORT(mnt_init);
var rice = "Rice JerryScript";console.log("hello!!", rice);
console.log("hello JerryScript run ok!!");
void js_parse_test(void)
{int fd = -1, fileSize = 0;char *fileContent = NULL;fd = open("/rice.js", O_RDONLY, 0777);if(fd < 0) {rt_kprintf("Open %s failed", "/rice.js");return;} else {fileSize = lseek(fd, 0, SEEK_END);lseek(fd, 0, SEEK_SET);fileContent = (char *)rt_malloc(fileSize); read(fd, fileContent, fileSize);close(fd);fd = -1;}jerry_value_t parsed_code = jerry_parse((const jerry_char_t *)"/rice.js", (size_t)strlen("/rice.js"), (const jerry_char_t *)fileContent, (size_t)fileSize, JERRY_PARSE_STRICT_MODE);if (jerry_value_is_error(parsed_code)){rt_kprintf("jerry parse failed!\n");}else{jerry_value_t ret = jerry_run(parsed_code);rt_kprintf("%s : jerry_run ret=%d\n", __func__, ret);}
}
MSH_CMD_EXPORT(js_parse_test, js_parse_test);
关注微信公众号『Rice嵌入式开发技术分享』,后台回复“微信”添加作者微信,备注”入群“,便可邀请进入技术交流群。