Orange Pi 5 + rgpio で GPIO や I2C の一部動作を確認

This commit is contained in:
ocogeclub 2023-04-11 22:25:50 +09:00
parent af9749333b
commit 7a2997c35a
15 changed files with 635 additions and 63 deletions

1
.npmrc Normal file
View File

@ -0,0 +1 @@
legacy-peer-deps=true

View File

@ -14,7 +14,7 @@ const ugj_const = {
localStorage_fname: 'ocoge.json', localStorage_fname: 'ocoge.json',
error_ja_all: 'エラーが発生しました。\n『おこげ倶楽部』までお問い合わせください。', error_ja_all: 'エラーが発生しました。\n『おこげ倶楽部』までお問い合わせください。',
pig: 'pigpio', pig: 'pigpio',
lg: 'lgpio', // 対応未定 rg: 'rgpio',
i2c_defbus: '1', // 文字列リテラルで指定 i2c_defbus: '1', // 文字列リテラルで指定
lang: 'js', lang: 'js',
dev_hash: '4e9205f9b7e571bec1aa52ab7871f420684fcf96149672a4d550a95863d6b072' dev_hash: '4e9205f9b7e571bec1aa52ab7871f420684fcf96149672a4d550a95863d6b072'
@ -31,7 +31,7 @@ class appTool {
this.saveFilepath = null; this.saveFilepath = null;
this.wsChanged = false; this.wsChanged = false;
this.children = []; this.children = [];
this.gpio_backend = ugj_const.pig; this.gpio_lib = ugj_const.pig;
this.i2c_bus = ugj_const.i2c_defbus; this.i2c_bus = ugj_const.i2c_defbus;
this.lang = ugj_const.lang; 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);
@ -207,7 +207,7 @@ class appTool {
// GPIO 関連リロードでGPIOをロックしたままハンドルを失うのを防ぐ // GPIO 関連リロードでGPIOをロックしたままハンドルを失うのを防ぐ
cleanupGPIO() { cleanupGPIO() {
// this.ugjEmitter.emit('device_stop');//デバイス停止イベント // this.ugjEmitter.emit('device_stop');//デバイス停止イベント
require('@ocoge.club/' + this.gpio_backend).close_all_handle(); require('@ocoge.club/' + this.gpio_lib).close_all_handle();
} }
// 設定(保存ファイルパスと未保存フラグ)をローカルストレージに保存 // 設定(保存ファイルパスと未保存フラグ)をローカルストレージに保存
@ -221,7 +221,8 @@ class appTool {
'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 'lang': this.lang,
'gpio_lib': this.gpio_lib
}; };
let s = JSON.stringify(o); let s = JSON.stringify(o);
localStorage.setItem(ugj_const.localStorage_fname, s); localStorage.setItem(ugj_const.localStorage_fname, s);
@ -242,8 +243,15 @@ class appTool {
this.ipcRenderer.send('i2c_check_menu', 'i2c-' + this.i2c_bus); this.ipcRenderer.send('i2c_check_menu', 'i2c-' + this.i2c_bus);
} }
if (o.lang) { if (o.lang) {
this.setLang(o.lang); let l;
this.ipcRenderer.send('lang_check_menu', this.lang); if (o.lang == 'js' || o.gpio_lib) {
l = o.lang + '-' + o.gpio_lib;
} else {
l = o.lang;
}
this.setLang(l);
console.log(`l= ${l}`);
this.ipcRenderer.send('lang_check_menu', l);
} }
} }
} }
@ -261,11 +269,18 @@ class appTool {
this.i2c_bus = n; this.i2c_bus = n;
} }
// 言語変更 // 言語/GPIOライブラリ変更
setLang(l) { setLang(l) {
this.lang = l; if (l == 'js-pigpio') {
this.lang = 'js';
this.gpio_lib = ugj_const.pig;
} else if (l == 'js-rgpio') {
this.lang = 'js';
this.gpio_lib = ugj_const.rg;
} else this.lang = 'py';
const exp = document.getElementById('dlgExport'); const exp = document.getElementById('dlgExport');
if (l == 'js') { if (this.lang == 'js') {
exp.innerText = 'ファイルへ保存'; exp.innerText = 'ファイルへ保存';
exp.title = 'ソースコードをファイルに保存します。'; exp.title = 'ソースコードをファイルに保存します。';
} else { } else {
@ -300,7 +315,7 @@ class appTool {
class webTool { class webTool {
constructor() { constructor() {
// GPIOブロックは使えません // GPIOブロックは使えません
this.gpio_backend = ugj_const.pig; this.gpio_lib = ugj_const.pig;
this.lang = 'js'; this.lang = 'js';
this.blocks_dir = ugj_const.blocks_dir; this.blocks_dir = ugj_const.blocks_dir;
} }

View File

@ -185,7 +185,7 @@ Blockly.Blocks['ugj_gpio_open'] = {
}; };
Blockly.JavaScript['ugj_gpio_open'] = function (block) { Blockly.JavaScript['ugj_gpio_open'] = function (block) {
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_backend + `');`] 'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_lib + `');`]
); );
var code = `await _pi.gpio_open();\n`; // var code = `await _pi.gpio_open();\n`; //
return code; return code;
@ -540,7 +540,7 @@ Blockly.JavaScript['ugj_serial_open'] = function (block) {
// var value_tty = Blockly.JavaScript.valueToCode(block, 'tty', Blockly.JavaScript.ORDER_ATOMIC); // var value_tty = Blockly.JavaScript.valueToCode(block, 'tty', Blockly.JavaScript.ORDER_ATOMIC);
var dropdown_baud = block.getFieldValue('baud'); var dropdown_baud = block.getFieldValue('baud');
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_backend + `');`] 'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_lib + `');`]
); );
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;
@ -680,7 +680,7 @@ Blockly.Blocks['ugj_i2c_open'] = {
Blockly.JavaScript['ugj_i2c_open'] = function (block) { Blockly.JavaScript['ugj_i2c_open'] = function (block) {
var value_i2c_address = Blockly.JavaScript.valueToCode(block, 'i2c_address', Blockly.JavaScript.ORDER_ATOMIC); var value_i2c_address = Blockly.JavaScript.valueToCode(block, 'i2c_address', Blockly.JavaScript.ORDER_ATOMIC);
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_backend + `');`] 'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_lib + `');`]
); );
var code = `await _pi.i2c_open(${apptool.i2c_bus}, ${value_i2c_address});\n`; var code = `await _pi.i2c_open(${apptool.i2c_bus}, ${value_i2c_address});\n`;
return code; return code;

View File

@ -0,0 +1,55 @@
'use strict';
const err_msg = 'AMG8833 is already opened. Please close old connection to use new one.';
const pig = require('@ocoge.club/rgpio');
let pi = -1;
let i2c_hand = -1;
exports.init = async (i2c_bus, i2c_addr, wael = null) => {
if (wael !== null) {
wael('beforeunload', async () => {
await exports.stop();
});
}
if (pi >= 0) { throw new Error(err_msg); return; }
pi = await pig._rgpiod_start('', '');
console.log('pi=' + pi);
if (i2c_hand >= 0) { throw new Error(err_msg); return; }
i2c_hand = await pig._i2c_open(pi, i2c_bus, i2c_addr, 0);
console.log('i2c_hand=' + i2c_hand);
await pig._i2c_write_byte_data(pi, i2c_hand, 0x00, 0x00); //Normal mode
await pig._i2c_write_byte_data(pi, i2c_hand, 0x02, 0x00); //10FPS
}
exports.read_thermistor = async () => {
let temp = await pig._i2c_read_word_data(pi, i2c_hand, 0x0e);
return temp * 0.0625;
}
exports.read_temp_array = async () => {
let linedata = [];
for (let i = 0; i < 8; i++) {
let data = await pig._i2c_read_i2c_block_data(pi, i2c_hand, 0x80 + 0x10 * i, 16);
let oneline = [];
for (let j = 0; j < 8; j++) {
oneline.push(((data[2 * j + 1] & 0x07) * 256 + data[2 * j]) * 0.25);
}
linedata.push(oneline);
}
return linedata;
}
exports.stop = async () => {
if (i2c_hand >= 0) {
await pig._i2c_close(pi, i2c_hand);
i2c_hand = -1;
}
if (pi >= 0) {
await pig._rgpiod_stop(pi);
pi = -1;
}
}
/*
* This code was ported from https://www.denshi.club/pc/raspi/5raspberry-pi-zeroiot381i2c-amg8833.html
*/

View File

@ -53,10 +53,10 @@ Blockly.defineBlocksWithJsonArray([{
}]); }]);
Blockly.JavaScript['ugj_grideye_init'] = function (block) { Blockly.JavaScript['ugj_grideye_init'] = function (block) {
var dropdown_addr = block.getFieldValue('addr'); var dropdown_addr = block.getFieldValue('addr');
Blockly.JavaScript.provideFunction_( // Blockly.JavaScript.provideFunction_(
'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_backend + `');`] // 'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_lib + `');`]
); // );
let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'amg8833', 'AMG8833x.js'); let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'amg8833', `AMG8833x_${apptool.gpio_lib}.js`);
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_amg8833', [`const _amg8833 = require('${modpath}');`] 'require_amg8833', [`const _amg8833 = require('${modpath}');`]
); );

View File

@ -18,7 +18,7 @@ Blockly.Blocks['ugj_bme280'] = {
Blockly.JavaScript['ugj_bme280'] = function (block) { Blockly.JavaScript['ugj_bme280'] = function (block) {
var dropdown_addr = block.getFieldValue('addr'); var dropdown_addr = block.getFieldValue('addr');
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_backend + `');`] 'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_lib + `');`]
); );
let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'bme280', 'BME280x.js'); let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'bme280', 'BME280x.js');
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(

View File

@ -33,7 +33,7 @@ Blockly.Blocks['ugj_gesture_init'] = {
Blockly.JavaScript['ugj_gesture_init'] = function (block) { Blockly.JavaScript['ugj_gesture_init'] = function (block) {
var value_i2c_addr = Blockly.JavaScript.valueToCode(block, 'i2c_addr', Blockly.JavaScript.ORDER_ATOMIC); var value_i2c_addr = Blockly.JavaScript.valueToCode(block, 'i2c_addr', Blockly.JavaScript.ORDER_ATOMIC);
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_backend + `');`] 'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_lib + `');`]
); );
let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'paj7620', 'PAJ7620x.js'); let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'paj7620', 'PAJ7620x.js');
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(

View File

@ -0,0 +1,12 @@
{
"targets": [
{
"target_name": "rgpio",
"sources": ["rgpio.cpp"],
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
"include_dirs": ["<!@(node -p \"require( 'node-addon-api' ).include\")"],
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
"libraries": ["-lrgpio"],
}
]
}

View File

@ -0,0 +1,70 @@
module.exports = require('bindings')('rgpio');
// module.exports.SET_ACTIVE_LOW = 4;
// module.exports.SET_OPEN_DRAIN = 8;
// module.exports.SET_OPEN_SOURCE = 16;
// module.exports.SET_PULL_UP = 32;
// module.exports.SET_PULL_DOWN = 64;
// module.exports.SET_PULL_NONE = 128;
module.exports.PULL_UP = 32;
module.exports.PULL_DOWN = 64;
module.exports.PULL_NONE = 128;
const CHIP_COUNT = 5;
const port = '';
let sbc = -1;
let gpiochip_hand = [];
let ser_hand = -1;
let i2c_hand = -1;
module.exports.gpio_open = async () => {
sbc = await module.exports._rgpiod_start('', port);
if (sbc < 0) return sbc;
for (let i = 0; i < CHIP_COUNT; i++) {
gpiochip_hand.push(await module.exports._gpiochip_open(sbc, i));
}
return gpiochip_hand;
}
module.exports.gpio_close = async () => {
for (let i = 0; i < CHIP_COUNT; i++) {
await module.exports._gpiochip_close(sbc, gpiochip_hand[i]);
}
gpiochip_hand = [];
await module.exports._rgpiod_stop(sbc);
sbc = -1;
}
module.exports.gpio_set_output = async gpio => {
let chip = Math.floor(gpio / 32);
let pin = Math.floor(gpio % 32);
if (gpiochip_hand[chip] >= 0) return await module.exports._gpio_claim_output(sbc, gpiochip_hand[chip], pin);
}
module.exports.gpio_write = async (gpio, value) => {
let chip = Math.floor(gpio / 32);
let pin = Math.floor(gpio % 32);
if (gpiochip_hand[chip] >= 0) return await module.exports._gpio_write(sbc, gpiochip_hand[chip], pin, value);
}
module.exports.i2c_open = async (i2c_bus, i2c_address) => {
if (i2c_hand >= 0) await module.exports._i2c_close(i2c_hand); // 勝手に閉じる
i2c_hand = await module.exports._i2c_open(sbc, i2c_bus, i2c_address, 0);
return i2c_hand;
}
module.exports.i2c_close = async () => {
if (i2c_hand >= 0) await module.exports._i2c_close(sbc, i2c_hand);
i2c_hand = -1;
}
module.exports.i2c_write_byte_data = async (reg, byte_val) => {
if (i2c_hand >= 0) return await module.exports._i2c_write_byte_data(sbc, i2c_hand, reg, byte_val);
}
module.exports.i2c_write_i2c_block_data = async (reg, data) => {
if (i2c_hand >= 0) return await module.exports._i2c_write_i2c_block_data(sbc, i2c_hand, reg, Buffer.from(data));
}
module.exports.i2c_read_word_data = async reg => {
if (i2c_hand >= 0) return await module.exports._i2c_read_word_data(sbc, i2c_hand, reg);
}
// 終了処理
module.exports.close_all_handle = async () => {
await module.exports.gpio_close();
// await module.exports.serial_close();
await module.exports.i2c_close();
}

View File

@ -0,0 +1,11 @@
{
"name": "@ocoge.club/rgpio",
"version": "0.0.1",
"main": "index.js",
"private": true,
"license": "MIT",
"dependencies": {
"bindings": "^1.5.0",
"node-addon-api": "^1.7.1"
}
}

View File

@ -0,0 +1,337 @@
/** lgpio を Node.js から利用するモジュール ** */
/** 関数名・書式は lgpio Python に準拠 ******************* */
#include <napi.h>
#include <rgpio.h>
#include <unistd.h>
#include <string>
using namespace Napi;
// rgpio デーモンに接続
Promise _rgpiodStart(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 2)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
if (!info[0].IsString() || !info[1].IsString())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
std::string ipaddr = info[0].As<String>().Utf8Value();
std::string port = info[1].As<String>().Utf8Value();
deferred.Resolve(Number::New(env, rgpiod_start(ipaddr.c_str(), port.c_str())));
}
return deferred.Promise();
}
// rgpioデーモンとの接続を閉じる
Promise _rgpiodStop(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 1)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
if (!info[0].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
rgpiod_stop(sbc);
deferred.Resolve(env.Null());
}
return deferred.Promise();
}
// gpiochipデバイスを開く
Promise _gpiochipOpen(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 2)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
int gpioDev = info[1].As<Number>().Int32Value();
deferred.Resolve(Number::New(env, gpiochip_open(sbc, gpioDev)));
}
return deferred.Promise();
}
// gpiochipデバイスを閉じる
Promise _gpiochipClose(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 2)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
int handle = info[1].As<Number>().Int32Value();
deferred.Resolve(Number::New(env, gpiochip_close(sbc, handle)));
}
return deferred.Promise();
}
// GPIO のモードを出力にする(ことを要求?)
Promise _gpioClaimOutput(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 3)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
int handle = info[1].As<Number>().Int32Value();
int gpio = info[2].As<Number>().Int32Value();
deferred.Resolve(Number::New(env, gpio_claim_output(sbc, handle, 0, gpio, 0)));
}
return deferred.Promise();
}
// GPIO のモードを入力にする(ことを要求?)
// GPIOの電圧を読む
// GPIO の電圧をセットする
Promise _gpioWrite(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 4)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber() || !info[3].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
int handle = info[1].As<Number>().Int32Value();
int gpio = info[2].As<Number>().Int32Value();
int value = info[3].As<Number>().Int32Value();
deferred.Resolve(Number::New(env, gpio_write(sbc, handle, gpio, value)));
}
return deferred.Promise();
}
// I2Cバスアドレスのデバイスのハンドルを返す
Promise _i2cOpen(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 4)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
else if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber() || !info[3].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
unsigned int i2c_bus = info[1].As<Number>().Uint32Value();
unsigned int i2c_addr = info[2].As<Number>().Uint32Value();
int flags = 0;
deferred.Resolve(Number::New(env, i2c_open(sbc, i2c_bus, i2c_addr, flags)));
}
return deferred.Promise();
}
// オープン済みI2Cハンドルを閉じる
Promise _i2cClose(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 2)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
else if (!info[0].IsNumber() || !info[1].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
unsigned int handle = info[1].As<Number>().Uint32Value();
deferred.Resolve(Number::New(env, i2c_close(sbc, handle)));
}
return deferred.Promise();
}
// I2Cハンドルに関連付けられているデバイスの指定されたレジスタに1バイトを書き込む
Promise _i2cWriteByteData(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 4)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
else if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber() || !info[3].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
unsigned int handle = info[1].As<Number>().Uint32Value();
unsigned int i2c_reg = info[2].As<Number>().Uint32Value();
unsigned int bVal = info[3].As<Number>().Uint32Value();
deferred.Resolve(Number::New(env, i2c_write_byte_data(sbc, handle, i2c_reg, bVal)));
}
return deferred.Promise();
}
// I2Cハンドルに関連付けられているデバイスの指定されたレジスタからcountバイトを読み込む。countは132。
Promise _i2cReadI2cBlockData(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 4)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
else if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber() || !info[3].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
unsigned int handle = info[1].As<Number>().Uint32Value();
unsigned int i2cReg = info[2].As<Number>().Uint32Value();
unsigned int count = info[3].As<Number>().Uint32Value();
char buf[count];
int rxCount = i2c_read_i2c_block_data(sbc, handle, i2cReg, buf, count);
auto outBuf = Buffer<char>::Copy(env, buf, rxCount);
deferred.Resolve(outBuf);
}
return deferred.Promise();
}
// I2Cハンドルに関連付けられているデバイスの指定されたレジスタに最大バイトのデータを書き込む。
Promise _i2cWriteI2cBlockData(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 4)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
else if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber() || !info[3].IsBuffer())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
unsigned int handle = info[1].As<Number>().Uint32Value();
unsigned int i2c_reg = info[2].As<Number>().Uint32Value();
auto buf = info[3].As<Buffer<char>>();
unsigned int count = buf.Length();
deferred.Resolve(Number::New(env, i2c_write_i2c_block_data(sbc, handle, i2c_reg, buf.Data(), count)));
}
return deferred.Promise();
}
// I2Cハンドルに関連付けられているデバイスの指定されたレジスタから単一の16ビットワードを読み取る
Promise _i2cReadWordData(const CallbackInfo &info)
{
Env env = info.Env();
auto deferred = Napi::Promise::Deferred::New(env);
if (info.Length() != 3)
{
deferred.Reject(
TypeError::New(env, "Invalid argument count").Value());
}
else if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber())
{
deferred.Reject(
Napi::TypeError::New(env, "Invalid argument types").Value());
}
else
{
int sbc = info[0].As<Number>().Int32Value();
unsigned int handle = info[1].As<Number>().Uint32Value();
unsigned int i2c_reg = info[2].As<Number>().Uint32Value();
deferred.Resolve(Number::New(env, i2c_read_word_data(sbc, handle, i2c_reg)));
}
return deferred.Promise();
}
Object
Init(Env env, Object exports)
{
exports.Set(String::New(env, "_rgpiod_start"), Function::New(env, _rgpiodStart));
exports.Set(String::New(env, "_rgpiod_stop"), Function::New(env, _rgpiodStop));
exports.Set(String::New(env, "_gpiochip_open"), Function::New(env, _gpiochipOpen));
exports.Set(String::New(env, "_gpiochip_close"), Function::New(env, _gpiochipClose));
exports.Set(String::New(env, "_gpio_claim_output"), Function::New(env, _gpioClaimOutput));
exports.Set(String::New(env, "_gpio_write"), Function::New(env, _gpioWrite));
exports.Set(String::New(env, "_i2c_open"), Function::New(env, _i2cOpen));
exports.Set(String::New(env, "_i2c_close"), Function::New(env, _i2cClose));
exports.Set(String::New(env, "_i2c_write_byte_data"), Function::New(env, _i2cWriteByteData));
exports.Set(String::New(env, "_i2c_read_i2c_block_data"), Function::New(env, _i2cReadI2cBlockData));
exports.Set(String::New(env, "_i2c_write_i2c_block_data"), Function::New(env, _i2cWriteI2cBlockData));
exports.Set(String::New(env, "_i2c_read_word_data"), Function::New(env, _i2cReadWordData));
return exports;
}
NODE_API_MODULE(rgpio, Init)

94
main.js
View File

@ -53,14 +53,14 @@ function createWindow() {
} }
const toggleCheck_i2c = checked_id => { const toggleCheck_i2c = checked_id => {
const menus = ['i2c-1', 'i2c-6']; const menus = ['i2c-1', 'i2c-5', 'i2c-6'];
menus.forEach(id => { menus.forEach(id => {
menu.getMenuItemById(id).checked = (id == checked_id); menu.getMenuItemById(id).checked = (id == checked_id);
}) })
} }
const toggleCheck_lang = checked_id => { const toggleCheck_lang = checked_id => {
const menus = ['js', 'py']; const menus = ['js-pigpio', 'js-rgpio', 'py'];
menus.forEach(id => { menus.forEach(id => {
menu.getMenuItemById(id).checked = (id == checked_id); menu.getMenuItemById(id).checked = (id == checked_id);
}) })
@ -155,48 +155,32 @@ let template = [
{ {
label: "Settings", label: "Settings",
submenu: [ 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('apptool.setI2cbusNo("1")');
}
}
},
{
label: "6",
id: "i2c-6",
type: 'checkbox',
click: (item, focusedWindow) => {
if (focusedWindow) {
toggleCheck_i2c("i2c-6");
focusedWindow.webContents.executeJavaScript('apptool.setI2cbusNo("6")');
}
}
},
]
},
{ {
label: "Language", label: "Language",
submenu: [ submenu: [
{ {
label: "JavaScript", label: "JavaScript (pigpio)",
id: "js", id: "js-pigpio",
type: 'checkbox', type: 'checkbox',
checked: true, checked: true,
click: (item, focusedWindow) => { click: (item, focusedWindow) => {
if (focusedWindow) { if (focusedWindow) {
// menu.getMenuItemById('py').checked = false; // menu.getMenuItemById('py').checked = false;
toggleCheck_lang("js"); toggleCheck_lang("js-pigpio");
focusedWindow.webContents.executeJavaScript('apptool.setLang("js")'); focusedWindow.webContents.executeJavaScript('apptool.setLang("js-pigpio")');
}
}
},
{
label: "JavaScript (rgpio)",
id: "js-rgpio",
type: 'checkbox',
checked: true,
click: (item, focusedWindow) => {
if (focusedWindow) {
// menu.getMenuItemById('py').checked = false;
toggleCheck_lang("js-rgpio");
focusedWindow.webContents.executeJavaScript('apptool.setLang("js-rgpio")');
} }
} }
}, },
@ -215,6 +199,46 @@ let template = [
] ]
},
{
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('apptool.setI2cbusNo("1")');
}
}
},
{
label: "5",
id: "i2c-5",
type: 'checkbox',
click: (item, focusedWindow) => {
if (focusedWindow) {
toggleCheck_i2c("i2c-5");
focusedWindow.webContents.executeJavaScript('apptool.setI2cbusNo("5")');
}
}
},
{
label: "6",
id: "i2c-6",
type: 'checkbox',
click: (item, focusedWindow) => {
if (focusedWindow) {
toggleCheck_i2c("i2c-6");
focusedWindow.webContents.executeJavaScript('apptool.setI2cbusNo("6")');
}
}
},
]
} }
] ]
}, },

58
package-lock.json generated
View File

@ -1,16 +1,15 @@
{ {
"name": "ocoge", "name": "ocoge",
"version": "0.1.10", "version": "0.1.11",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ocoge", "name": "ocoge",
"version": "0.1.10", "version": "0.1.11",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@blockly/field-slider": "^4.0.12", "@blockly/field-slider": "^4.0.12",
"@ocoge.club/pigpio": "file:local_modules/pigpio",
"@tensorflow-models/blazeface": "^0.0.7", "@tensorflow-models/blazeface": "^0.0.7",
"@tensorflow-models/knn-classifier": "^1.2.4", "@tensorflow-models/knn-classifier": "^1.2.4",
"@tensorflow-models/mobilenet": "^2.1.0", "@tensorflow-models/mobilenet": "^2.1.0",
@ -29,6 +28,10 @@
"@electron-forge/maker-deb": "^6.1.1", "@electron-forge/maker-deb": "^6.1.1",
"@electron/rebuild": "^3.2.10", "@electron/rebuild": "^3.2.10",
"electron": "^24.0.0" "electron": "^24.0.0"
},
"optionalDependencies": {
"@ocoge.club/pigpio": "file:local_modules/pigpio",
"@ocoge.club/rgpio": "file:local_modules/rgpio"
} }
}, },
"node_modules/@blockly/field-slider": { "node_modules/@blockly/field-slider": {
@ -668,6 +671,7 @@
"resolved": "file:local_modules/pigpio", "resolved": "file:local_modules/pigpio",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"bindings": "^1.5.0", "bindings": "^1.5.0",
"node-addon-api": "^1.7.1" "node-addon-api": "^1.7.1"
@ -676,7 +680,25 @@
"node_modules/@ocoge.club/pigpio/node_modules/node-addon-api": { "node_modules/@ocoge.club/pigpio/node_modules/node-addon-api": {
"version": "1.7.2", "version": "1.7.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
"integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==" "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
"optional": true
},
"node_modules/@ocoge.club/rgpio": {
"version": "0.0.1",
"resolved": "file:local_modules/rgpio",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"bindings": "^1.5.0",
"node-addon-api": "^1.7.1"
}
},
"node_modules/@ocoge.club/rgpio/node_modules/node-addon-api": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
"integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
"optional": true
}, },
"node_modules/@sindresorhus/is": { "node_modules/@sindresorhus/is": {
"version": "4.6.0", "version": "4.6.0",
@ -1347,6 +1369,7 @@
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"optional": true,
"dependencies": { "dependencies": {
"file-uri-to-path": "1.0.0" "file-uri-to-path": "1.0.0"
} }
@ -2741,7 +2764,8 @@
"node_modules/file-uri-to-path": { "node_modules/file-uri-to-path": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
}, },
"node_modules/filename-reserved-regex": { "node_modules/filename-reserved-regex": {
"version": "2.0.0", "version": "2.0.0",
@ -6779,6 +6803,7 @@
}, },
"@ocoge.club/pigpio": { "@ocoge.club/pigpio": {
"version": "0.0.1", "version": "0.0.1",
"optional": true,
"requires": { "requires": {
"bindings": "^1.5.0", "bindings": "^1.5.0",
"node-addon-api": "^1.7.1" "node-addon-api": "^1.7.1"
@ -6787,7 +6812,24 @@
"node-addon-api": { "node-addon-api": {
"version": "1.7.2", "version": "1.7.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
"integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==" "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
"optional": true
}
}
},
"@ocoge.club/rgpio": {
"version": "0.0.1",
"optional": true,
"requires": {
"bindings": "^1.5.0",
"node-addon-api": "^1.7.1"
},
"dependencies": {
"node-addon-api": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
"integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
"optional": true
} }
} }
}, },
@ -7320,6 +7362,7 @@
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"optional": true,
"requires": { "requires": {
"file-uri-to-path": "1.0.0" "file-uri-to-path": "1.0.0"
} }
@ -8356,7 +8399,8 @@
"file-uri-to-path": { "file-uri-to-path": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
}, },
"filename-reserved-regex": { "filename-reserved-regex": {
"version": "2.0.0", "version": "2.0.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "ocoge", "name": "ocoge",
"version": "0.1.10", "version": "0.1.11",
"description": "ブロックベースビジュアルプログラム開発・実行環境", "description": "ブロックベースビジュアルプログラム開発・実行環境",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
@ -29,7 +29,6 @@
}, },
"dependencies": { "dependencies": {
"@blockly/field-slider": "^4.0.12", "@blockly/field-slider": "^4.0.12",
"@ocoge.club/pigpio": "file:local_modules/pigpio",
"@tensorflow-models/blazeface": "^0.0.7", "@tensorflow-models/blazeface": "^0.0.7",
"@tensorflow-models/knn-classifier": "^1.2.4", "@tensorflow-models/knn-classifier": "^1.2.4",
"@tensorflow-models/mobilenet": "^2.1.0", "@tensorflow-models/mobilenet": "^2.1.0",
@ -43,6 +42,10 @@
"nodemailer": "^6.9.1", "nodemailer": "^6.9.1",
"prismjs": "^1.29.0" "prismjs": "^1.29.0"
}, },
"optionalDependencies": {
"@ocoge.club/pigpio": "file:local_modules/pigpio",
"@ocoge.club/rgpio": "file:local_modules/rgpio"
},
"config": { "config": {
"forge": { "forge": {
"packagerConfig": {}, "packagerConfig": {},