mirror of
https://github.com/ocogeclub/ocoge.git
synced 2024-11-25 00:49:48 +00:00
[update] micropythonモードを試験的に実装
This commit is contained in:
parent
41f1c30cde
commit
c151546f3e
@ -19,9 +19,9 @@
|
|||||||
<div id="dlgTitle">Source Code:</div>
|
<div id="dlgTitle">Source Code:</div>
|
||||||
<pre id="dlgContent" class="prettyprint lang-js linenums"></pre>
|
<pre id="dlgContent" class="prettyprint lang-js linenums"></pre>
|
||||||
<button id="dlgClose" title="このダイアログを閉じます。">閉じる</button>
|
<button id="dlgClose" title="このダイアログを閉じます。">閉じる</button>
|
||||||
<button id="dlgExport" title="ソースコードをファイルに保存します。">ファイルに保存</button>
|
<button id="dlgExport" title="ソースコードを保存します。">保存</button>
|
||||||
<span class="dlgCli" title="ソースコードの window.alert() を console.log() に置換します。コンソールで動作させるときにちょっと便利です。"><input
|
<!-- <span id="cli" class="dlgCli" title="ソースコードの window.alert() などを console.log() に置換します。コンソールで動作させるときにちょっと便利です。"><input
|
||||||
type="checkbox" id="dlgCli">CLI</span>
|
type="checkbox" id="dlgCli">CLI</span> -->
|
||||||
<div id="conmenu">
|
<div id="conmenu">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#" onclick="document.execCommand('copy');" class="conCopy">コピー</a></li>
|
<li><a href="#" onclick="document.execCommand('copy');" class="conCopy">コピー</a></li>
|
||||||
|
106
index.js
106
index.js
@ -323,7 +323,12 @@ const ugj_loadWorkspace = () => {
|
|||||||
const ugj_pyBeautify = (code) => {
|
const ugj_pyBeautify = (code) => {
|
||||||
let formatted = '';
|
let formatted = '';
|
||||||
// // formatted = window.ocogeapi.child_process.spawnSync('python3', ['-m', 'black', '-'], { input: code }).stdout.toString();
|
// // formatted = window.ocogeapi.child_process.spawnSync('python3', ['-m', 'black', '-'], { input: code }).stdout.toString();
|
||||||
// formatted = require('child_process').spawnSync('python3', ['-m', 'black', '-'], { input: code }).stdout.toString();
|
try {
|
||||||
|
formatted = require('child_process').spawnSync('python3', ['-m', 'black', '-'], { input: code }).stdout.toString();
|
||||||
|
} catch (e) {
|
||||||
|
formatted = code;
|
||||||
|
console.log('Python formatter "Black" is not found.');
|
||||||
|
}
|
||||||
return formatted;
|
return formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,8 +345,9 @@ const ugj_createCode = (args) => {
|
|||||||
code = Blockly.Python.workspaceToCode(workspace);
|
code = Blockly.Python.workspaceToCode(workspace);
|
||||||
} catch (e) { // Pythonコードを持たないブロックがある場合
|
} catch (e) { // Pythonコードを持たないブロックがある場合
|
||||||
window.alert('Python 非対応のブロックが使用されています。\n' + e.message);
|
window.alert('Python 非対応のブロックが使用されています。\n' + e.message);
|
||||||
|
code = '';
|
||||||
}
|
}
|
||||||
code = Blockly.Python.workspaceToCode(workspace);
|
// code = Blockly.Python.workspaceToCode(workspace);
|
||||||
}
|
}
|
||||||
else { // Javascript コード出力
|
else { // Javascript コード出力
|
||||||
code = Blockly.JavaScript.workspaceToCode(workspace);
|
code = Blockly.JavaScript.workspaceToCode(workspace);
|
||||||
@ -411,28 +417,48 @@ const ugj_createCode = (args) => {
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
const ugj_runCode = async () => {
|
const ugj_runCode = async () => {
|
||||||
document.activeElement.blur(); //実行ボタンからフォーカスを外す:エンターキー押下が悪さをするため
|
if (elutil.lang == 'js') {
|
||||||
let btnel = document.getElementById('runbtn');
|
document.activeElement.blur(); //実行ボタンからフォーカスを外す:エンターキー押下が悪さをするため
|
||||||
btnel.disabled = true;
|
let btnel = document.getElementById('runbtn');
|
||||||
// let code = ugj_createCode({ 'async': true });
|
btnel.disabled = true;
|
||||||
// await eval(code).catch(e => { alert(e); });
|
// let code = ugj_createCode({ 'async': true });
|
||||||
let AsyncFunction = Object.getPrototypeOf(async function () { }).constructor
|
// await eval(code).catch(e => { alert(e); });
|
||||||
let ocogeFunc = new AsyncFunction(ugj_createCode({}));
|
let AsyncFunction = Object.getPrototypeOf(async function () { }).constructor
|
||||||
await ocogeFunc().catch(e => { window.alert(e); });
|
let ocogeFunc = new AsyncFunction(ugj_createCode({}));
|
||||||
console.log('Code Execution done.');
|
await ocogeFunc().catch(e => { window.alert(e); });
|
||||||
btnel.disabled = false;
|
console.log('Code Execution done.');
|
||||||
|
btnel.disabled = false;
|
||||||
|
} else if (elutil.lang == 'py') {
|
||||||
|
let code = ugj_createCode({ 'ext': 'py' });
|
||||||
|
if (code) ugj_spawnPyboard(code, 'r');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pyboard ocoge
|
||||||
|
const ugj_spawnPyboard = (code, mode) => {
|
||||||
|
let script_path = elutil.path.join(elutil.library_path, 'pyboard_ocoge.py');
|
||||||
|
let p = require('child_process').spawn('python3', [script_path, mode]);
|
||||||
|
p.stdin.write(code);
|
||||||
|
p.stdin.end();
|
||||||
|
p.stderr.on('data', d => { console.error(d.toString()) });
|
||||||
|
p.stdout.on('data', d => { console.log(d.toString()) });
|
||||||
|
p.on('close', c => {
|
||||||
|
if (c == 0) console.log(`正常終了`);
|
||||||
|
else window.alert(`エラーが発生しました。詳しくはコンソールを参照してください。`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// コードをダイアログで表示・保存
|
// コードをダイアログで表示・保存
|
||||||
// エレメントのオブジェクトとかコールバックとか Python対応とか
|
// エレメントのオブジェクトとかコールバックとか Python対応とか
|
||||||
// 色々この中で完結させてみる
|
// 色々この中で完結させてみる
|
||||||
const ugj_showCode = () => {
|
const ugj_showCode = () => {
|
||||||
var ext = 'js';
|
// var ext = 'js';
|
||||||
|
var ext = elutil.lang;
|
||||||
const dialog = document.getElementById('codeDlg');
|
const dialog = document.getElementById('codeDlg');
|
||||||
const content = document.getElementById('dlgContent');
|
const content = document.getElementById('dlgContent');
|
||||||
const btn_close = document.getElementById('dlgClose');
|
const btn_close = document.getElementById('dlgClose');
|
||||||
const btn_export = document.getElementById('dlgExport');
|
const btn_export = document.getElementById('dlgExport');
|
||||||
const chkbox_cli = document.getElementById('dlgCli');
|
// const chkbox_cli = document.getElementById('dlgCli');
|
||||||
|
|
||||||
const dialog_title = document.getElementById('dlgTitle');
|
const dialog_title = document.getElementById('dlgTitle');
|
||||||
|
|
||||||
@ -443,37 +469,49 @@ const ugj_showCode = () => {
|
|||||||
|
|
||||||
dialog.showModal();
|
dialog.showModal();
|
||||||
|
|
||||||
|
const save_to_file = code => {
|
||||||
|
if (elutil.saveFile(code, ext) === false) window.alert('保存できませんでした。');
|
||||||
|
}
|
||||||
|
|
||||||
const close_cb = () => {
|
const close_cb = () => {
|
||||||
dialog.close();
|
dialog.close();
|
||||||
btn_close.removeEventListener('click', close_cb);
|
btn_close.removeEventListener('click', close_cb);
|
||||||
btn_export.removeEventListener('click', export_cb);
|
btn_export.removeEventListener('click', export_cb);
|
||||||
|
document.removeEventListener('keyup', keyev_cb);
|
||||||
}
|
}
|
||||||
const export_cb = () => {
|
const export_cb = () => {
|
||||||
let code = ugj_createCode({ 'ext': ext, 'async': true, 'beautify': true });
|
if (ext == 'js') {
|
||||||
// blackboardWrite()とwindow.alert()、fukidashi()をconsole.log()に書き換え、
|
let code = ugj_createCode({ 'ext': ext, 'async': true, 'beautify': true });
|
||||||
// document... と ugj_... と elutil... をコメントアウト(ブラウザ関連部分の追放という意味では不完全なので注意)
|
// if (elutil.saveFile(code, ext) === false) window.alert('保存できませんでした。');
|
||||||
// あと正規表現もいい加減
|
save_to_file(code);
|
||||||
if (chkbox_cli.checked && ext == 'js')
|
} else {
|
||||||
code = code.replace(/const appendDiv[^#]*\/\/#/gm, 'const blackboardWrite = text => console.log(text);').replace('window.alert', 'console.log').replace(/_fukidashi(.*), \d+(\);)/gm, 'console.log$1$2').replace(/(^(?=.*document.)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*ugj_)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*elutil.)[^;]*;)/gm, '/* $1 */');
|
let code = ugj_createCode({ 'ext': 'py', 'beautify': true });
|
||||||
if (elutil.saveFile(code, ext) === false) {
|
ugj_spawnPyboard(code, 'd');
|
||||||
window.alert('保存できませんでした。');
|
|
||||||
}
|
}
|
||||||
close_cb();
|
close_cb();
|
||||||
}
|
}
|
||||||
|
const keyev_cb = ev => {
|
||||||
|
if (ev.key == 'c' && ext == 'js') {
|
||||||
|
// CLI モード
|
||||||
|
// blackboardWrite()とwindow.alert()、fukidashi()をconsole.log()に書き換え、
|
||||||
|
// document... と ugj_... と elutil... をコメントアウト(ブラウザ関連部分の追放という意味では不完全なので注意)
|
||||||
|
// あと正規表現もいい加減
|
||||||
|
let code = ugj_createCode({ 'ext': ext, 'async': true, 'beautify': true });
|
||||||
|
code = code.replace(/const appendDiv[^#]*\/\/#/gm, 'const blackboardWrite = text => console.log(text);').replace('window.alert', 'console.log').replace(/_fukidashi(.*), \d+(\);)/gm, 'console.log$1$2').replace(/(^(?=.*document.)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*ugj_)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*elutil.)[^;]*;)/gm, '/* $1 */');
|
||||||
|
// if (elutil.saveFile(code, ext) === false) window.alert('保存できませんでした。');
|
||||||
|
save_to_file(code);
|
||||||
|
close_cb();
|
||||||
|
} else if (ev.key == 'f' && ext == 'py') {
|
||||||
|
let code = ugj_createCode({ 'ext': ext, 'beautify': true });
|
||||||
|
// if (elutil.saveFile(code, ext) === false) window.alert('保存できませんでした。');
|
||||||
|
save_to_file(code);
|
||||||
|
close_cb();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
btn_close.addEventListener('click', close_cb);
|
btn_close.addEventListener('click', close_cb);
|
||||||
btn_export.addEventListener('click', export_cb);
|
btn_export.addEventListener('click', export_cb);
|
||||||
// document.addEventListener('keypress', (ev) => {
|
document.addEventListener('keyup', keyev_cb);
|
||||||
// if (ev.key == 'p' && ext == 'js') {
|
|
||||||
// ext = 'py';
|
|
||||||
// showCode();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// document.addEventListener('keyup', (ev) => {
|
|
||||||
// if (ev.key == 'p') {
|
|
||||||
// ext = 'js';
|
|
||||||
// showCode();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ const ugj_const = {
|
|||||||
mascot_defname: 'tamachee.png',
|
mascot_defname: 'tamachee.png',
|
||||||
library_dirname: 'lib',
|
library_dirname: 'lib',
|
||||||
document_root: 'Documents',
|
document_root: 'Documents',
|
||||||
|
tmp_dir: '.ocogeclub/tmp',
|
||||||
executable_path: '.ocogeclub/apps/',
|
executable_path: '.ocogeclub/apps/',
|
||||||
blocks_sensors_dir: 'blocks/sensors/',
|
blocks_sensors_dir: 'blocks/sensors/',
|
||||||
localStorage_fname: 'ocoge.json',
|
localStorage_fname: 'ocoge.json',
|
||||||
@ -16,6 +17,7 @@ const ugj_const = {
|
|||||||
pig: 'pigpio',
|
pig: 'pigpio',
|
||||||
lg: 'lgpio', // 対応未定
|
lg: 'lgpio', // 対応未定
|
||||||
i2c_defbus: '1', // 文字列リテラルで指定
|
i2c_defbus: '1', // 文字列リテラルで指定
|
||||||
|
lang: 'js',
|
||||||
dev_hash: '4e9205f9b7e571bec1aa52ab7871f420684fcf96149672a4d550a95863d6b072'
|
dev_hash: '4e9205f9b7e571bec1aa52ab7871f420684fcf96149672a4d550a95863d6b072'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,10 +34,12 @@ class elUtil {
|
|||||||
this.children = [];
|
this.children = [];
|
||||||
this.gpio_backend = ugj_const.pig;
|
this.gpio_backend = ugj_const.pig;
|
||||||
this.i2c_bus = ugj_const.i2c_defbus;
|
this.i2c_bus = ugj_const.i2c_defbus;
|
||||||
|
this.lang = ugj_const.lang;
|
||||||
this.doc_root = this.path.join(process.env["HOME"], ugj_const.document_root);
|
this.doc_root = this.path.join(process.env["HOME"], ugj_const.document_root);
|
||||||
this.doc_current = this.path.join(process.env["HOME"], ugj_const.document_root);
|
this.doc_current = this.path.join(process.env["HOME"], ugj_const.document_root);
|
||||||
this.executable_path = this.path.join(process.env["HOME"], ugj_const.executable_path);
|
this.executable_path = this.path.join(process.env["HOME"], ugj_const.executable_path);
|
||||||
// this.blocks_sensors_dir = this.path.join(process.env["HOME"], ugj_const.blocks_sensors_dir);
|
// this.blocks_sensors_dir = this.path.join(process.env["HOME"], ugj_const.blocks_sensors_dir);
|
||||||
|
this.tmp_dir = this.path.join(process.env["HOME"], ugj_const.tmp_dir);
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
this.ugjEmitter = new EventEmitter();
|
this.ugjEmitter = new EventEmitter();
|
||||||
}
|
}
|
||||||
@ -249,12 +253,14 @@ class elUtil {
|
|||||||
savePrefsToLS() {
|
savePrefsToLS() {
|
||||||
let wc = '0';
|
let wc = '0';
|
||||||
if (this.wsChanged) wc = '1';
|
if (this.wsChanged) wc = '1';
|
||||||
|
// const ser_port = document.getElementById('dlgPort').value;
|
||||||
let o = {
|
let o = {
|
||||||
'saveFilepath': this.saveFilepath,
|
'saveFilepath': this.saveFilepath,
|
||||||
'wsChanged': wc,
|
'wsChanged': wc,
|
||||||
'mascotFilePath': this.mascotFilePath,
|
'mascotFilePath': this.mascotFilePath,
|
||||||
'doc_current': this.doc_current,
|
'doc_current': this.doc_current,
|
||||||
'i2c_bus': this.i2c_bus
|
'i2c_bus': this.i2c_bus,
|
||||||
|
'lang': this.lang
|
||||||
};
|
};
|
||||||
let s = JSON.stringify(o);
|
let s = JSON.stringify(o);
|
||||||
localStorage.setItem(ugj_const.localStorage_fname, s);
|
localStorage.setItem(ugj_const.localStorage_fname, s);
|
||||||
@ -270,7 +276,14 @@ class elUtil {
|
|||||||
else this.setWsChanged(true);
|
else this.setWsChanged(true);
|
||||||
if (o.mascotFilePath) this.setMascotFilePath(o.mascotFilePath);
|
if (o.mascotFilePath) this.setMascotFilePath(o.mascotFilePath);
|
||||||
if (o.doc_current) this.doc_current = o.doc_current;
|
if (o.doc_current) this.doc_current = o.doc_current;
|
||||||
if (o.i2c_bus) this.i2c_bus = o.i2c_bus;
|
if (o.i2c_bus) {
|
||||||
|
this.i2c_bus = o.i2c_bus;
|
||||||
|
this.ipcRenderer.send('i2c_check_menu', 'i2c-' + this.i2c_bus);
|
||||||
|
}
|
||||||
|
if (o.lang) {
|
||||||
|
this.setLang(o.lang);
|
||||||
|
this.ipcRenderer.send('lang_check_menu', this.lang);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +300,19 @@ class elUtil {
|
|||||||
this.i2c_bus = n;
|
this.i2c_bus = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 言語変更
|
||||||
|
setLang(l) {
|
||||||
|
this.lang = l;
|
||||||
|
const exp = document.getElementById('dlgExport');
|
||||||
|
if (l == 'js') {
|
||||||
|
exp.innerText = 'ファイルへ保存';
|
||||||
|
exp.title = 'ソースコードをファイルに保存します。';
|
||||||
|
} else {
|
||||||
|
exp.innerText = 'デプロイ';
|
||||||
|
exp.title = 'ソースコードをデバイスに転送します。';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// ファイル名にアプリケーションのドキュメントルートまでのパスをつけて返す
|
// ファイル名にアプリケーションのドキュメントルートまでのパスをつけて返す
|
||||||
getDocPath(filename) {
|
getDocPath(filename) {
|
||||||
@ -299,6 +325,7 @@ class brUtil {
|
|||||||
constructor() {
|
constructor() {
|
||||||
// GPIOブロックは使えません
|
// GPIOブロックは使えません
|
||||||
this.gpio_backend = ugj_const.pig;
|
this.gpio_backend = ugj_const.pig;
|
||||||
|
this.lang = 'js';
|
||||||
}
|
}
|
||||||
|
|
||||||
// マスコット
|
// マスコット
|
||||||
|
BIN
lib/__pycache__/pyboard.cpython-39.pyc
Normal file
BIN
lib/__pycache__/pyboard.cpython-39.pyc
Normal file
Binary file not shown.
2
lib/aaa.py
Normal file
2
lib/aaa.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# test
|
||||||
|
import test
|
16
lib/main.py
Normal file
16
lib/main.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from machine import Pin
|
||||||
|
from utime import sleep
|
||||||
|
|
||||||
|
pin = None
|
||||||
|
|
||||||
|
|
||||||
|
pin = 25
|
||||||
|
_pin = {}
|
||||||
|
_pin[pin] = Pin(pin, Pin.OUT)
|
||||||
|
for count2 in range(5):
|
||||||
|
for count in range(2):
|
||||||
|
_pin[pin].value(1)
|
||||||
|
sleep(0.1)
|
||||||
|
_pin[pin].value(0)
|
||||||
|
sleep(0.1)
|
||||||
|
sleep(0.6)
|
797
lib/pyboard.py
Normal file
797
lib/pyboard.py
Normal file
@ -0,0 +1,797 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
#
|
||||||
|
# The MIT License (MIT)
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014-2021 Damien P. George
|
||||||
|
# Copyright (c) 2017 Paul Sokolovsky
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyboard interface
|
||||||
|
|
||||||
|
This module provides the Pyboard class, used to communicate with and
|
||||||
|
control a MicroPython device over a communication channel. Both real
|
||||||
|
boards and emulated devices (e.g. running in QEMU) are supported.
|
||||||
|
Various communication channels are supported, including a serial
|
||||||
|
connection, telnet-style network connection, external process
|
||||||
|
connection.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
import pyboard
|
||||||
|
pyb = pyboard.Pyboard('/dev/ttyACM0')
|
||||||
|
|
||||||
|
Or:
|
||||||
|
|
||||||
|
pyb = pyboard.Pyboard('192.168.1.1')
|
||||||
|
|
||||||
|
Then:
|
||||||
|
|
||||||
|
pyb.enter_raw_repl()
|
||||||
|
pyb.exec('import pyb')
|
||||||
|
pyb.exec('pyb.LED(1).on()')
|
||||||
|
pyb.exit_raw_repl()
|
||||||
|
|
||||||
|
Note: if using Python2 then pyb.exec must be written as pyb.exec_.
|
||||||
|
To run a script from the local machine on the board and print out the results:
|
||||||
|
|
||||||
|
import pyboard
|
||||||
|
pyboard.execfile('test.py', device='/dev/ttyACM0')
|
||||||
|
|
||||||
|
This script can also be run directly. To execute a local script, use:
|
||||||
|
|
||||||
|
./pyboard.py test.py
|
||||||
|
|
||||||
|
Or:
|
||||||
|
|
||||||
|
python pyboard.py test.py
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import ast
|
||||||
|
|
||||||
|
try:
|
||||||
|
stdout = sys.stdout.buffer
|
||||||
|
except AttributeError:
|
||||||
|
# Python2 doesn't have buffer attr
|
||||||
|
stdout = sys.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def stdout_write_bytes(b):
|
||||||
|
b = b.replace(b"\x04", b"")
|
||||||
|
stdout.write(b)
|
||||||
|
stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
class PyboardError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TelnetToSerial:
|
||||||
|
def __init__(self, ip, user, password, read_timeout=None):
|
||||||
|
self.tn = None
|
||||||
|
import telnetlib
|
||||||
|
|
||||||
|
self.tn = telnetlib.Telnet(ip, timeout=15)
|
||||||
|
self.read_timeout = read_timeout
|
||||||
|
if b"Login as:" in self.tn.read_until(b"Login as:", timeout=read_timeout):
|
||||||
|
self.tn.write(bytes(user, "ascii") + b"\r\n")
|
||||||
|
|
||||||
|
if b"Password:" in self.tn.read_until(b"Password:", timeout=read_timeout):
|
||||||
|
# needed because of internal implementation details of the telnet server
|
||||||
|
time.sleep(0.2)
|
||||||
|
self.tn.write(bytes(password, "ascii") + b"\r\n")
|
||||||
|
|
||||||
|
if b"for more information." in self.tn.read_until(
|
||||||
|
b'Type "help()" for more information.', timeout=read_timeout
|
||||||
|
):
|
||||||
|
# login successful
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
self.fifo = deque()
|
||||||
|
return
|
||||||
|
|
||||||
|
raise PyboardError("Failed to establish a telnet connection with the board")
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.tn:
|
||||||
|
self.tn.close()
|
||||||
|
|
||||||
|
def read(self, size=1):
|
||||||
|
while len(self.fifo) < size:
|
||||||
|
timeout_count = 0
|
||||||
|
data = self.tn.read_eager()
|
||||||
|
if len(data):
|
||||||
|
self.fifo.extend(data)
|
||||||
|
timeout_count = 0
|
||||||
|
else:
|
||||||
|
time.sleep(0.25)
|
||||||
|
if self.read_timeout is not None and timeout_count > 4 * self.read_timeout:
|
||||||
|
break
|
||||||
|
timeout_count += 1
|
||||||
|
|
||||||
|
data = b""
|
||||||
|
while len(data) < size and len(self.fifo) > 0:
|
||||||
|
data += bytes([self.fifo.popleft()])
|
||||||
|
return data
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
self.tn.write(data)
|
||||||
|
return len(data)
|
||||||
|
|
||||||
|
def inWaiting(self):
|
||||||
|
n_waiting = len(self.fifo)
|
||||||
|
if not n_waiting:
|
||||||
|
data = self.tn.read_eager()
|
||||||
|
self.fifo.extend(data)
|
||||||
|
return len(data)
|
||||||
|
else:
|
||||||
|
return n_waiting
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessToSerial:
|
||||||
|
"Execute a process and emulate serial connection using its stdin/stdout."
|
||||||
|
|
||||||
|
def __init__(self, cmd):
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
self.subp = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
bufsize=0,
|
||||||
|
shell=True,
|
||||||
|
preexec_fn=os.setsid,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initially was implemented with selectors, but that adds Python3
|
||||||
|
# dependency. However, there can be race conditions communicating
|
||||||
|
# with a particular child process (like QEMU), and selectors may
|
||||||
|
# still work better in that case, so left inplace for now.
|
||||||
|
#
|
||||||
|
# import selectors
|
||||||
|
# self.sel = selectors.DefaultSelector()
|
||||||
|
# self.sel.register(self.subp.stdout, selectors.EVENT_READ)
|
||||||
|
|
||||||
|
import select
|
||||||
|
|
||||||
|
self.poll = select.poll()
|
||||||
|
self.poll.register(self.subp.stdout.fileno())
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
import signal
|
||||||
|
|
||||||
|
os.killpg(os.getpgid(self.subp.pid), signal.SIGTERM)
|
||||||
|
|
||||||
|
def read(self, size=1):
|
||||||
|
data = b""
|
||||||
|
while len(data) < size:
|
||||||
|
data += self.subp.stdout.read(size - len(data))
|
||||||
|
return data
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
self.subp.stdin.write(data)
|
||||||
|
return len(data)
|
||||||
|
|
||||||
|
def inWaiting(self):
|
||||||
|
# res = self.sel.select(0)
|
||||||
|
res = self.poll.poll(0)
|
||||||
|
if res:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessPtyToTerminal:
|
||||||
|
"""Execute a process which creates a PTY and prints slave PTY as
|
||||||
|
first line of its output, and emulate serial connection using
|
||||||
|
this PTY."""
|
||||||
|
|
||||||
|
def __init__(self, cmd):
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
import serial
|
||||||
|
|
||||||
|
self.subp = subprocess.Popen(
|
||||||
|
cmd.split(),
|
||||||
|
bufsize=0,
|
||||||
|
shell=False,
|
||||||
|
preexec_fn=os.setsid,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
pty_line = self.subp.stderr.readline().decode("utf-8")
|
||||||
|
m = re.search(r"/dev/pts/[0-9]+", pty_line)
|
||||||
|
if not m:
|
||||||
|
print("Error: unable to find PTY device in startup line:", pty_line)
|
||||||
|
self.close()
|
||||||
|
sys.exit(1)
|
||||||
|
pty = m.group()
|
||||||
|
# rtscts, dsrdtr params are to workaround pyserial bug:
|
||||||
|
# http://stackoverflow.com/questions/34831131/pyserial-does-not-play-well-with-virtual-port
|
||||||
|
self.ser = serial.Serial(pty, interCharTimeout=1, rtscts=True, dsrdtr=True)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
import signal
|
||||||
|
|
||||||
|
os.killpg(os.getpgid(self.subp.pid), signal.SIGTERM)
|
||||||
|
|
||||||
|
def read(self, size=1):
|
||||||
|
return self.ser.read(size)
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
return self.ser.write(data)
|
||||||
|
|
||||||
|
def inWaiting(self):
|
||||||
|
return self.ser.inWaiting()
|
||||||
|
|
||||||
|
|
||||||
|
class Pyboard:
|
||||||
|
def __init__(
|
||||||
|
self, device, baudrate=115200, user="micro", password="python", wait=0, exclusive=True
|
||||||
|
):
|
||||||
|
self.in_raw_repl = False
|
||||||
|
self.use_raw_paste = True
|
||||||
|
if device.startswith("exec:"):
|
||||||
|
self.serial = ProcessToSerial(device[len("exec:") :])
|
||||||
|
elif device.startswith("execpty:"):
|
||||||
|
self.serial = ProcessPtyToTerminal(device[len("qemupty:") :])
|
||||||
|
elif device and device[0].isdigit() and device[-1].isdigit() and device.count(".") == 3:
|
||||||
|
# device looks like an IP address
|
||||||
|
self.serial = TelnetToSerial(device, user, password, read_timeout=10)
|
||||||
|
else:
|
||||||
|
import serial
|
||||||
|
|
||||||
|
# Set options, and exclusive if pyserial supports it
|
||||||
|
serial_kwargs = {"baudrate": baudrate, "interCharTimeout": 1}
|
||||||
|
if serial.__version__ >= "3.3":
|
||||||
|
serial_kwargs["exclusive"] = exclusive
|
||||||
|
|
||||||
|
delayed = False
|
||||||
|
for attempt in range(wait + 1):
|
||||||
|
try:
|
||||||
|
self.serial = serial.Serial(device, **serial_kwargs)
|
||||||
|
break
|
||||||
|
except (OSError, IOError): # Py2 and Py3 have different errors
|
||||||
|
if wait == 0:
|
||||||
|
continue
|
||||||
|
if attempt == 0:
|
||||||
|
sys.stdout.write("Waiting {} seconds for pyboard ".format(wait))
|
||||||
|
delayed = True
|
||||||
|
time.sleep(1)
|
||||||
|
sys.stdout.write(".")
|
||||||
|
sys.stdout.flush()
|
||||||
|
else:
|
||||||
|
if delayed:
|
||||||
|
print("")
|
||||||
|
raise PyboardError("failed to access " + device)
|
||||||
|
if delayed:
|
||||||
|
print("")
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.serial.close()
|
||||||
|
|
||||||
|
def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None):
|
||||||
|
# if data_consumer is used then data is not accumulated and the ending must be 1 byte long
|
||||||
|
assert data_consumer is None or len(ending) == 1
|
||||||
|
|
||||||
|
data = self.serial.read(min_num_bytes)
|
||||||
|
if data_consumer:
|
||||||
|
data_consumer(data)
|
||||||
|
timeout_count = 0
|
||||||
|
while True:
|
||||||
|
if data.endswith(ending):
|
||||||
|
break
|
||||||
|
elif self.serial.inWaiting() > 0:
|
||||||
|
new_data = self.serial.read(1)
|
||||||
|
if data_consumer:
|
||||||
|
data_consumer(new_data)
|
||||||
|
data = new_data
|
||||||
|
else:
|
||||||
|
data = data + new_data
|
||||||
|
timeout_count = 0
|
||||||
|
else:
|
||||||
|
timeout_count += 1
|
||||||
|
if timeout is not None and timeout_count >= 100 * timeout:
|
||||||
|
break
|
||||||
|
time.sleep(0.01)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def enter_raw_repl(self, soft_reset=True):
|
||||||
|
self.serial.write(b"\r\x03\x03") # ctrl-C twice: interrupt any running program
|
||||||
|
|
||||||
|
# flush input (without relying on serial.flushInput())
|
||||||
|
n = self.serial.inWaiting()
|
||||||
|
while n > 0:
|
||||||
|
self.serial.read(n)
|
||||||
|
n = self.serial.inWaiting()
|
||||||
|
|
||||||
|
self.serial.write(b"\r\x01") # ctrl-A: enter raw REPL
|
||||||
|
|
||||||
|
if soft_reset:
|
||||||
|
data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n>")
|
||||||
|
if not data.endswith(b"raw REPL; CTRL-B to exit\r\n>"):
|
||||||
|
print(data)
|
||||||
|
raise PyboardError("could not enter raw repl")
|
||||||
|
|
||||||
|
self.serial.write(b"\x04") # ctrl-D: soft reset
|
||||||
|
|
||||||
|
# Waiting for "soft reboot" independently to "raw REPL" (done below)
|
||||||
|
# allows boot.py to print, which will show up after "soft reboot"
|
||||||
|
# and before "raw REPL".
|
||||||
|
data = self.read_until(1, b"soft reboot\r\n")
|
||||||
|
if not data.endswith(b"soft reboot\r\n"):
|
||||||
|
print(data)
|
||||||
|
raise PyboardError("could not enter raw repl")
|
||||||
|
|
||||||
|
data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n")
|
||||||
|
if not data.endswith(b"raw REPL; CTRL-B to exit\r\n"):
|
||||||
|
print(data)
|
||||||
|
raise PyboardError("could not enter raw repl")
|
||||||
|
|
||||||
|
self.in_raw_repl = True
|
||||||
|
|
||||||
|
def exit_raw_repl(self):
|
||||||
|
self.serial.write(b"\r\x02") # ctrl-B: enter friendly REPL
|
||||||
|
self.in_raw_repl = False
|
||||||
|
|
||||||
|
def follow(self, timeout, data_consumer=None):
|
||||||
|
# wait for normal output
|
||||||
|
data = self.read_until(1, b"\x04", timeout=timeout, data_consumer=data_consumer)
|
||||||
|
if not data.endswith(b"\x04"):
|
||||||
|
raise PyboardError("timeout waiting for first EOF reception")
|
||||||
|
data = data[:-1]
|
||||||
|
|
||||||
|
# wait for error output
|
||||||
|
data_err = self.read_until(1, b"\x04", timeout=timeout)
|
||||||
|
if not data_err.endswith(b"\x04"):
|
||||||
|
raise PyboardError("timeout waiting for second EOF reception")
|
||||||
|
data_err = data_err[:-1]
|
||||||
|
|
||||||
|
# return normal and error output
|
||||||
|
return data, data_err
|
||||||
|
|
||||||
|
def raw_paste_write(self, command_bytes):
|
||||||
|
# Read initial header, with window size.
|
||||||
|
data = self.serial.read(2)
|
||||||
|
window_size = data[0] | data[1] << 8
|
||||||
|
window_remain = window_size
|
||||||
|
|
||||||
|
# Write out the command_bytes data.
|
||||||
|
i = 0
|
||||||
|
while i < len(command_bytes):
|
||||||
|
while window_remain == 0 or self.serial.inWaiting():
|
||||||
|
data = self.serial.read(1)
|
||||||
|
if data == b"\x01":
|
||||||
|
# Device indicated that a new window of data can be sent.
|
||||||
|
window_remain += window_size
|
||||||
|
elif data == b"\x04":
|
||||||
|
# Device indicated abrupt end. Acknowledge it and finish.
|
||||||
|
self.serial.write(b"\x04")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# Unexpected data from device.
|
||||||
|
raise PyboardError("unexpected read during raw paste: {}".format(data))
|
||||||
|
# Send out as much data as possible that fits within the allowed window.
|
||||||
|
b = command_bytes[i : min(i + window_remain, len(command_bytes))]
|
||||||
|
self.serial.write(b)
|
||||||
|
window_remain -= len(b)
|
||||||
|
i += len(b)
|
||||||
|
|
||||||
|
# Indicate end of data.
|
||||||
|
self.serial.write(b"\x04")
|
||||||
|
|
||||||
|
# Wait for device to acknowledge end of data.
|
||||||
|
data = self.read_until(1, b"\x04")
|
||||||
|
if not data.endswith(b"\x04"):
|
||||||
|
raise PyboardError("could not complete raw paste: {}".format(data))
|
||||||
|
|
||||||
|
def exec_raw_no_follow(self, command):
|
||||||
|
if isinstance(command, bytes):
|
||||||
|
command_bytes = command
|
||||||
|
else:
|
||||||
|
command_bytes = bytes(command, encoding="utf8")
|
||||||
|
|
||||||
|
# check we have a prompt
|
||||||
|
data = self.read_until(1, b">")
|
||||||
|
if not data.endswith(b">"):
|
||||||
|
raise PyboardError("could not enter raw repl")
|
||||||
|
|
||||||
|
if self.use_raw_paste:
|
||||||
|
# Try to enter raw-paste mode.
|
||||||
|
self.serial.write(b"\x05A\x01")
|
||||||
|
data = self.serial.read(2)
|
||||||
|
if data == b"R\x00":
|
||||||
|
# Device understood raw-paste command but doesn't support it.
|
||||||
|
pass
|
||||||
|
elif data == b"R\x01":
|
||||||
|
# Device supports raw-paste mode, write out the command using this mode.
|
||||||
|
return self.raw_paste_write(command_bytes)
|
||||||
|
else:
|
||||||
|
# Device doesn't support raw-paste, fall back to normal raw REPL.
|
||||||
|
data = self.read_until(1, b"w REPL; CTRL-B to exit\r\n>")
|
||||||
|
if not data.endswith(b"w REPL; CTRL-B to exit\r\n>"):
|
||||||
|
print(data)
|
||||||
|
raise PyboardError("could not enter raw repl")
|
||||||
|
# Don't try to use raw-paste mode again for this connection.
|
||||||
|
self.use_raw_paste = False
|
||||||
|
|
||||||
|
# Write command using standard raw REPL, 256 bytes every 10ms.
|
||||||
|
for i in range(0, len(command_bytes), 256):
|
||||||
|
self.serial.write(command_bytes[i : min(i + 256, len(command_bytes))])
|
||||||
|
time.sleep(0.01)
|
||||||
|
self.serial.write(b"\x04")
|
||||||
|
|
||||||
|
# check if we could exec command
|
||||||
|
data = self.serial.read(2)
|
||||||
|
if data != b"OK":
|
||||||
|
raise PyboardError("could not exec command (response: %r)" % data)
|
||||||
|
|
||||||
|
def exec_raw(self, command, timeout=10, data_consumer=None):
|
||||||
|
self.exec_raw_no_follow(command)
|
||||||
|
return self.follow(timeout, data_consumer)
|
||||||
|
|
||||||
|
def eval(self, expression):
|
||||||
|
ret = self.exec_("print({})".format(expression))
|
||||||
|
ret = ret.strip()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def exec_(self, command, data_consumer=None):
|
||||||
|
ret, ret_err = self.exec_raw(command, data_consumer=data_consumer)
|
||||||
|
if ret_err:
|
||||||
|
raise PyboardError("exception", ret, ret_err)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def execfile(self, filename):
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
pyfile = f.read()
|
||||||
|
return self.exec_(pyfile)
|
||||||
|
|
||||||
|
def get_time(self):
|
||||||
|
t = str(self.eval("pyb.RTC().datetime()"), encoding="utf8")[1:-1].split(", ")
|
||||||
|
return int(t[4]) * 3600 + int(t[5]) * 60 + int(t[6])
|
||||||
|
|
||||||
|
def fs_ls(self, src):
|
||||||
|
cmd = (
|
||||||
|
"import uos\nfor f in uos.ilistdir(%s):\n"
|
||||||
|
" print('{:12} {}{}'.format(f[3]if len(f)>3 else 0,f[0],'/'if f[1]&0x4000 else ''))"
|
||||||
|
% (("'%s'" % src) if src else "")
|
||||||
|
)
|
||||||
|
self.exec_(cmd, data_consumer=stdout_write_bytes)
|
||||||
|
|
||||||
|
def fs_cat(self, src, chunk_size=256):
|
||||||
|
cmd = (
|
||||||
|
"with open('%s') as f:\n while 1:\n"
|
||||||
|
" b=f.read(%u)\n if not b:break\n print(b,end='')" % (src, chunk_size)
|
||||||
|
)
|
||||||
|
self.exec_(cmd, data_consumer=stdout_write_bytes)
|
||||||
|
|
||||||
|
def fs_get(self, src, dest, chunk_size=256, progress_callback=None):
|
||||||
|
if progress_callback:
|
||||||
|
src_size = int(self.exec_("import os\nprint(os.stat('%s')[6])" % src))
|
||||||
|
written = 0
|
||||||
|
self.exec_("f=open('%s','rb')\nr=f.read" % src)
|
||||||
|
with open(dest, "wb") as f:
|
||||||
|
while True:
|
||||||
|
data = bytearray()
|
||||||
|
self.exec_("print(r(%u))" % chunk_size, data_consumer=lambda d: data.extend(d))
|
||||||
|
assert data.endswith(b"\r\n\x04")
|
||||||
|
try:
|
||||||
|
data = ast.literal_eval(str(data[:-3], "ascii"))
|
||||||
|
if not isinstance(data, bytes):
|
||||||
|
raise ValueError("Not bytes")
|
||||||
|
except (UnicodeError, ValueError) as e:
|
||||||
|
raise PyboardError("fs_get: Could not interpret received data: %s" % str(e))
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
f.write(data)
|
||||||
|
if progress_callback:
|
||||||
|
written += len(data)
|
||||||
|
progress_callback(written, src_size)
|
||||||
|
self.exec_("f.close()")
|
||||||
|
|
||||||
|
def fs_put(self, src, dest, chunk_size=256, progress_callback=None):
|
||||||
|
if progress_callback:
|
||||||
|
src_size = os.path.getsize(src)
|
||||||
|
written = 0
|
||||||
|
self.exec_("f=open('%s','wb')\nw=f.write" % dest)
|
||||||
|
with open(src, "rb") as f:
|
||||||
|
while True:
|
||||||
|
data = f.read(chunk_size)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
if sys.version_info < (3,):
|
||||||
|
self.exec_("w(b" + repr(data) + ")")
|
||||||
|
else:
|
||||||
|
self.exec_("w(" + repr(data) + ")")
|
||||||
|
if progress_callback:
|
||||||
|
written += len(data)
|
||||||
|
progress_callback(written, src_size)
|
||||||
|
self.exec_("f.close()")
|
||||||
|
|
||||||
|
def fs_mkdir(self, dir):
|
||||||
|
self.exec_("import uos\nuos.mkdir('%s')" % dir)
|
||||||
|
|
||||||
|
def fs_rmdir(self, dir):
|
||||||
|
self.exec_("import uos\nuos.rmdir('%s')" % dir)
|
||||||
|
|
||||||
|
def fs_rm(self, src):
|
||||||
|
self.exec_("import uos\nuos.remove('%s')" % src)
|
||||||
|
|
||||||
|
|
||||||
|
# in Python2 exec is a keyword so one must use "exec_"
|
||||||
|
# but for Python3 we want to provide the nicer version "exec"
|
||||||
|
setattr(Pyboard, "exec", Pyboard.exec_)
|
||||||
|
|
||||||
|
|
||||||
|
def execfile(filename, device="/dev/ttyACM0", baudrate=115200, user="micro", password="python"):
|
||||||
|
pyb = Pyboard(device, baudrate, user, password)
|
||||||
|
pyb.enter_raw_repl()
|
||||||
|
output = pyb.execfile(filename)
|
||||||
|
stdout_write_bytes(output)
|
||||||
|
pyb.exit_raw_repl()
|
||||||
|
pyb.close()
|
||||||
|
|
||||||
|
|
||||||
|
def filesystem_command(pyb, args, progress_callback=None):
|
||||||
|
def fname_remote(src):
|
||||||
|
if src.startswith(":"):
|
||||||
|
src = src[1:]
|
||||||
|
return src
|
||||||
|
|
||||||
|
def fname_cp_dest(src, dest):
|
||||||
|
src = src.rsplit("/", 1)[-1]
|
||||||
|
if dest is None or dest == "":
|
||||||
|
dest = src
|
||||||
|
elif dest == ".":
|
||||||
|
dest = "./" + src
|
||||||
|
elif dest.endswith("/"):
|
||||||
|
dest += src
|
||||||
|
return dest
|
||||||
|
|
||||||
|
cmd = args[0]
|
||||||
|
args = args[1:]
|
||||||
|
try:
|
||||||
|
if cmd == "cp":
|
||||||
|
srcs = args[:-1]
|
||||||
|
dest = args[-1]
|
||||||
|
if srcs[0].startswith("./") or dest.startswith(":"):
|
||||||
|
op = pyb.fs_put
|
||||||
|
fmt = "cp %s :%s"
|
||||||
|
dest = fname_remote(dest)
|
||||||
|
else:
|
||||||
|
op = pyb.fs_get
|
||||||
|
fmt = "cp :%s %s"
|
||||||
|
for src in srcs:
|
||||||
|
src = fname_remote(src)
|
||||||
|
dest2 = fname_cp_dest(src, dest)
|
||||||
|
print(fmt % (src, dest2))
|
||||||
|
op(src, dest2, progress_callback=progress_callback)
|
||||||
|
else:
|
||||||
|
op = {
|
||||||
|
"ls": pyb.fs_ls,
|
||||||
|
"cat": pyb.fs_cat,
|
||||||
|
"mkdir": pyb.fs_mkdir,
|
||||||
|
"rmdir": pyb.fs_rmdir,
|
||||||
|
"rm": pyb.fs_rm,
|
||||||
|
}[cmd]
|
||||||
|
if cmd == "ls" and not args:
|
||||||
|
args = [""]
|
||||||
|
for src in args:
|
||||||
|
src = fname_remote(src)
|
||||||
|
print("%s :%s" % (cmd, src))
|
||||||
|
op(src)
|
||||||
|
except PyboardError as er:
|
||||||
|
print(str(er.args[2], "ascii"))
|
||||||
|
pyb.exit_raw_repl()
|
||||||
|
pyb.close()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
_injected_import_hook_code = """\
|
||||||
|
import uos, uio
|
||||||
|
class _FS:
|
||||||
|
class File(uio.IOBase):
|
||||||
|
def __init__(self):
|
||||||
|
self.off = 0
|
||||||
|
def ioctl(self, request, arg):
|
||||||
|
return 0
|
||||||
|
def readinto(self, buf):
|
||||||
|
buf[:] = memoryview(_injected_buf)[self.off:self.off + len(buf)]
|
||||||
|
self.off += len(buf)
|
||||||
|
return len(buf)
|
||||||
|
mount = umount = chdir = lambda *args: None
|
||||||
|
def stat(self, path):
|
||||||
|
if path == '_injected.mpy':
|
||||||
|
return tuple(0 for _ in range(10))
|
||||||
|
else:
|
||||||
|
raise OSError(-2) # ENOENT
|
||||||
|
def open(self, path, mode):
|
||||||
|
return self.File()
|
||||||
|
uos.mount(_FS(), '/_')
|
||||||
|
uos.chdir('/_')
|
||||||
|
from _injected import *
|
||||||
|
uos.umount('/_')
|
||||||
|
del _injected_buf, _FS
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
cmd_parser = argparse.ArgumentParser(description="Run scripts on the pyboard.")
|
||||||
|
cmd_parser.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--device",
|
||||||
|
default=os.environ.get("PYBOARD_DEVICE", "/dev/ttyACM0"),
|
||||||
|
help="the serial device or the IP address of the pyboard",
|
||||||
|
)
|
||||||
|
cmd_parser.add_argument(
|
||||||
|
"-b",
|
||||||
|
"--baudrate",
|
||||||
|
default=os.environ.get("PYBOARD_BAUDRATE", "115200"),
|
||||||
|
help="the baud rate of the serial device",
|
||||||
|
)
|
||||||
|
cmd_parser.add_argument("-u", "--user", default="micro", help="the telnet login username")
|
||||||
|
cmd_parser.add_argument("-p", "--password", default="python", help="the telnet login password")
|
||||||
|
cmd_parser.add_argument("-c", "--command", help="program passed in as string")
|
||||||
|
cmd_parser.add_argument(
|
||||||
|
"-w",
|
||||||
|
"--wait",
|
||||||
|
default=0,
|
||||||
|
type=int,
|
||||||
|
help="seconds to wait for USB connected board to become available",
|
||||||
|
)
|
||||||
|
group = cmd_parser.add_mutually_exclusive_group()
|
||||||
|
group.add_argument(
|
||||||
|
"--soft-reset",
|
||||||
|
default=True,
|
||||||
|
action="store_true",
|
||||||
|
help="Whether to perform a soft reset when connecting to the board [default]",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--no-soft-reset",
|
||||||
|
action="store_false",
|
||||||
|
dest="soft_reset",
|
||||||
|
)
|
||||||
|
group = cmd_parser.add_mutually_exclusive_group()
|
||||||
|
group.add_argument(
|
||||||
|
"--follow",
|
||||||
|
action="store_true",
|
||||||
|
default=None,
|
||||||
|
help="follow the output after running the scripts [default if no scripts given]",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--no-follow",
|
||||||
|
action="store_false",
|
||||||
|
dest="follow",
|
||||||
|
)
|
||||||
|
group = cmd_parser.add_mutually_exclusive_group()
|
||||||
|
group.add_argument(
|
||||||
|
"--exclusive",
|
||||||
|
action="store_true",
|
||||||
|
default=True,
|
||||||
|
help="Open the serial device for exclusive access [default]",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--no-exclusive",
|
||||||
|
action="store_false",
|
||||||
|
dest="exclusive",
|
||||||
|
)
|
||||||
|
cmd_parser.add_argument(
|
||||||
|
"-f",
|
||||||
|
"--filesystem",
|
||||||
|
action="store_true",
|
||||||
|
help="perform a filesystem action: "
|
||||||
|
"cp local :device | cp :device local | cat path | ls [path] | rm path | mkdir path | rmdir path",
|
||||||
|
)
|
||||||
|
cmd_parser.add_argument("files", nargs="*", help="input files")
|
||||||
|
args = cmd_parser.parse_args()
|
||||||
|
|
||||||
|
# open the connection to the pyboard
|
||||||
|
try:
|
||||||
|
pyb = Pyboard(
|
||||||
|
args.device, args.baudrate, args.user, args.password, args.wait, args.exclusive
|
||||||
|
)
|
||||||
|
except PyboardError as er:
|
||||||
|
print(er)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# run any command or file(s)
|
||||||
|
if args.command is not None or args.filesystem or len(args.files):
|
||||||
|
# we must enter raw-REPL mode to execute commands
|
||||||
|
# this will do a soft-reset of the board
|
||||||
|
try:
|
||||||
|
pyb.enter_raw_repl(args.soft_reset)
|
||||||
|
except PyboardError as er:
|
||||||
|
print(er)
|
||||||
|
pyb.close()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def execbuffer(buf):
|
||||||
|
try:
|
||||||
|
if args.follow is None or args.follow:
|
||||||
|
ret, ret_err = pyb.exec_raw(
|
||||||
|
buf, timeout=None, data_consumer=stdout_write_bytes
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
pyb.exec_raw_no_follow(buf)
|
||||||
|
ret_err = None
|
||||||
|
except PyboardError as er:
|
||||||
|
print(er)
|
||||||
|
pyb.close()
|
||||||
|
sys.exit(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(1)
|
||||||
|
if ret_err:
|
||||||
|
pyb.exit_raw_repl()
|
||||||
|
pyb.close()
|
||||||
|
stdout_write_bytes(ret_err)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# do filesystem commands, if given
|
||||||
|
if args.filesystem:
|
||||||
|
filesystem_command(pyb, args.files)
|
||||||
|
del args.files[:]
|
||||||
|
|
||||||
|
# run the command, if given
|
||||||
|
if args.command is not None:
|
||||||
|
execbuffer(args.command.encode("utf-8"))
|
||||||
|
|
||||||
|
# run any files
|
||||||
|
for filename in args.files:
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
pyfile = f.read()
|
||||||
|
if filename.endswith(".mpy") and pyfile[0] == ord("M"):
|
||||||
|
pyb.exec_("_injected_buf=" + repr(pyfile))
|
||||||
|
pyfile = _injected_import_hook_code
|
||||||
|
execbuffer(pyfile)
|
||||||
|
|
||||||
|
# exiting raw-REPL just drops to friendly-REPL mode
|
||||||
|
pyb.exit_raw_repl()
|
||||||
|
|
||||||
|
# if asked explicitly, or no files given, then follow the output
|
||||||
|
if args.follow or (args.command is None and not args.filesystem and len(args.files) == 0):
|
||||||
|
try:
|
||||||
|
ret, ret_err = pyb.follow(timeout=None, data_consumer=stdout_write_bytes)
|
||||||
|
except PyboardError as er:
|
||||||
|
print(er)
|
||||||
|
sys.exit(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(1)
|
||||||
|
if ret_err:
|
||||||
|
pyb.close()
|
||||||
|
stdout_write_bytes(ret_err)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# close the connection to the pyboard
|
||||||
|
pyb.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
45
lib/pyboard_ocoge.py
Normal file
45
lib/pyboard_ocoge.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import sys
|
||||||
|
import pyboard
|
||||||
|
import serial.tools.list_ports
|
||||||
|
|
||||||
|
args = sys.argv
|
||||||
|
|
||||||
|
# port = args[1]
|
||||||
|
mode = args[1]
|
||||||
|
src = sys.stdin.read()
|
||||||
|
|
||||||
|
dest = 'main.py'
|
||||||
|
chunk_size=256
|
||||||
|
|
||||||
|
# USBシリアルポート自動認識:アルファベット順で最初に見つけたポートを使用
|
||||||
|
for p in sorted(serial.tools.list_ports.comports()):
|
||||||
|
if p.hwid.startswith('USB'):
|
||||||
|
port = p.device
|
||||||
|
print ('Device found: ' + port)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print('No devices found.', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
pyb = pyboard.Pyboard(port)
|
||||||
|
pyb.enter_raw_repl()
|
||||||
|
|
||||||
|
if mode == 'r':
|
||||||
|
print('Run code', flush=True)
|
||||||
|
pyb.exec(src)
|
||||||
|
elif mode == 'd':
|
||||||
|
print('Deploy code', flush=True)
|
||||||
|
pyb.exec("f=open('%s','wb')\nw=f.write" % dest)
|
||||||
|
pos = 0
|
||||||
|
while True:
|
||||||
|
data = src[pos:pos+chunk_size]
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
if sys.version_info < (3,):
|
||||||
|
pyb.exec("w(b" + repr(data) + ")")
|
||||||
|
else:
|
||||||
|
pyb.exec("w(" + repr(data) + ")")
|
||||||
|
pos += chunk_size
|
||||||
|
pyb.exec("f.close()")
|
||||||
|
|
||||||
|
pyb.exit_raw_repl()
|
255
main.js
255
main.js
@ -25,7 +25,7 @@ function createWindow() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
/** Maximize Window at startup */
|
/** Maximize Window at startup */
|
||||||
win.maximize()
|
// win.maximize()
|
||||||
|
|
||||||
// and load the index.html of the app.
|
// and load the index.html of the app.
|
||||||
win.loadFile('index.html')
|
win.loadFile('index.html')
|
||||||
@ -51,6 +51,22 @@ function createWindow() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleCheck_i2c = checked_id => {
|
||||||
|
const menus = ['i2c-1', 'i2c-6'];
|
||||||
|
menus.forEach(id => {
|
||||||
|
menu.getMenuItemById(id).checked = (id == checked_id);
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
const toggleCheck_lang = checked_id => {
|
||||||
|
const menus = ['js', 'py'];
|
||||||
|
menus.forEach(id => {
|
||||||
|
menu.getMenuItemById(id).checked = (id == checked_id);
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// This method will be called when Electron has finished
|
// This method will be called when Electron has finished
|
||||||
// initialization and is ready to create browser windows.
|
// initialization and is ready to create browser windows.
|
||||||
// Some APIs can only be used after this event occurs.
|
// Some APIs can only be used after this event occurs.
|
||||||
@ -64,104 +80,147 @@ app.whenReady().then(() => {
|
|||||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||||
})
|
})
|
||||||
|
|
||||||
/** Custom Menu */
|
// Menu Unvisible
|
||||||
let template = [
|
|
||||||
{
|
|
||||||
label: 'Menu',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Toggle Menu Bar',
|
|
||||||
click: () => {
|
|
||||||
win.setMenuBarVisibility(!win.menuBarVisible)
|
|
||||||
},
|
|
||||||
accelerator: "CommandOrControl+Shift+M"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Reload',
|
|
||||||
click: () => {
|
|
||||||
win.reload()
|
|
||||||
},
|
|
||||||
accelerator: "F5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Mascot',
|
|
||||||
click: (item, focusedWindow) => {
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.webContents.executeJavaScript('ugj_selectMascot()')
|
|
||||||
},
|
|
||||||
accelerator: "CommandOrControl+M"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle Developer Tools',
|
|
||||||
click: () => {
|
|
||||||
win.webContents.toggleDevTools()
|
|
||||||
},
|
|
||||||
accelerator: "F12"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'About',
|
|
||||||
click: () => {
|
|
||||||
var os = require('os')
|
|
||||||
const { version } = require('./package.json')
|
|
||||||
// var detail = 'Version: ' + process.env.npm_package_version + '\n'
|
|
||||||
var detail = 'Version: ' + version + '\n'
|
|
||||||
+ 'Node.js: ' + process.versions.node + '\n'
|
|
||||||
+ 'Chrome: ' + process.versions.chrome + '\n'
|
|
||||||
+ 'Electron: ' + process.versions.electron + '\n'
|
|
||||||
+ 'V8: ' + process.versions.v8 + '\n'
|
|
||||||
+ 'OS: ' + os.type + ' ' + os.arch + ' ' + os.version + ' ' + os.release
|
|
||||||
var options = {
|
|
||||||
type: 'info',
|
|
||||||
buttons: ['OK'],
|
|
||||||
title: 'ocoge',
|
|
||||||
message: 'ocoge: code generator',
|
|
||||||
detail: detail
|
|
||||||
}
|
|
||||||
require('electron').dialog.showMessageBox(win, options)
|
|
||||||
},
|
|
||||||
accelerator: "CommandOrControl+I"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Quit',
|
|
||||||
click: () => {
|
|
||||||
app.quit()
|
|
||||||
},
|
|
||||||
accelerator: "CommandOrControl+Q"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Settings",
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: "i2c bus",
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: "1",
|
|
||||||
click: (item, focusedWindow) => {
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.webContents.executeJavaScript('elutil.setI2cbusNo("1")');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "6",
|
|
||||||
click: (item, focusedWindow) => {
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.webContents.executeJavaScript('elutil.setI2cbusNo("6")');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const menu = Menu.buildFromTemplate(template)
|
|
||||||
Menu.setApplicationMenu(menu)
|
|
||||||
win.setMenuBarVisibility(false)
|
win.setMenuBarVisibility(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/** Custom Menu */
|
||||||
|
let template = [
|
||||||
|
{
|
||||||
|
label: 'Menu',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Toggle Menu Bar',
|
||||||
|
click: () => {
|
||||||
|
win.setMenuBarVisibility(!win.menuBarVisible)
|
||||||
|
},
|
||||||
|
accelerator: "CommandOrControl+Shift+M"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Reload',
|
||||||
|
click: () => {
|
||||||
|
win.reload()
|
||||||
|
},
|
||||||
|
accelerator: "F5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Mascot',
|
||||||
|
click: (item, focusedWindow) => {
|
||||||
|
if (focusedWindow)
|
||||||
|
focusedWindow.webContents.executeJavaScript('ugj_selectMascot()')
|
||||||
|
},
|
||||||
|
accelerator: "CommandOrControl+M"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Developer Tools',
|
||||||
|
click: () => {
|
||||||
|
win.webContents.toggleDevTools()
|
||||||
|
},
|
||||||
|
accelerator: "F12"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'About',
|
||||||
|
click: () => {
|
||||||
|
var os = require('os')
|
||||||
|
const { version } = require('./package.json')
|
||||||
|
// var detail = 'Version: ' + process.env.npm_package_version + '\n'
|
||||||
|
var detail = 'Version: ' + version + '\n'
|
||||||
|
+ 'Node.js: ' + process.versions.node + '\n'
|
||||||
|
+ 'Chrome: ' + process.versions.chrome + '\n'
|
||||||
|
+ 'Electron: ' + process.versions.electron + '\n'
|
||||||
|
+ 'V8: ' + process.versions.v8 + '\n'
|
||||||
|
+ 'OS: ' + os.type + ' ' + os.arch + ' ' + os.version + ' ' + os.release
|
||||||
|
var options = {
|
||||||
|
type: 'info',
|
||||||
|
buttons: ['OK'],
|
||||||
|
title: 'ocoge',
|
||||||
|
message: 'ocoge: code generator',
|
||||||
|
detail: detail
|
||||||
|
}
|
||||||
|
require('electron').dialog.showMessageBox(win, options)
|
||||||
|
},
|
||||||
|
accelerator: "CommandOrControl+I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
click: () => {
|
||||||
|
app.quit()
|
||||||
|
},
|
||||||
|
accelerator: "CommandOrControl+Q"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Settings",
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: "i2c bus",
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: "1",
|
||||||
|
id: "i2c-1",
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: true,
|
||||||
|
click: (item, focusedWindow) => {
|
||||||
|
if (focusedWindow) {
|
||||||
|
toggleCheck_i2c("i2c-1");
|
||||||
|
focusedWindow.webContents.executeJavaScript('elutil.setI2cbusNo("1")');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "6",
|
||||||
|
id: "i2c-6",
|
||||||
|
type: 'checkbox',
|
||||||
|
click: (item, focusedWindow) => {
|
||||||
|
if (focusedWindow) {
|
||||||
|
toggleCheck_i2c("i2c-6");
|
||||||
|
focusedWindow.webContents.executeJavaScript('elutil.setI2cbusNo("6")');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Language",
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: "JavaScript",
|
||||||
|
id: "js",
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: true,
|
||||||
|
click: (item, focusedWindow) => {
|
||||||
|
if (focusedWindow) {
|
||||||
|
// menu.getMenuItemById('py').checked = false;
|
||||||
|
toggleCheck_lang("js");
|
||||||
|
focusedWindow.webContents.executeJavaScript('elutil.setLang("js")');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "MicroPython (Test phase)",
|
||||||
|
id: "py",
|
||||||
|
type: 'checkbox',
|
||||||
|
click: (item, focusedWindow) => {
|
||||||
|
if (focusedWindow) {
|
||||||
|
// menu.getMenuItemById('js').checked = false;
|
||||||
|
toggleCheck_lang("py");
|
||||||
|
focusedWindow.webContents.executeJavaScript('elutil.setLang("py")');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const menu = Menu.buildFromTemplate(template)
|
||||||
|
Menu.setApplicationMenu(menu)
|
||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
// On macOS it is common for applications and their menu bar
|
// On macOS it is common for applications and their menu bar
|
||||||
@ -186,6 +245,12 @@ app.on('window-all-closed', () => {
|
|||||||
ipcMain.on('set_title', (ev, title) => {
|
ipcMain.on('set_title', (ev, title) => {
|
||||||
win.setTitle(title)
|
win.setTitle(title)
|
||||||
})
|
})
|
||||||
|
ipcMain.on('i2c_check_menu', (ev, menuid) => {
|
||||||
|
toggleCheck_i2c(menuid);
|
||||||
|
})
|
||||||
|
ipcMain.on('lang_check_menu', (ev, menuid) => {
|
||||||
|
toggleCheck_lang(menuid);
|
||||||
|
})
|
||||||
ipcMain.handle('open_dialog', (ev, title, dpath, filter) => {
|
ipcMain.handle('open_dialog', (ev, title, dpath, filter) => {
|
||||||
let filepaths = dialog.showOpenDialogSync(win, {
|
let filepaths = dialog.showOpenDialogSync(win, {
|
||||||
properties: ['openFile'],
|
properties: ['openFile'],
|
||||||
|
4786
package-lock.json
generated
4786
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
32
package.json
32
package.json
@ -12,23 +12,20 @@
|
|||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/ocogeclub/ocoge.git"
|
"url": "git+https://git.ocoge.club/ocoge.club/ocoge.git"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/ocogeclub/ocoge/issues"
|
"url": "https://git.ocoge.club/ocoge.club/ocoge/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/ocogeclub/ocoge#readme",
|
"homepage": "https://git.ocoge.club/ocoge.club/ocoge#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron-forge/cli": "^6.0.0-beta.63",
|
"@electron-forge/cli": "^6.0.0-beta.64",
|
||||||
"@electron-forge/maker-deb": "^6.0.0-beta.63",
|
"@electron-forge/maker-deb": "^6.0.0-beta.64",
|
||||||
"@electron-forge/maker-rpm": "^6.0.0-beta.63",
|
"electron": "^19.0.8",
|
||||||
"@electron-forge/maker-squirrel": "6.0.0-beta.33",
|
"electron-rebuild": "^3.2.8"
|
||||||
"@electron-forge/maker-zip": "^6.0.0-beta.63",
|
|
||||||
"electron": "^19.0.3",
|
|
||||||
"electron-rebuild": "^3.2.7"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ocoge.club/pigpio": "file:local_modules/@ocoge.club/pigpio",
|
"@ocoge.club/pigpio": "file:local_modules/@ocoge.club/pigpio",
|
||||||
@ -38,27 +35,14 @@
|
|||||||
"@tensorflow/tfjs": "^3.18.0",
|
"@tensorflow/tfjs": "^3.18.0",
|
||||||
"@tensorflow/tfjs-backend-wasm": "^3.18.0",
|
"@tensorflow/tfjs-backend-wasm": "^3.18.0",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"electron-squirrel-startup": "^1.0.0",
|
|
||||||
"node-abi": "^3.22.0",
|
"node-abi": "^3.22.0",
|
||||||
"nodemailer": "^6.7.5",
|
"nodemailer": "^6.7.7",
|
||||||
"tensorset": "^1.2.9"
|
"tensorset": "^1.2.9"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"forge": {
|
"forge": {
|
||||||
"packagerConfig": {},
|
"packagerConfig": {},
|
||||||
"makers": [
|
"makers": [
|
||||||
{
|
|
||||||
"name": "@electron-forge/maker-squirrel",
|
|
||||||
"config": {
|
|
||||||
"name": "ocoge"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "@electron-forge/maker-zip",
|
|
||||||
"platforms": [
|
|
||||||
"darwin"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "@electron-forge/maker-deb",
|
"name": "@electron-forge/maker-deb",
|
||||||
"config": {
|
"config": {
|
||||||
|
189
ugj_blocks.js
189
ugj_blocks.js
@ -285,9 +285,9 @@ Blockly.JavaScript['ugj_gpio_open'] = function (block) {
|
|||||||
};
|
};
|
||||||
Blockly.Python['ugj_gpio_open'] = function (block) {
|
Blockly.Python['ugj_gpio_open'] = function (block) {
|
||||||
Blockly.Python.provideFunction_(
|
Blockly.Python.provideFunction_(
|
||||||
'import_lgpio', ['import lgpio as pi']
|
'import_pin', ['from machine import Pin']
|
||||||
);
|
);
|
||||||
var code = `gpioHand = pi.gpiochip_open(0)\n`; //
|
var code = `_pin = {}\n`; //
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ Blockly.JavaScript['ugj_gpio_close'] = function (block) {
|
|||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_gpio_close'] = function (block) {
|
Blockly.Python['ugj_gpio_close'] = function (block) {
|
||||||
var code = 'pi.gpiochip_close(gpioHand)\n';
|
var code = '';
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -349,7 +349,7 @@ Blockly.JavaScript['ugj_gpio_set_output'] = function (block) {
|
|||||||
};
|
};
|
||||||
Blockly.Python['ugj_gpio_set_output'] = function (block) {
|
Blockly.Python['ugj_gpio_set_output'] = function (block) {
|
||||||
var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.gpio_set_output(${value_gpio})\n`;
|
var code = `_pin[${value_gpio}] = Pin(${value_gpio}, Pin.OUT)\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -402,12 +402,12 @@ Blockly.JavaScript['ugj_gpio_set_input'] = function (block) {
|
|||||||
var code = `await _pi.gpio_set_input(${value_gpio}, ${dropdown_lflag});\n`;
|
var code = `await _pi.gpio_set_input(${value_gpio}, ${dropdown_lflag});\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_gpio_set_input'] = function (block) {
|
// Blockly.Python['ugj_gpio_set_input'] = function (block) {
|
||||||
var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
// var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
||||||
var dropdown_lflag = block.getFieldValue('lflag');
|
// var dropdown_lflag = block.getFieldValue('lflag');
|
||||||
var code = `await pi.gpio_set_input(gpioHand, ${value_gpio}, ${dropdown_lflag})\n`;
|
// var code = `\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
|
|
||||||
/********************* */
|
/********************* */
|
||||||
/** Read GPIO Value ** */
|
/** Read GPIO Value ** */
|
||||||
@ -438,11 +438,11 @@ Blockly.JavaScript['ugj_gpio_read'] = function (block) {
|
|||||||
var code = `await _pi.gpio_read(${value_gpio})`;
|
var code = `await _pi.gpio_read(${value_gpio})`;
|
||||||
return [code, Blockly.JavaScript.ORDER_NONE];
|
return [code, Blockly.JavaScript.ORDER_NONE];
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_gpio_read'] = function (block) {
|
// Blockly.Python['ugj_gpio_read'] = function (block) {
|
||||||
var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
// var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.gpio_read(gpioHand, ${value_gpio})`;
|
// var code = ``;
|
||||||
return [code, Blockly.Python.ORDER_NONE];
|
// return [code, Blockly.Python.ORDER_NONE];
|
||||||
};
|
// };
|
||||||
|
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
/** GPIO Write Value - Common GPIO on/off **/
|
/** GPIO Write Value - Common GPIO on/off **/
|
||||||
@ -492,7 +492,7 @@ Blockly.JavaScript['ugj_gpio_write'] = function (block) {
|
|||||||
Blockly.Python['ugj_gpio_write'] = function (block) {
|
Blockly.Python['ugj_gpio_write'] = function (block) {
|
||||||
var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
||||||
var dropdown_level = block.getFieldValue('level');
|
var dropdown_level = block.getFieldValue('level');
|
||||||
var code = `await pi.gpio_write(gpioHand, ${value_gpio}, ${dropdown_level})\n`;
|
var code = `_pin[${value_gpio}].value(${dropdown_level})\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -532,12 +532,12 @@ Blockly.JavaScript['ugj_servo'] = function (block) {
|
|||||||
var code = `await _pi.servo(${value_gpio}, ${value_pulsewidth});\n`;
|
var code = `await _pi.servo(${value_gpio}, ${value_pulsewidth});\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_servo'] = function (block) {
|
// Blockly.Python['ugj_servo'] = function (block) {
|
||||||
var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
// var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
||||||
var value_pulsewidth = Blockly.Python.valueToCode(block, 'pulsewidth', Blockly.Python.ORDER_ATOMIC);
|
// var value_pulsewidth = Blockly.Python.valueToCode(block, 'pulsewidth', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.servo(gpioHand, ${value_gpio}, ${value_pulsewidth})\n`;
|
// var code = `await pi.servo(gpioHand, ${value_gpio}, ${value_pulsewidth})\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
|
|
||||||
/************************************************* */
|
/************************************************* */
|
||||||
/** starts software timed PWM on an output GPIO ** */
|
/** starts software timed PWM on an output GPIO ** */
|
||||||
@ -581,13 +581,13 @@ Blockly.JavaScript['ugj_pwm'] = function (block) {
|
|||||||
var code = `await _pi.pwm(${value_gpio}, ${value_pwm_frequency}, ${value_pwm_duty_cycle});\n`;
|
var code = `await _pi.pwm(${value_gpio}, ${value_pwm_frequency}, ${value_pwm_duty_cycle});\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_pwm'] = function (block) {
|
// Blockly.Python['ugj_pwm'] = function (block) {
|
||||||
var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
// var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC);
|
||||||
var value_pwm_frequency = Blockly.Python.valueToCode(block, 'pwm_frequency', Blockly.Python.ORDER_ATOMIC);
|
// var value_pwm_frequency = Blockly.Python.valueToCode(block, 'pwm_frequency', Blockly.Python.ORDER_ATOMIC);
|
||||||
var value_pwm_duty_cycle = Blockly.Python.valueToCode(block, 'pwm_duty_cycle', Blockly.Python.ORDER_ATOMIC);
|
// var value_pwm_duty_cycle = Blockly.Python.valueToCode(block, 'pwm_duty_cycle', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.pwm(gpioHand, ${value_gpio}, ${value_pwm_frequency}, ${value_pwm_duty_cycle})\n`;
|
// var code = `await pi.pwm(gpioHand, ${value_gpio}, ${value_pwm_frequency}, ${value_pwm_duty_cycle})\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
/********************** */
|
/********************** */
|
||||||
/** Open Serial Port ** */
|
/** Open Serial Port ** */
|
||||||
/********************** */
|
/********************** */
|
||||||
@ -635,15 +635,15 @@ Blockly.JavaScript['ugj_serial_open'] = function (block) {
|
|||||||
var code = `await _pi.serial_open('/dev/serial0', ${dropdown_baud});\n`;
|
var code = `await _pi.serial_open('/dev/serial0', ${dropdown_baud});\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_serial_open'] = function (block) {
|
// Blockly.Python['ugj_serial_open'] = function (block) {
|
||||||
var value_tty = Blockly.Python.valueToCode(block, 'tty', Blockly.Python.ORDER_ATOMIC);
|
// var value_tty = Blockly.Python.valueToCode(block, 'tty', Blockly.Python.ORDER_ATOMIC);
|
||||||
var dropdown_baud = block.getFieldValue('baud');
|
// var dropdown_baud = block.getFieldValue('baud');
|
||||||
Blockly.Python.provideFunction_(
|
// Blockly.Python.provideFunction_(
|
||||||
'import_lgpio', ['import lgpio as pi']
|
// 'import_lgpio', ['import lgpio as pi']
|
||||||
);
|
// );
|
||||||
var code = `ser_hand = pi.serial_open(${value_tty}, ${dropdown_baud}, 0)\n`;
|
// var code = `ser_hand = pi.serial_open(${value_tty}, ${dropdown_baud}, 0)\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
/*********************** */
|
/*********************** */
|
||||||
/** Close Serial Port ** */
|
/** Close Serial Port ** */
|
||||||
/*********************** */
|
/*********************** */
|
||||||
@ -666,10 +666,10 @@ Blockly.JavaScript['ugj_serial_close'] = function (block) {
|
|||||||
var code = 'await _pi.serial_close();\n';
|
var code = 'await _pi.serial_close();\n';
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_serial_close'] = function (block) {
|
// Blockly.Python['ugj_serial_close'] = function (block) {
|
||||||
var code = 'pi.serial_close(ser_hand)\n';
|
// var code = 'pi.serial_close(ser_hand)\n';
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
|
|
||||||
/************************** */
|
/************************** */
|
||||||
/** Write Data to Serial ** */
|
/** Write Data to Serial ** */
|
||||||
@ -701,11 +701,11 @@ Blockly.JavaScript['ugj_serial_write'] = function (block) {
|
|||||||
var code = `await _pi.serial_write(${value_data});\n`;
|
var code = `await _pi.serial_write(${value_data});\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_serial_write'] = function (block) {
|
// Blockly.Python['ugj_serial_write'] = function (block) {
|
||||||
var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
|
// var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.serial_write(ser_hand, ${value_data}.encode())\n`;
|
// var code = `await pi.serial_write(ser_hand, ${value_data}.encode())\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
|
|
||||||
/************************ */
|
/************************ */
|
||||||
/** Read Data from Serial */
|
/** Read Data from Serial */
|
||||||
@ -736,11 +736,11 @@ Blockly.JavaScript['ugj_serial_read'] = function (block) {
|
|||||||
var code = `await _pi.serial_read(${value_count})`;
|
var code = `await _pi.serial_read(${value_count})`;
|
||||||
return [code, Blockly.JavaScript.ORDER_ATOMIC];
|
return [code, Blockly.JavaScript.ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_serial_read'] = function (block) {
|
// Blockly.Python['ugj_serial_read'] = function (block) {
|
||||||
var value_count = Blockly.Python.valueToCode(block, 'count', Blockly.Python.ORDER_ATOMIC);
|
// var value_count = Blockly.Python.valueToCode(block, 'count', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.serial_read(ser_hand, ${value_count}).decode()`;
|
// var code = `await pi.serial_read(ser_hand, ${value_count}).decode()`;
|
||||||
return [code, Blockly.Python.ORDER_ATOMIC];
|
// return [code, Blockly.Python.ORDER_ATOMIC];
|
||||||
};
|
// };
|
||||||
|
|
||||||
/********************* */
|
/********************* */
|
||||||
/** Open I2C Device ** */
|
/** Open I2C Device ** */
|
||||||
@ -775,14 +775,14 @@ Blockly.JavaScript['ugj_i2c_open'] = function (block) {
|
|||||||
var code = `await _pi.i2c_open(${elutil.i2c_bus}, ${value_i2c_address});\n`;
|
var code = `await _pi.i2c_open(${elutil.i2c_bus}, ${value_i2c_address});\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_i2c_open'] = function (block) {
|
// Blockly.Python['ugj_i2c_open'] = function (block) {
|
||||||
var value_i2c_address = Blockly.Python.valueToCode(block, 'i2c_address', Blockly.Python.ORDER_ATOMIC);
|
// var value_i2c_address = Blockly.Python.valueToCode(block, 'i2c_address', Blockly.Python.ORDER_ATOMIC);
|
||||||
Blockly.Python.provideFunction_(
|
// Blockly.Python.provideFunction_(
|
||||||
'import_lgpio', ['import lgpio as pi']
|
// 'import_lgpio', ['import lgpio as pi']
|
||||||
);
|
// );
|
||||||
var code = `i2c_hand = pi.i2c_open(1, ${value_i2c_address})\n`;
|
// var code = `i2c_hand = pi.i2c_open(1, ${value_i2c_address})\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
/********************** */
|
/********************** */
|
||||||
/** Close I2C Device ** */
|
/** Close I2C Device ** */
|
||||||
/********************** */
|
/********************** */
|
||||||
@ -805,10 +805,10 @@ Blockly.JavaScript['ugj_i2c_close'] = function (block) {
|
|||||||
var code = `await _pi.i2c_close();\n`;
|
var code = `await _pi.i2c_close();\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_i2c_close'] = function (block) {
|
// Blockly.Python['ugj_i2c_close'] = function (block) {
|
||||||
var code = `await pi.i2c_close(i2c_hand)\n`;
|
// var code = `await pi.i2c_close(i2c_hand)\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
|
|
||||||
/****************************************************************** */
|
/****************************************************************** */
|
||||||
/** Writes a single byte to the specified register of the device ** */
|
/** Writes a single byte to the specified register of the device ** */
|
||||||
@ -846,12 +846,12 @@ Blockly.JavaScript['ugj_i2c_write_byte_data'] = function (block) {
|
|||||||
var code = `await _pi.i2c_write_byte_data(${value_reg}, ${value_byte_val});\n`;
|
var code = `await _pi.i2c_write_byte_data(${value_reg}, ${value_byte_val});\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_i2c_write_byte_data'] = function (block) {
|
// Blockly.Python['ugj_i2c_write_byte_data'] = function (block) {
|
||||||
var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC);
|
// var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC);
|
||||||
var value_byte_val = Blockly.Python.valueToCode(block, 'byte_val', Blockly.Python.ORDER_ATOMIC);
|
// var value_byte_val = Blockly.Python.valueToCode(block, 'byte_val', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.i2c_write_byte_data(i2c_hand, ${value_reg}, ${value_byte_val})\n`;
|
// var code = `await pi.i2c_write_byte_data(i2c_hand, ${value_reg}, ${value_byte_val})\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
|
|
||||||
/****************************************************************** */
|
/****************************************************************** */
|
||||||
/** Read a single byte from the specified resister of the device ** */
|
/** Read a single byte from the specified resister of the device ** */
|
||||||
@ -882,11 +882,11 @@ Blockly.JavaScript['ugj_i2c_read_byte_data'] = function (block) {
|
|||||||
var code = `await _pi.i2c_read_byte_data(${value_reg})`;
|
var code = `await _pi.i2c_read_byte_data(${value_reg})`;
|
||||||
return [code, Blockly.JavaScript.ORDER_ATOMIC];
|
return [code, Blockly.JavaScript.ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_i2c_read_byte_data'] = function (block) {
|
// Blockly.Python['ugj_i2c_read_byte_data'] = function (block) {
|
||||||
var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC);
|
// var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.i2c_read_byte_data(i2c_hand, ${value_reg})\n`;
|
// var code = `await pi.i2c_read_byte_data(i2c_hand, ${value_reg})\n`;
|
||||||
return [code, Blockly.Python.ORDER_ATOMIC];
|
// return [code, Blockly.Python.ORDER_ATOMIC];
|
||||||
};
|
// };
|
||||||
|
|
||||||
Blockly.Blocks['ugj_i2c_read_word_data'] = {
|
Blockly.Blocks['ugj_i2c_read_word_data'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
@ -941,13 +941,13 @@ Blockly.JavaScript['ugj_i2c_write_i2c_block_data'] = function (block) {
|
|||||||
var code = `await _pi.i2c_write_i2c_block_data (${value_reg}, ${value_data});`;
|
var code = `await _pi.i2c_write_i2c_block_data (${value_reg}, ${value_data});`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_i2c_write_i2c_block_data'] = function (block) {
|
// Blockly.Python['ugj_i2c_write_i2c_block_data'] = function (block) {
|
||||||
var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC);
|
// var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC);
|
||||||
var value_name = Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_ATOMIC);
|
// var value_name = Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_ATOMIC);
|
||||||
// TODO: Assemble Python into code variable.
|
// // TODO: Assemble Python into code variable.
|
||||||
var code = '...\n';
|
// var code = '...\n';
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
|
|
||||||
/************************************************************************** */
|
/************************************************************************** */
|
||||||
/** Returns count bytes read from the raw device associated with handle. ** */
|
/** Returns count bytes read from the raw device associated with handle. ** */
|
||||||
@ -978,11 +978,11 @@ Blockly.JavaScript['ugj_i2c_read_device'] = function (block) {
|
|||||||
var code = `await _pi.i2c_read_device(${value_count})`;
|
var code = `await _pi.i2c_read_device(${value_count})`;
|
||||||
return [code, Blockly.JavaScript.ORDER_ATOMIC];
|
return [code, Blockly.JavaScript.ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_i2c_read_device'] = function (block) {
|
// Blockly.Python['ugj_i2c_read_device'] = function (block) {
|
||||||
var value_count = Blockly.Python.valueToCode(block, 'count', Blockly.Python.ORDER_ATOMIC);
|
// var value_count = Blockly.Python.valueToCode(block, 'count', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.i2c_read_device(i2c_hand, ${value_count}).decode()`;
|
// var code = `await pi.i2c_read_device(i2c_hand, ${value_count}).decode()`;
|
||||||
return [code, Blockly.Python.ORDER_ATOMIC];
|
// return [code, Blockly.Python.ORDER_ATOMIC];
|
||||||
};
|
// };
|
||||||
/********************************************** */
|
/********************************************** */
|
||||||
/** Writes the data bytes to the raw device. ** */
|
/** Writes the data bytes to the raw device. ** */
|
||||||
/********************************************** */
|
/********************************************** */
|
||||||
@ -1013,14 +1013,11 @@ Blockly.JavaScript['ugj_i2c_write_device'] = function (block) {
|
|||||||
var code = `await _pi.i2c_write_device(${value_data})\n`;
|
var code = `await _pi.i2c_write_device(${value_data})\n`;
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Blockly.Python['ugj_i2c_write_device'] = function (block) {
|
// Blockly.Python['ugj_i2c_write_device'] = function (block) {
|
||||||
var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
|
// var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
|
||||||
var code = `await pi.i2c_write_device(i2c_hand, ${value_data}.encode())\n`;
|
// var code = `await pi.i2c_write_device(i2c_hand, ${value_data}.encode())\n`;
|
||||||
return code;
|
// return code;
|
||||||
};
|
// };
|
||||||
|
|
||||||
/** センサー */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Multimedia *****************************************************************************************************/
|
/** Multimedia *****************************************************************************************************/
|
||||||
@ -2576,7 +2573,7 @@ Blockly.JavaScript['ugj_sleep'] = function (block) {
|
|||||||
Blockly.Python['ugj_sleep'] = function (block) {
|
Blockly.Python['ugj_sleep'] = function (block) {
|
||||||
var value_sec = Blockly.Python.valueToCode(block, 'sec', Blockly.Python.ORDER_ATOMIC);
|
var value_sec = Blockly.Python.valueToCode(block, 'sec', Blockly.Python.ORDER_ATOMIC);
|
||||||
Blockly.Python.provideFunction_(
|
Blockly.Python.provideFunction_(
|
||||||
'import_sleep', ['from time import sleep']
|
'import_sleep', ['from utime import sleep']
|
||||||
)
|
)
|
||||||
var code = `sleep(${value_sec})\n`;
|
var code = `sleep(${value_sec})\n`;
|
||||||
return code;
|
return code;
|
||||||
|
Loading…
Reference in New Issue
Block a user