Skip to content

QuickJS

JS 移植于Quickjs
QuickJS是一个小型的嵌入式Javascript引擎。它几乎完整支持ES2020规范,包括Promise,箭头函数,模块、异步生成器、代理和 BigInt。

  • 小巧且易于嵌入集成,只需几个 C 文件,无外部依赖
  • 启动时间极短的快速解释器
  • 几乎完整的ES2020支持,包括模块,异步生成器。是其它嵌入式JS引擎不可比拟的。

QuickJS作者 Fabrice Bellard。

法布里斯·贝拉法国著名的计算机程序员,你可能未听说其名但如下软件你一定很熟悉:

  • FFmpeg、
  • QEMU
  • QuickJS

视频展示

示例 读取ds3231实时时钟,并使用LVGL 显示在屏幕上

js
import * as fs        from "fs"
import * as lvgl      from "lvgl"
import {GPIO,I2C,SPI} from "rp2040";


console.log("this is JS message\r\n",Object.keys(lvgl));
SetGpioCallBack(isr_callback);

var btnEventTable ={};
function reg_btn_callback(pin,func){
    let evList = btnEventTable[pin+''];
    if(evList){
        let exist = evList.find(it=>it == func);
        if(!exist) btnEventTable[pin+''].push(func);
    } 
    else btnEventTable[pin+''] =[func];
}

function isr_callback(pin,mask){
    if(btnEventTable[pin+'']){
        for(let f of btnEventTable[pin+'']){
            if(typeof(f) == 'function'){
                f(pin,mask);
            } 
        }
    }
    btnEventTable[pin+''] = [];
}

function tm_format (tm){
    function b2(v){if(v>=10)return v;return "0"+v;}
    let year     = tm.getFullYear();
    let month    = tm.getMonth()+1;
    let date     = tm.getDate();
    let hour     = tm.getHours();
    let minutes  = tm.getMinutes();
    let seconds  = tm.getSeconds();
    let mSec     = tm.getMilliseconds();
    // hour = (hour +8) %24
    let date_str = `${year}-${b2(month)}-${b2(date)} ${b2(hour)}:${b2(minutes)}:${b2(seconds)}`;
    return date_str;
}


var n_num = 0;
var pin_17 = new GPIO(17);

function wait_one_sec(sec = 1) {
    return new Promise((resolve, err) => {
        setTimeout(() => {
            resolve(sec);
        }, sec * 1000);
    })
}

function wait_btn_click(key) {
    return new Promise((resolve, err) => {
        function do_it(k,m){
            resolve({key:k,mask:m})
        }
        reg_btn_callback(key,do_it);
    })
}

function ds3231_rtc(i2c,addr){
    function bcd2dec(dec){
        return parseInt(dec.toString(16),10);
    }
    i2c.write(addr,[0]);
    let bytes            = new Uint8Array(i2c.read(addr,7));
    let [ss,mm,hh,d,m,y] = [0,1,2,4,5,6].map(i=>bcd2dec(bytes[i]));
    let datetime         = new Date(y+2000, m, d, hh, mm, ss);
    let tm_Str = tm_format(datetime);
    console.log(`Read:`,bytes ,"Datetime:",tm_Str);
    lvgl.text(tm_Str);
    return datetime;
}


async function test_promise() {
    wait_one_sec(5).then( async _ => {
        console.log("After 5 seconds");
        GPIO.Toggle(17);
        await wait_btn_click(21).then( obj =>{
            let {key,mask} = obj;
            console.log(`KEY DOWN: ${key} ${mask}`);
            GPIO.Toggle(17)
        })
    })
    try{
        let i2c_bus  = new I2C(5,4);//clk_pin,sda_pin,clock
        let devs = i2c_bus.scan();
        console.log(`SCAN devs count ${devs.length} => [${devs.map(d=>d.toString(16)).join(',')}]`)
        if(devs.length){
            setInterval(_=>{
                devs.map(addr=>{
                    if(addr ==0x68) ds3231_rtc(i2c_bus,addr);
                })
            },1000)
        }
    }catch(err){
        console.log("ERR",err);
    }
}

test_promise();
import * as fs        from "fs"
import * as lvgl      from "lvgl"
import {GPIO,I2C,SPI} from "rp2040";


console.log("this is JS message\r\n",Object.keys(lvgl));
SetGpioCallBack(isr_callback);

var btnEventTable ={};
function reg_btn_callback(pin,func){
    let evList = btnEventTable[pin+''];
    if(evList){
        let exist = evList.find(it=>it == func);
        if(!exist) btnEventTable[pin+''].push(func);
    } 
    else btnEventTable[pin+''] =[func];
}

function isr_callback(pin,mask){
    if(btnEventTable[pin+'']){
        for(let f of btnEventTable[pin+'']){
            if(typeof(f) == 'function'){
                f(pin,mask);
            } 
        }
    }
    btnEventTable[pin+''] = [];
}

function tm_format (tm){
    function b2(v){if(v>=10)return v;return "0"+v;}
    let year     = tm.getFullYear();
    let month    = tm.getMonth()+1;
    let date     = tm.getDate();
    let hour     = tm.getHours();
    let minutes  = tm.getMinutes();
    let seconds  = tm.getSeconds();
    let mSec     = tm.getMilliseconds();
    // hour = (hour +8) %24
    let date_str = `${year}-${b2(month)}-${b2(date)} ${b2(hour)}:${b2(minutes)}:${b2(seconds)}`;
    return date_str;
}


var n_num = 0;
var pin_17 = new GPIO(17);

function wait_one_sec(sec = 1) {
    return new Promise((resolve, err) => {
        setTimeout(() => {
            resolve(sec);
        }, sec * 1000);
    })
}

function wait_btn_click(key) {
    return new Promise((resolve, err) => {
        function do_it(k,m){
            resolve({key:k,mask:m})
        }
        reg_btn_callback(key,do_it);
    })
}

function ds3231_rtc(i2c,addr){
    function bcd2dec(dec){
        return parseInt(dec.toString(16),10);
    }
    i2c.write(addr,[0]);
    let bytes            = new Uint8Array(i2c.read(addr,7));
    let [ss,mm,hh,d,m,y] = [0,1,2,4,5,6].map(i=>bcd2dec(bytes[i]));
    let datetime         = new Date(y+2000, m, d, hh, mm, ss);
    let tm_Str = tm_format(datetime);
    console.log(`Read:`,bytes ,"Datetime:",tm_Str);
    lvgl.text(tm_Str);
    return datetime;
}


async function test_promise() {
    wait_one_sec(5).then( async _ => {
        console.log("After 5 seconds");
        GPIO.Toggle(17);
        await wait_btn_click(21).then( obj =>{
            let {key,mask} = obj;
            console.log(`KEY DOWN: ${key} ${mask}`);
            GPIO.Toggle(17)
        })
    })
    try{
        let i2c_bus  = new I2C(5,4);//clk_pin,sda_pin,clock
        let devs = i2c_bus.scan();
        console.log(`SCAN devs count ${devs.length} => [${devs.map(d=>d.toString(16)).join(',')}]`)
        if(devs.length){
            setInterval(_=>{
                devs.map(addr=>{
                    if(addr ==0x68) ds3231_rtc(i2c_bus,addr);
                })
            },1000)
        }
    }catch(err){
        console.log("ERR",err);
    }
}

test_promise();

API for JS

全局obj

  • console.log
  • sleep
  • active_port
  • flash_mcu
  • setTimeout
  • setInterval
  • clearTimeout
  • parseJSON
  • SetGpioCallBack
  • loadScript

fs

  • mount
  • mkfs
  • open
  • remove
  • rename
  • stat
  • readdir
  • rmdir
  • loadFile
  • loadScript

GPIO

  • GPIO.Dir
  • GPIO.Pull
  • GPIO.Init
  • GPIO.Toggle
  • GPIO.On
  • GPIO.Off
  • GPIO.Get
  • GPIO.Set

I2C

  • reset
  • scan
  • read
  • write

SPI

  • init
  • read
  • write
  • WR
  • port
  • cs
  • baudrate
  • mode

Released under the MIT License.