mirror of
https://github.com/ocogeclub/ocoge.git
synced 2024-11-23 16:19:47 +00:00
[update] SSD1306サポート,RP2040を介したPWMなどを追加
This commit is contained in:
parent
a97a207d55
commit
82db8193d2
@ -14,7 +14,7 @@ const ugj_const = {
|
||||
localStorage_fname: 'ocoge.json',
|
||||
error_ja_all: 'エラーが発生しました。\n『おこげ倶楽部』までお問い合わせください。',
|
||||
pig: 'pigpio',
|
||||
rg: 'rgpio',
|
||||
rg: '@ocoge/rgpio',
|
||||
i2c_defbus: '1', // 文字列リテラルで指定
|
||||
lang: 'js',
|
||||
dev_hash: '4e9205f9b7e571bec1aa52ab7871f420684fcf96149672a4d550a95863d6b072'
|
||||
@ -309,6 +309,11 @@ class appTool {
|
||||
return formatted;
|
||||
}
|
||||
|
||||
// メインプロセス:Node-Canvas 呼び出し:OLED テキスト画像生成
|
||||
async textToRGBA(text, font, color, start_x, start_y) {
|
||||
return await this.ipcRenderer.invoke('text_to_rgba', text, font, color, start_x, start_y);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// ブラウザ動作用
|
||||
|
@ -209,7 +209,8 @@ Blockly.defineBlocksWithJsonArray([{
|
||||
"helpUrl": "",
|
||||
"style": "gpio_blocks"
|
||||
}]);
|
||||
Blockly.JavaScript['ugj_gpio_open'] = function (block) {
|
||||
javascript.javascriptGenerator.forBlock['ugj_gpio_open'] = function (block, generator) {
|
||||
// Blockly.JavaScript['ugj_gpio_open'] = function (block) {
|
||||
Blockly.JavaScript.provideFunction_(
|
||||
'require_gpio', [`const _rg = require('${apptool.gpio_lib}');`]
|
||||
);
|
||||
@ -666,9 +667,9 @@ Blockly.Blocks['oc_i2c_open'] = {
|
||||
Blockly.JavaScript['oc_i2c_open'] = function (block) {
|
||||
var value_addr = Blockly.JavaScript.valueToCode(block, 'addr', Blockly.JavaScript.ORDER_ATOMIC);
|
||||
var variable_i2c_hand = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('i2c_hand'), Blockly.Names.NameType.VARIABLE);
|
||||
Blockly.JavaScript.provideFunction_(
|
||||
'require_gpio', require_gpio
|
||||
);
|
||||
// Blockly.JavaScript.provideFunction_(
|
||||
// 'require_gpio', require_gpio
|
||||
// );
|
||||
var code = `${variable_i2c_hand} = await _rg.i2c_open(${apptool.i2c_bus}, ${value_addr});\n`;
|
||||
return code;
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ apptool.blocks_dir = (function () {
|
||||
var flyout_contents = [];
|
||||
const registerCategory = (category_dir, subcategories) => {
|
||||
for (let sbctgr of subcategories) {
|
||||
let fname = apptool.blocks_dir + category_dir + '/' + sbctgr + "/index.js";
|
||||
let fname = apptool.blocks_dir + category_dir + '/' + sbctgr;
|
||||
let script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = fname;
|
||||
@ -25,11 +25,12 @@ const registerCategory = (category_dir, subcategories) => {
|
||||
}
|
||||
|
||||
// センサーカテゴリ
|
||||
registerCategory('sensors', [ // カテゴリディレクトリ名
|
||||
"amg8833",
|
||||
"paj7620",
|
||||
"bme280",
|
||||
registerCategory('sensors', [ // サブカテゴリファイル名
|
||||
"amg8833.js",
|
||||
"paj7620.js",
|
||||
"bme280.js",
|
||||
"ssd1306.js",
|
||||
// "dht11",
|
||||
// "pico_slave",
|
||||
"z-line" // フライアウト下端の不可視ライン。スクリプトにカテゴリ名を含むので注意
|
||||
"z-line.js" // フライアウト下端の不可視ライン。スクリプトにカテゴリ名を含むので注意
|
||||
]);
|
||||
|
@ -56,11 +56,13 @@ Blockly.JavaScript['ugj_grideye_init'] = function (block) {
|
||||
// Blockly.JavaScript.provideFunction_(
|
||||
// 'require_gpio', [`const _pi = require('` + 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.js`);
|
||||
Blockly.JavaScript.provideFunction_(
|
||||
'require_amg8833', [`const _amg8833 = require('${modpath}');`]
|
||||
'require_amg8833', [`const _amg8833 = require('@ocoge/amg8833');`]
|
||||
// 'require_amg8833', [`const _amg8833 = require('${modpath}');`]
|
||||
);
|
||||
var code = `await _amg8833.init(${apptool.i2c_bus}, ${dropdown_addr}, window.addEventListener);\n`;
|
||||
var code = `await _amg8833.init(_rg, ${apptool.i2c_bus}, ${dropdown_addr});\n`;
|
||||
// var code = `await _amg8833.init(${apptool.i2c_bus}, ${dropdown_addr}, window.addEventListener);\n`;
|
||||
return code;//
|
||||
};
|
||||
/********************** */
|
@ -1,55 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const err_msg = 'AMG8833 is already opened. Please close old connection to use new one.';
|
||||
const pig = require(`${apptool.gpio_lib}`);
|
||||
|
||||
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
|
||||
*/
|
@ -21,15 +21,16 @@ Blockly.JavaScript['ugj_bme280'] = function (block) {
|
||||
// 'require_gpio', [`const _pi = require('` + 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`);
|
||||
// let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'bme280', `BME280x.js`);
|
||||
Blockly.JavaScript.provideFunction_(
|
||||
'require_bme280', [`const _bme280 = require('${modpath}');`]
|
||||
'require_bme280', [`const _bme280 = require('@ocoge/bme280');`]
|
||||
// 'require_bme280', [`const _bme280 = require('${modpath}');`]
|
||||
);
|
||||
var code = `const options = {
|
||||
i2cBusNo: ${apptool.i2c_bus},
|
||||
i2cAddress: ${dropdown_addr}
|
||||
};
|
||||
await _bme280.init(options);
|
||||
await _bme280.init(_rg, options);
|
||||
let _thp = await _bme280.readSensorData();
|
||||
let _bmedata = [];
|
||||
_bmedata[0] = Math.round(_thp.temperature_C * 10) / 10;
|
@ -35,11 +35,12 @@ Blockly.JavaScript['ugj_gesture_init'] = function (block) {
|
||||
// Blockly.JavaScript.provideFunction_(
|
||||
// 'require_gpio', [`const _pi = require('` + 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_(
|
||||
'require_paj7620', [`const _paj7620 = require('${modpath}');`]
|
||||
'require_paj7620', [`const _paj7620 = require('@ocoge/paj7620');`]
|
||||
// 'require_paj7620', [`const _paj7620 = require('${modpath}');`]
|
||||
);
|
||||
var code = `await _paj7620.init(${apptool.i2c_bus}, ${value_i2c_addr}, window.addEventListener);
|
||||
var code = `await _paj7620.init(_rg, ${apptool.i2c_bus}, ${value_i2c_addr});
|
||||
`;
|
||||
return code;
|
||||
};
|
636
blocks/sensors/ssd1306.js
Normal file
636
blocks/sensors/ssd1306.js
Normal file
@ -0,0 +1,636 @@
|
||||
/*************** */
|
||||
/** SSD1306 OLED */
|
||||
/*************** */
|
||||
Blockly.Blocks['oc_oled_init'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("有機ELディスプレイ")
|
||||
.appendField(new Blockly.FieldVariable("oled"), "i2c_device")
|
||||
.appendField("に接続");
|
||||
this.appendDummyInput()
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendField("I2Cアドレス")
|
||||
.appendField(new Blockly.FieldDropdown([["0x3c", "0x3c"], ["0x3d", "0x3d"]]), "i2c_addr");
|
||||
this.appendDummyInput()
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendField("画面サイズ(幅x高さ)")
|
||||
.appendField(new Blockly.FieldDropdown([["128x64", "128x64"], ["128x32", "128x32"], ["96x16", "96x16"]]), "disp_size");
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setStyle('sensor_blocks');
|
||||
this.setTooltip("I2C 接続の SSD1306 有機ELディスプレイを使えるようにします。");
|
||||
this.setHelpUrl("");
|
||||
}
|
||||
};
|
||||
javascript.javascriptGenerator.forBlock['oc_oled_init'] = function (block, generator) {
|
||||
var variable_i2c_device = generator.nameDB_.getName(block.getFieldValue('i2c_device'), Blockly.Names.NameType.VARIABLE);
|
||||
var dropdown_i2c_addr = block.getFieldValue('i2c_addr');
|
||||
var dropdown_disp_size = block.getFieldValue('disp_size');
|
||||
Blockly.JavaScript.provideFunction_(
|
||||
'require_oled', [`const _oled = require('@ocoge/ssd1306');`]
|
||||
);
|
||||
let size_x, size_y;
|
||||
if (dropdown_disp_size == '128x64') {
|
||||
size_x = 128;
|
||||
size_y = 64;
|
||||
}
|
||||
|
||||
var code = `var _opts = {
|
||||
width: ${size_x},
|
||||
height: ${size_y},
|
||||
address: ${dropdown_i2c_addr},
|
||||
bus: ${apptool.i2c_bus}
|
||||
};
|
||||
${variable_i2c_device} = new _oled(_rg, _opts);
|
||||
${variable_i2c_device}.clearDisplay();
|
||||
${variable_i2c_device}.turnOnDisplay();
|
||||
`;
|
||||
return code;
|
||||
};
|
||||
/** Draw Line */
|
||||
Blockly.Blocks['oc_oled_drawline'] = {
|
||||
init: function () {
|
||||
this.appendValueInput("start_x")
|
||||
.setCheck("Number")
|
||||
.appendField(new Blockly.FieldVariable("oled"), "oled_hand")
|
||||
.appendField("に線を描く:始点 (");
|
||||
this.appendValueInput("start_y")
|
||||
.setCheck("Number")
|
||||
.appendField(",");
|
||||
this.appendValueInput("end_x")
|
||||
.setCheck("Number")
|
||||
.appendField(") 終点 (");
|
||||
this.appendValueInput("end_y")
|
||||
.setCheck("Number")
|
||||
.appendField(",");
|
||||
this.appendDummyInput()
|
||||
.appendField(") 色")
|
||||
.appendField(new Blockly.FieldDropdown([["白", "1"], ["黒", "0"]]), "color");
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setStyle('sensor_blocks');
|
||||
this.setTooltip("OLED に線を描きます。");
|
||||
this.setHelpUrl("");
|
||||
}
|
||||
};
|
||||
javascript.javascriptGenerator.forBlock['oc_oled_drawline'] = function (block, generator) {
|
||||
var variable_oled_hand = generator.nameDB_.getName(block.getFieldValue('oled_hand'), Blockly.Names.NameType.VARIABLE);
|
||||
var value_start_x = generator.valueToCode(block, 'start_x', javascript.Order.ATOMIC);
|
||||
var value_start_y = generator.valueToCode(block, 'start_y', javascript.Order.ATOMIC);
|
||||
var value_end_x = generator.valueToCode(block, 'end_x', javascript.Order.ATOMIC);
|
||||
var value_end_y = generator.valueToCode(block, 'end_y', javascript.Order.ATOMIC);
|
||||
var dropdown_color = block.getFieldValue('color');
|
||||
var code = `${variable_oled_hand}.drawLine(${value_start_x}, ${value_start_y}, ${value_end_x}, ${value_end_y}, ${dropdown_color});`;
|
||||
return code;
|
||||
};
|
||||
|
||||
/** 矩形塗りつぶし */
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "oc_oled_fillrect",
|
||||
"message0": "%1 に四角形を描画して塗りつぶす:左上座標 ( %2 , %3 ) 幅 %4 高さ %5 色 %6",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "left",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "top",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "width",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "height",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "color",
|
||||
"options": [
|
||||
[
|
||||
"白",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"黒",
|
||||
"0"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"tooltip": "OLED に四角形を描画して塗りつぶします。",
|
||||
"helpUrl": "",
|
||||
"style": "sensor_blocks"
|
||||
}]);
|
||||
javascript.javascriptGenerator.forBlock['oc_oled_fillrect'] = function (block, generator) {
|
||||
var variable_oled_hand = generator.nameDB_.getName(block.getFieldValue('oled_hand'), Blockly.Names.NameType.VARIABLE);
|
||||
var value_left = generator.valueToCode(block, 'left', javascript.Order.ATOMIC);
|
||||
var value_top = generator.valueToCode(block, 'top', javascript.Order.ATOMIC);
|
||||
var value_width = generator.valueToCode(block, 'width', javascript.Order.ATOMIC);
|
||||
var value_height = generator.valueToCode(block, 'height', javascript.Order.ATOMIC);
|
||||
var dropdown_color = block.getFieldValue('color');
|
||||
var code = `${variable_oled_hand}.fillRect(${value_left}, ${value_top}, ${value_width}, ${value_height}, ${dropdown_color});\n`;
|
||||
return code;
|
||||
};
|
||||
|
||||
/** 文字を描画(node-canvas) */
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "oc_oled_canvastext",
|
||||
"message0": "%1 にテキストを表示 %2 フォント %3 %4 色 %5 %6 始点 x座標 %7 y座標 %8",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "text",
|
||||
"check": "String"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "font",
|
||||
"options": [
|
||||
[
|
||||
"美咲ゴシック(8x8)",
|
||||
"8px MisakiGothic"
|
||||
],
|
||||
[
|
||||
"PixelMplus(10x10)",
|
||||
"10px PixelMplus10"
|
||||
],
|
||||
[
|
||||
"PixelMplus(12x12)",
|
||||
"12px PixelMplus12"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_dummy",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "color",
|
||||
"options": [
|
||||
[
|
||||
"白",
|
||||
"white"
|
||||
],
|
||||
[
|
||||
"黒",
|
||||
"black"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_dummy",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "start_x",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "start_y",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
}
|
||||
],
|
||||
"inputsInline": false,
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"style": "sensor_blocks",
|
||||
"tooltip": "OLEDに指定のフォントで文字を描画します(node-canvas利用)。始点は1文字目の左下の座標です。",
|
||||
"helpUrl": ""
|
||||
}]);
|
||||
|
||||
javascript.javascriptGenerator.forBlock['oc_oled_canvastext'] = function (block, generator) {
|
||||
var variable_oled_hand = generator.nameDB_.getName(block.getFieldValue('oled_hand'), Blockly.Names.NameType.VARIABLE);
|
||||
var value_text = generator.valueToCode(block, 'text', javascript.Order.ATOMIC);
|
||||
var value_start_x = generator.valueToCode(block, 'start_x', javascript.Order.ATOMIC);
|
||||
var value_start_y = generator.valueToCode(block, 'start_y', javascript.Order.ATOMIC);
|
||||
var dropdown_font = block.getFieldValue('font');
|
||||
var dropdown_color = block.getFieldValue('color');
|
||||
var code = `${variable_oled_hand}.drawRGBAImage(await apptool.textToRGBA(${value_text}, '${dropdown_font}', '${dropdown_color}', ${value_start_x}, ${value_start_y}), 0, 0);`;
|
||||
return code;
|
||||
};
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "oc_oled_writestring",
|
||||
"message0": "%1 に英数字を表示 %2 フォント %3 %4 色 %5 %6 始点 x座標 %7 y座標 %8",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "text",
|
||||
"check": "String"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "font",
|
||||
"options": [
|
||||
["oled_3x5", "oled_3x5"],
|
||||
["tiny_4x6", "tiny_4x6"],
|
||||
["oled_5x7", "oled_5x7"],
|
||||
["small_6x8", "small_6x8"],
|
||||
["sinclair_8x8", "sinclair_8x8"],
|
||||
["sinclair_inverted_8x8", "sinclair_inverted_8x8"],
|
||||
["tiny_8x8", "tiny_8x8"],
|
||||
["cp437_8x8", "cp437_8x8"],
|
||||
["myke2_8x9", "myke2_8x9"],
|
||||
["small_8x12", "small_8x12"],
|
||||
["tron_8x12", "tron_8x12"],
|
||||
["retro_8x16", "retro_8x16"],
|
||||
["medium_numbers_12x16", "medium_numbers_12x16"],
|
||||
["big_numbers_14x24", "big_numbers_14x24"],
|
||||
["arial_bold_16x16", "arial_bold_16x16"],
|
||||
["arial_italic_16x16", "arial_italic_16x16"],
|
||||
["arial_normal_16x16", "arial_normal_16x16"],
|
||||
["big_16x16", "big_16x16"],
|
||||
["franklin_gothic_normal_16x16", "franklin_gothic_normal_16x16"],
|
||||
["hallfetica_normal_16x16", "hallfetica_normal_16x16"],
|
||||
["nadianne_16x16", "nadianne_16x16"],
|
||||
["sinclair_medium_16x16", "sinclair_medium_16x16"],
|
||||
["sinclair_medium_inverted_16x16", "sinclair_medium_inverted_16x16"],
|
||||
["swiss_721_outline_16x16", "swiss_721_outline_16x16"],
|
||||
["various_symbols_16x16", "various_symbols_16x16"],
|
||||
["dot_matrix_medium_16x22", "dot_matrix_medium_16x22"],
|
||||
["dot_matrix_medium_zero_slash_16x22", "dot_matrix_medium_zero_slash_16x22"],
|
||||
["dot_matrix_medium_numbers_only_16x22", "dot_matrix_medium_numbers_only_16x22"],
|
||||
["arial_round_16x24", "arial_round_16x24"],
|
||||
["ocr_a_extended_medium_16x24", "ocr_a_extended_medium_16x24"],
|
||||
["sixteen_segment_16x24", "sixteen_segment_16x24"],
|
||||
["grotesk_16x32", "grotesk_16x32"],
|
||||
["grotesk_bold_16x32", "grotesk_bold_16x32"],
|
||||
["retro_16x32", "retro_16x32"],
|
||||
["various_symbols_16x32", "various_symbols_16x32"],
|
||||
["various_symbols_v2_16x32", "various_symbols_v2_16x32"],
|
||||
["dot_matrix_large_numbers_only_24x29", "dot_matrix_large_numbers_only_24x29"],
|
||||
["inconsola_24x32", "inconsola_24x32"],
|
||||
["ubuntu_24x32", "ubuntu_24x32"],
|
||||
["ubuntu_bold_24x32", "ubuntu_bold_24x32"],
|
||||
["dingbats1_extra_large_32x24", "dingbats1_extra_large_32x24"],
|
||||
["various_symbols_32x32", "various_symbols_32x32"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_dummy",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "color",
|
||||
"options": [
|
||||
[
|
||||
"白",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"黒",
|
||||
"0"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_dummy",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "start_x",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "start_y",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
}
|
||||
],
|
||||
"inputsInline": false,
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"tooltip": "OLEDに指定の英字(数字)フォントで文字を描画します。始点は1文字目の左上の座標です。",
|
||||
"helpUrl": "",
|
||||
"style": "sensor_blocks"
|
||||
}]);
|
||||
javascript.javascriptGenerator.forBlock['oc_oled_writestring'] = function (block, generator) {
|
||||
var variable_oled_hand = generator.nameDB_.getName(block.getFieldValue('oled_hand'), Blockly.Names.NameType.VARIABLE);
|
||||
var value_text = generator.valueToCode(block, 'text', javascript.Order.ATOMIC);
|
||||
var dropdown_font = block.getFieldValue('font');
|
||||
var dropdown_color = block.getFieldValue('color');
|
||||
var value_start_x = generator.valueToCode(block, 'start_x', javascript.Order.ATOMIC);
|
||||
var value_start_y = generator.valueToCode(block, 'start_y', javascript.Order.ATOMIC);
|
||||
Blockly.JavaScript.provideFunction_(
|
||||
'require_fontpack', [`const _fontpack = require('oled-font-pack');`]
|
||||
);
|
||||
var code = `${variable_oled_hand}.setCursor(${value_start_x}, ${value_start_y});
|
||||
${variable_oled_hand}.writeString(_fontpack.${dropdown_font}, 1, ${value_text}, ${dropdown_color}, false);
|
||||
`;
|
||||
return code;
|
||||
};
|
||||
/** 点を描画 */
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "oc_oled_drawpixel",
|
||||
"message0": "%1 に点を描画:座標 ( %2 , %3 ) 色 %4",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "x",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "y",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "color",
|
||||
"options": [
|
||||
[
|
||||
"白",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"黒",
|
||||
"0"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"tooltip": "OLED に点を描きます。",
|
||||
"helpUrl": "",
|
||||
"style": "sensor_blocks"
|
||||
}]);
|
||||
javascript.javascriptGenerator.forBlock['oc_oled_drawpixel'] = function (block, generator) {
|
||||
var variable_oled_hand = generator.nameDB_.getName(block.getFieldValue('oled_hand'), Blockly.Names.NameType.VARIABLE);
|
||||
var value_x = generator.valueToCode(block, 'x', javascript.Order.ATOMIC);
|
||||
var value_y = generator.valueToCode(block, 'y', javascript.Order.ATOMIC);
|
||||
var dropdown_color = block.getFieldValue('color');
|
||||
var code = `${variable_oled_hand}.drawPixel([[${value_x}, ${value_y}, ${dropdown_color}]]);\n`;
|
||||
return code;
|
||||
};
|
||||
|
||||
/********* */
|
||||
/** Flyout */
|
||||
/********* */
|
||||
flyout_contents = flyout_contents.concat([
|
||||
{
|
||||
"kind": "label",
|
||||
"text": "有機ELディスプレイ(SSD1306)",
|
||||
"web-line": "4.0",
|
||||
"web-line-width": "200"
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"type": "oc_oled_init",
|
||||
"fields": {
|
||||
"type": "field_variable",
|
||||
"name": "i2c_device",
|
||||
"variable": "oled"
|
||||
},
|
||||
"fields": {
|
||||
"i2c_addr": "0x3c",
|
||||
"disp_size": "128x64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"type": "oc_oled_drawpixel",
|
||||
"fields": {
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
"inputs": {
|
||||
"x": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"y": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"fields": {
|
||||
"color": "1",
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"type": "oc_oled_drawline",
|
||||
"fields": {
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
"inputs": {
|
||||
"start_x": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_y": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"end_x": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "128"
|
||||
}
|
||||
}
|
||||
},
|
||||
"end_y": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "64"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"fields": {
|
||||
"color": "1",
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"type": "oc_oled_fillrect",
|
||||
"fields": {
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
"inputs": {
|
||||
"left": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "24"
|
||||
}
|
||||
}
|
||||
},
|
||||
"top": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "12"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "80"
|
||||
}
|
||||
}
|
||||
},
|
||||
"height": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "40"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"fields": {
|
||||
"color": "1",
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"type": "oc_oled_canvastext",
|
||||
"fields": {
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
"inputs": {
|
||||
"text": {
|
||||
"shadow": {
|
||||
"type": "text",
|
||||
"fields": {
|
||||
"TEXT": "我輩は猫である。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_x": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_y": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"fields": {
|
||||
"font": '8px MisakiGothic',
|
||||
"color": "white"
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"type": "oc_oled_writestring",
|
||||
"fields": {
|
||||
"type": "field_variable",
|
||||
"name": "oled_hand",
|
||||
"variable": "oled"
|
||||
},
|
||||
"inputs": {
|
||||
"text": {
|
||||
"shadow": {
|
||||
"type": "text",
|
||||
"fields": {
|
||||
"TEXT": "I am a cat."
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_x": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_y": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"fields": {
|
||||
"NUM": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"fields": {
|
||||
"font": 'oled_5x7',
|
||||
"color": "1"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
]);
|
||||
|
BIN
fonts/PixelMplus10-Regular.ttf
Normal file
BIN
fonts/PixelMplus10-Regular.ttf
Normal file
Binary file not shown.
BIN
fonts/PixelMplus12-Regular.ttf
Normal file
BIN
fonts/PixelMplus12-Regular.ttf
Normal file
Binary file not shown.
BIN
fonts/misaki_gothic.ttf
Normal file
BIN
fonts/misaki_gothic.ttf
Normal file
Binary file not shown.
BIN
img/oled_prog_bw.png
Normal file
BIN
img/oled_prog_bw.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 841 B |
6
index.js
6
index.js
@ -8,8 +8,10 @@ const testfunc = async () => {
|
||||
|
||||
//============ User Customize Start ===============
|
||||
// カスタムブロックカラー定義
|
||||
Blockly.HSV_SATURATION = 0.55;
|
||||
Blockly.HSV_VALUE = 0.75;
|
||||
Blockly.utils.colour.setHsvSaturation(0.55);
|
||||
Blockly.utils.colour.setHsvValue(0.75);
|
||||
// Blockly.HSV_SATURATION = 0.55;
|
||||
// Blockly.HSV_VALUE = 0.75;
|
||||
var gpio_color = '0';
|
||||
var sonsor_color = '20';
|
||||
var multimedia_color = '240';
|
||||
|
58
local_modules/amg8833/amg8833x.js
Normal file
58
local_modules/amg8833/amg8833x.js
Normal file
@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
const err_msg = 'AMG8833 is already opened. Please close old connection to use new one.';
|
||||
// const pig = require(`${apptool.gpio_lib}`);
|
||||
|
||||
// let pi = -1;
|
||||
let rg;
|
||||
let i2c_hand = -1;
|
||||
exports.init = async (_rg, 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);
|
||||
rg = _rg;
|
||||
if (i2c_hand >= 0) { throw new Error(err_msg); return; }
|
||||
i2c_hand = await rg.i2c_open(i2c_bus, i2c_addr, 0);
|
||||
// i2c_hand = await pig._i2c_open(pi, i2c_bus, i2c_addr, 0);
|
||||
console.log('i2c_hand=' + i2c_hand);
|
||||
await rg.i2c_write_byte_data(i2c_hand, 0x00, 0x00); //Normal mode
|
||||
await rg.i2c_write_byte_data(i2c_hand, 0x02, 0x00); //10FPS
|
||||
}
|
||||
|
||||
exports.read_thermistor = async () => {
|
||||
let temp = await rg.i2c_read_word_data(i2c_hand, 0x0e);
|
||||
return temp * 0.0625;
|
||||
}
|
||||
|
||||
exports.read_temp_array = async () => {
|
||||
let linedata = [];
|
||||
for (let i = 0; i < 8; i++) {
|
||||
let data = await rg.i2c_read_i2c_block_data(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 rg.i2c_close(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
|
||||
*/
|
7
local_modules/amg8833/package.json
Normal file
7
local_modules/amg8833/package.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@ocoge/amg8833",
|
||||
"version": "1.0.0",
|
||||
"main": "amg8833x.js",
|
||||
"private": true,
|
||||
"license": "MIT"
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
this.pig = null;
|
||||
this.pi = null;
|
||||
// this.pig = null;
|
||||
// this.pi = null;
|
||||
this.rg = null;
|
||||
|
||||
this.i2cBusNo = null;
|
||||
this.i2cAddress = null;
|
||||
@ -41,18 +42,19 @@ this.REGISTER_PRESSURE_DATA = 0xF7;
|
||||
this.REGISTER_TEMP_DATA = 0xFA;
|
||||
this.REGISTER_HUMIDITY_DATA = 0xFD;
|
||||
|
||||
exports.init = async (options) => {
|
||||
this.pig = require(`${apptool.gpio_lib}`);
|
||||
this.pi = await this.pig._rgpiod_start('', '');
|
||||
exports.init = async (rg, options) => {
|
||||
// this.pig = require(`${apptool.gpio_lib}`);
|
||||
// this.pi = await this.rg.rgpiod_start('', '');
|
||||
this.rg = rg;
|
||||
|
||||
this.i2cBusNo = (options && options.hasOwnProperty('i2cBusNo')) ? options.i2cBusNo : 1;
|
||||
this.i2cAddress = (options && options.hasOwnProperty('i2cAddress')) ? options.i2cAddress : this.BME280_DEFAULT_I2C_ADDRESS();
|
||||
this.i2cHand = await this.pig._i2c_open(this.pi, this.i2cBusNo, this.i2cAddress, 0);
|
||||
this.i2cHand = await this.rg.i2c_open(this.i2cBusNo, this.i2cAddress, 0);
|
||||
|
||||
let r;
|
||||
r = await this.pig._i2c_write_byte_data(this.pi, this.i2cHand, this.REGISTER_CHIPID, 0);
|
||||
r = await this.rg.i2c_write_byte_data(this.i2cHand, this.REGISTER_CHIPID, 0);
|
||||
if (r < 0) return r;
|
||||
let chipId = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_CHIPID);
|
||||
let chipId = await this.rg.i2c_read_byte_data(this.i2cHand, this.REGISTER_CHIPID);
|
||||
if (chipId !== this.CHIP_ID_BME280() &&
|
||||
chipId !== this.CHIP_ID1_BMP280() &&
|
||||
chipId !== this.CHIP_ID2_BMP280() &&
|
||||
@ -66,11 +68,11 @@ exports.init = async (options) => {
|
||||
}
|
||||
// Humidity 16x oversampling
|
||||
//
|
||||
let r = await this.pig._i2c_write_byte_data(this.pi, this.i2cHand, this.REGISTER_CONTROL_HUM, 0b00000101);
|
||||
let r = await this.rg.i2c_write_byte_data(this.i2cHand, this.REGISTER_CONTROL_HUM, 0b00000101);
|
||||
if (r < 0) return `Humidity 16x oversampling error: ${r}`;
|
||||
// Temperture/pressure 16x oversampling, normal mode
|
||||
//
|
||||
r = await this.pig._i2c_write_byte_data(this.pi, this.i2cHand, this.REGISTER_CONTROL, 0b10110111);
|
||||
r = await this.rg.i2c_write_byte_data(this.i2cHand, this.REGISTER_CONTROL, 0b10110111);
|
||||
if (r < 0) return `Temperture/pressure 16x oversampling error: ${r}`;
|
||||
|
||||
return 0;
|
||||
@ -83,7 +85,7 @@ exports.init = async (options) => {
|
||||
//
|
||||
exports.reset = async () => {
|
||||
const POWER_ON_RESET_CMD = 0xB6;
|
||||
let r = await this.pig._i2c_write_byte_data(this.pi, this.i2cHand, this.REGISTER_RESET, POWER_ON_RESET_CMD);
|
||||
let r = await this.rg.i2c_write_byte_data(this.i2cHand, this.REGISTER_RESET, POWER_ON_RESET_CMD);
|
||||
if (r < 0) return `cannot power-on reset: ${r}`;
|
||||
else return 0;
|
||||
}
|
||||
@ -94,10 +96,10 @@ exports.reset = async () => {
|
||||
//
|
||||
exports.cancel = async () => {
|
||||
if (this.i2cHand >= 0) {
|
||||
await this.pig._i2c_close(this.pi, this.i2cHand);
|
||||
await this.rg.i2c_close(this.i2cHand);
|
||||
this.i2cHand = null;
|
||||
await this.pig._rgpiod_stop(this.pi);
|
||||
this.pi = null;
|
||||
// await this.rg.rgpiod_stop(this.pi);
|
||||
// this.pi = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +110,7 @@ exports.readSensorData = async () => {
|
||||
|
||||
// Grab temperature, humidity, and pressure in a single read
|
||||
//
|
||||
let buffer = await this.pig._i2c_read_i2c_block_data(this.pi, this.i2cHand, this.REGISTER_PRESSURE_DATA, 8);
|
||||
let buffer = await this.rg.i2c_read_i2c_block_data(this.i2cHand, this.REGISTER_PRESSURE_DATA, 8);
|
||||
if (!buffer) return `couldn't grab data`;
|
||||
// Temperature (temperature first since we need t_fine for pressure and humidity)
|
||||
//
|
||||
@ -160,15 +162,15 @@ exports.readSensorData = async () => {
|
||||
}
|
||||
|
||||
exports.loadCalibration = async (callback) => {
|
||||
let buffer = await this.pig._i2c_read_i2c_block_data(this.pi, this.i2cHand, this.REGISTER_DIG_T1, 24);
|
||||
let buffer = await this.rg.i2c_read_i2c_block_data(this.i2cHand, this.REGISTER_DIG_T1, 24);
|
||||
if (buffer) {
|
||||
let h1 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H1);
|
||||
let h2 = await this.pig._i2c_read_word_data(this.pi, this.i2cHand, this.REGISTER_DIG_H2);
|
||||
let h3 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H3);
|
||||
let h4 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H4);
|
||||
let h5 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H5);
|
||||
let h5_1 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H5 + 1);
|
||||
let h6 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H6);
|
||||
let h1 = await this.rg.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H1);
|
||||
let h2 = await this.rg.i2c_read_word_data(this.i2cHand, this.REGISTER_DIG_H2);
|
||||
let h3 = await this.rg.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H3);
|
||||
let h4 = await this.rg.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H4);
|
||||
let h5 = await this.rg.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H5);
|
||||
let h5_1 = await this.rg.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H5 + 1);
|
||||
let h6 = await this.rg.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H6);
|
||||
|
||||
this.cal = {
|
||||
dig_T1: this.uint16(buffer[1], buffer[0]),
|
7
local_modules/bme280/package.json
Normal file
7
local_modules/bme280/package.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@ocoge/bme280",
|
||||
"version": "1.0.0",
|
||||
"main": "bme280x.js",
|
||||
"private": true,
|
||||
"license": "MIT"
|
||||
}
|
7
local_modules/paj7620/package.json
Normal file
7
local_modules/paj7620/package.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@ocoge/paj7620",
|
||||
"version": "1.0.0",
|
||||
"main": "paj7620x.js",
|
||||
"private": true,
|
||||
"license": "MIT"
|
||||
}
|
@ -313,22 +313,23 @@ const debug = 1;
|
||||
|
||||
const err_msg = 'PAJ7620 is already opened. Please close old connection to use new one.';
|
||||
let rg = -1;
|
||||
let sbc = -1;
|
||||
// let sbc = -1;
|
||||
let i2c_hand = -1;
|
||||
//Initialize the sensors
|
||||
exports.init = async (i2c_bus, i2c_addr, wael = null) => {
|
||||
if (wael !== null) {
|
||||
wael('beforeunload', async () => {
|
||||
await exports.stop();
|
||||
});
|
||||
}
|
||||
rg = require(`rgpio`);//${apptool.gpio_lib}
|
||||
if (sbc >= 0) { throw new Error(err_msg); return; }
|
||||
sbc = await rg._rgpiod_start('', '');
|
||||
exports.init = async (_rg, i2c_bus, i2c_addr) => {
|
||||
// if (wael !== null) {
|
||||
// wael('beforeunload', async () => {
|
||||
// await exports.stop();
|
||||
// });
|
||||
// }
|
||||
// rg = require(`rgpio`);//${apptool.gpio_lib}
|
||||
// if (sbc >= 0) { throw new Error(err_msg); return; }
|
||||
// sbc = await rg._rgpiod_start('', '');
|
||||
rg = _rg;
|
||||
if (i2c_hand >= 0) { throw new Error(err_msg); return; }
|
||||
i2c_hand = await rg._i2c_open(sbc, i2c_bus, i2c_addr, 0);
|
||||
i2c_hand = await rg.i2c_open(i2c_bus, i2c_addr, 0);
|
||||
if (debug)
|
||||
console.log("sbc=" + sbc + ", i2c_hand=" + i2c_hand);
|
||||
console.log("i2c_hand=" + i2c_hand);
|
||||
|
||||
await sleep(.001);
|
||||
await paj7620SelectBank(BANK0);
|
||||
@ -355,7 +356,7 @@ exports.init = async (i2c_bus, i2c_addr, wael = null) => {
|
||||
|
||||
// Write a byte to a register on the Gesture sensor
|
||||
const paj7620WriteReg = async (addr, cmd) =>
|
||||
await rg._i2c_write_word_data(sbc, i2c_hand, addr, cmd);
|
||||
await rg.i2c_write_word_data(i2c_hand, addr, cmd);
|
||||
|
||||
//Select a register bank on the Gesture Sensor
|
||||
const paj7620SelectBank = async bank => {
|
||||
@ -365,7 +366,7 @@ const paj7620SelectBank = async bank => {
|
||||
|
||||
//Read a block of bytes of length "qty" starting at address "addr" from the Gesture sensor
|
||||
const paj7620ReadReg = async (addr, qty) => {
|
||||
return await rg._i2c_read_i2c_block_data(sbc, i2c_hand, addr, qty);
|
||||
return await rg.i2c_read_i2c_block_data(i2c_hand, addr, qty);
|
||||
}
|
||||
|
||||
//Return a vlaue from the gestire sensor which can be used in a program
|
||||
@ -457,13 +458,13 @@ exports.return_gesture = async () => {
|
||||
|
||||
exports.stop = async () => {
|
||||
if (i2c_hand >= 0) {
|
||||
await rg._i2c_close(sbc, i2c_hand);
|
||||
await rg.i2c_close(i2c_hand);
|
||||
i2c_hand = -1;
|
||||
}
|
||||
if (sbc >= 0) {
|
||||
await rg._rgpiod_stop(sbc);
|
||||
sbc = -1;
|
||||
}
|
||||
// if (sbc >= 0) {
|
||||
// await rg.rgpiod_stop(sbc);
|
||||
// sbc = -1;
|
||||
// }
|
||||
}
|
||||
|
||||
/*
|
@ -94,12 +94,18 @@ module.exports.i2c_write_byte_data = async (handle, reg, byte_val) => {
|
||||
module.exports.i2c_read_byte_data = async (handle, reg) => {
|
||||
return await module.exports._i2c_read_byte_data(sbc, handle, reg);
|
||||
}
|
||||
module.exports.i2c_read_i2c_block_data = async (handle, reg, count = -1) => {
|
||||
return await module.exports._i2c_read_i2c_block_data(sbc, handle, reg, count);
|
||||
}
|
||||
module.exports.i2c_write_i2c_block_data = async (handle, reg, data) => {
|
||||
return await module.exports._i2c_write_i2c_block_data(sbc, handle, reg, Buffer.from(data), -1);
|
||||
}
|
||||
module.exports.i2c_read_word_data = async (handle, reg) => {
|
||||
return await module.exports._i2c_read_word_data(sbc, handle, reg);
|
||||
}
|
||||
module.exports.i2c_write_word_data = async (handle, reg, word_val) => {
|
||||
return await module.exports._i2c_write_word_data(sbc, handle, reg, word_val);
|
||||
}
|
||||
module.exports.i2c_read_device = async (handle, count) => {
|
||||
return new TextDecoder().decode(await module.exports._i2c_read_device(sbc, handle, count));
|
||||
}
|
||||
@ -107,6 +113,37 @@ module.exports.i2c_write_device = async (handle, data) => {
|
||||
return await module.exports._i2c_write_device(sbc, handle, Buffer.from(data), -1);
|
||||
}
|
||||
|
||||
/***** 同期関数 *****/
|
||||
module.exports.rgpio_sbc_sync = (host = 'localhost', port = 8889, show_errors = true) => {
|
||||
if (sbc < 0) {
|
||||
sbc = module.exports._rgpiod_start_sync(host, port.toString());
|
||||
if (sbc < 0) {
|
||||
if (show_errors) console.log(sbc);
|
||||
}
|
||||
}
|
||||
return sbc;
|
||||
}
|
||||
module.exports.sbc_stop_sync = () => {
|
||||
module.exports._rgpiod_stop_sync(sbc);
|
||||
chip_hand = [];
|
||||
sbc = -1;
|
||||
}
|
||||
module.exports.i2c_open_sync = (i2c_bus, i2c_address, i2c_flags = 0) => {
|
||||
return module.exports._i2c_open_sync(sbc, i2c_bus, i2c_address, i2c_flags);
|
||||
}
|
||||
module.exports.i2c_close_sync = handle => {
|
||||
module.exports._i2c_close_sync(sbc, handle);
|
||||
}
|
||||
module.exports.i2c_read_byte_sync = handle => {
|
||||
return module.exports._i2c_read_byte_sync(sbc, handle);
|
||||
}
|
||||
module.exports.i2c_write_device_sync = (handle, data, count = -1) => {
|
||||
let buffer = Buffer.from(data);
|
||||
if (count < 0) count = buffer.length;
|
||||
return module.exports._i2c_write_device_sync(sbc, handle, buffer, count);
|
||||
}
|
||||
|
||||
|
||||
// 終了処理
|
||||
module.exports.close_all_handle = async () => {
|
||||
await module.exports.sbc_stop();
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "rgpio",
|
||||
"name": "@ocoge/rgpio",
|
||||
"version": "0.0.1",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
|
@ -652,12 +652,156 @@ Promise _i2cWriteDevice(const CallbackInfo &info)
|
||||
int count = info[3].As<Number>().Uint32Value();
|
||||
|
||||
if (count < 0)
|
||||
int count = buf.Length();
|
||||
count = buf.Length();
|
||||
deferred.Resolve(Number::New(env, i2c_write_device(sbc, handle, buf.Data(), count)));
|
||||
}
|
||||
return deferred.Promise();
|
||||
}
|
||||
|
||||
/******** 同期処理関数 ********/
|
||||
// rgpio デーモンに接続
|
||||
Value _rgpiodStartSync(const CallbackInfo &info)
|
||||
{
|
||||
Env env = info.Env();
|
||||
if (info.Length() != 2)
|
||||
{
|
||||
TypeError::New(env, "Invalid argument count: _rgpiodStartSync")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else if (!info[0].IsString() || !info[1].IsString())
|
||||
{
|
||||
TypeError::New(env, "Invalid argument types: _rgpiodStartSync").ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string ipaddr = info[0].As<String>().Utf8Value();
|
||||
std::string port = info[1].As<String>().Utf8Value();
|
||||
return Number::New(env, rgpiod_start(ipaddr.c_str(), port.c_str()));
|
||||
}
|
||||
}
|
||||
// rgpioデーモンとの接続を閉じる
|
||||
Value _rgpiodStopSync(const CallbackInfo &info)
|
||||
{
|
||||
Env env = info.Env();
|
||||
if (info.Length() != 1)
|
||||
{
|
||||
TypeError::New(env, "Invalid argument count: _rgpiodStopSync")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else if (!info[0].IsNumber())
|
||||
{
|
||||
TypeError::New(env, "Invalid argument types: _rgpiodStop")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else
|
||||
{
|
||||
int sbc = info[0].As<Number>().Int32Value();
|
||||
rgpiod_stop(sbc);
|
||||
return env.Null();
|
||||
}
|
||||
}
|
||||
// I2Cバスアドレスのデバイスのハンドルを返す
|
||||
Value _i2cOpenSync(const CallbackInfo &info)
|
||||
{
|
||||
Env env = info.Env();
|
||||
if (info.Length() != 4)
|
||||
{
|
||||
TypeError::New(env, "Invalid argument count: _i2cOpen")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber() || !info[3].IsNumber())
|
||||
{
|
||||
TypeError::New(env, "Invalid argument types: _i2cOpen")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else
|
||||
{
|
||||
int sbc = info[0].As<Number>().Int32Value();
|
||||
int i2c_bus = info[1].As<Number>().Uint32Value();
|
||||
int i2c_addr = info[2].As<Number>().Uint32Value();
|
||||
int i2c_flags = info[3].As<Number>().Uint32Value();
|
||||
return Number::New(env, i2c_open(sbc, i2c_bus, i2c_addr, i2c_flags));
|
||||
}
|
||||
}
|
||||
// オープン済みI2Cハンドルを閉じる
|
||||
Value _i2cCloseSync(const CallbackInfo &info)
|
||||
{
|
||||
Env env = info.Env();
|
||||
if (info.Length() != 2)
|
||||
{
|
||||
TypeError::New(env, "Invalid argument count: _i2cClose")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else if (!info[0].IsNumber() || !info[1].IsNumber())
|
||||
{
|
||||
TypeError::New(env, "Invalid argument types: _i2cClose")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else
|
||||
{
|
||||
int sbc = info[0].As<Number>().Int32Value();
|
||||
int handle = info[1].As<Number>().Uint32Value();
|
||||
return Number::New(env, i2c_close(sbc, handle));
|
||||
}
|
||||
}
|
||||
// デバイスから1バイトを受け取る
|
||||
Value _i2cReadByteSync(const CallbackInfo &info)
|
||||
{
|
||||
Env env = info.Env();
|
||||
if (info.Length() != 2)
|
||||
{
|
||||
TypeError::New(env, "Invalid argument count: _i2cReadByteSync")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else if (!info[0].IsNumber() || !info[0].IsNumber())
|
||||
{
|
||||
TypeError::New(env, "Invalid argument types: _i2cReadByteSync")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else
|
||||
{
|
||||
int sbc = info[0].As<Number>().Int32Value();
|
||||
int handle = info[1].As<Number>().Uint32Value();
|
||||
return Number::New(env, i2c_read_byte(sbc, handle));
|
||||
}
|
||||
}
|
||||
// i2c デバイスにバイト列を送る(data: buffer)
|
||||
Value _i2cWriteDeviceSync(const CallbackInfo &info)
|
||||
{
|
||||
Env env = info.Env();
|
||||
if (info.Length() != 4)
|
||||
{
|
||||
TypeError::New(env, "Invalid argument count: _i2cWriteDevice")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsBuffer() || !info[3].IsNumber())
|
||||
{
|
||||
TypeError::New(env, "Invalid argument types: _i2cWriteDevice")
|
||||
.ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
else
|
||||
{
|
||||
int sbc = info[0].As<Number>().Int32Value();
|
||||
int handle = info[1].As<Number>().Uint32Value();
|
||||
auto buf = info[2].As<Buffer<char>>();
|
||||
int count = info[3].As<Number>().Uint32Value();
|
||||
|
||||
return Number::New(env, i2c_write_device(sbc, handle, buf.Data(), count));
|
||||
}
|
||||
}
|
||||
|
||||
Object
|
||||
Init(Env env, Object exports)
|
||||
{
|
||||
@ -686,6 +830,13 @@ Init(Env env, Object exports)
|
||||
exports.Set(String::New(env, "_i2c_write_word_data"), Function::New(env, _i2cWriteWordData));
|
||||
exports.Set(String::New(env, "_i2c_write_device"), Function::New(env, _i2cWriteDevice));
|
||||
exports.Set(String::New(env, "_i2c_read_device"), Function::New(env, _i2cReadDevice));
|
||||
exports.Set(String::New(env, "_rgpiod_start_sync"), Function::New(env, _rgpiodStartSync));
|
||||
exports.Set(String::New(env, "_rgpiod_stop_sync"), Function::New(env, _rgpiodStopSync));
|
||||
exports.Set(String::New(env, "_i2c_open_sync"), Function::New(env, _i2cOpenSync));
|
||||
exports.Set(String::New(env, "_i2c_close_sync"), Function::New(env, _i2cCloseSync));
|
||||
exports.Set(String::New(env, "_i2c_read_byte_sync"), Function::New(env, _i2cReadByteSync));
|
||||
exports.Set(String::New(env, "_i2c_write_device_sync"), Function::New(env, _i2cWriteDeviceSync));
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
|
669
local_modules/ssd1306/oled.js
Normal file
669
local_modules/ssd1306/oled.js
Normal file
@ -0,0 +1,669 @@
|
||||
var Oled = function (rg, opts) {
|
||||
|
||||
this.HEIGHT = opts.height || 32;
|
||||
this.WIDTH = opts.width || 128;
|
||||
this.ADDRESS = opts.address || 0x3C;
|
||||
this.BUS = opts.bus || 1;
|
||||
this.PROTOCOL = 'I2C';
|
||||
this.LINESPACING = typeof opts.linespacing !== 'undefined' ? opts.linespacing : 1;
|
||||
this.LETTERSPACING = typeof opts.letterspacing !== 'undefined' ? opts.letterspacing : 1;
|
||||
|
||||
|
||||
// create command buffers
|
||||
this.DISPLAY_OFF = 0xAE;
|
||||
this.DISPLAY_ON = 0xAF;
|
||||
this.SET_DISPLAY_CLOCK_DIV = 0xD5;
|
||||
this.SET_MULTIPLEX = 0xA8;
|
||||
this.SET_DISPLAY_OFFSET = 0xD3;
|
||||
this.SET_START_LINE = 0x00;
|
||||
this.CHARGE_PUMP = 0x8D;
|
||||
this.EXTERNAL_VCC = false;
|
||||
this.MEMORY_MODE = 0x20;
|
||||
this.SEG_REMAP = 0xA1; // using 0xA0 will flip screen
|
||||
this.COM_SCAN_DEC = 0xC8;
|
||||
this.COM_SCAN_INC = 0xC0;
|
||||
this.SET_COM_PINS = 0xDA;
|
||||
this.SET_CONTRAST = 0x81;
|
||||
this.SET_PRECHARGE = 0xd9;
|
||||
this.SET_VCOM_DETECT = 0xDB;
|
||||
this.DISPLAY_ALL_ON_RESUME = 0xA4;
|
||||
this.NORMAL_DISPLAY = 0xA6;
|
||||
this.COLUMN_ADDR = 0x21;
|
||||
this.PAGE_ADDR = 0x22;
|
||||
this.INVERT_DISPLAY = 0xA7;
|
||||
this.ACTIVATE_SCROLL = 0x2F;
|
||||
this.DEACTIVATE_SCROLL = 0x2E;
|
||||
this.SET_VERTICAL_SCROLL_AREA = 0xA3;
|
||||
this.RIGHT_HORIZONTAL_SCROLL = 0x26;
|
||||
this.LEFT_HORIZONTAL_SCROLL = 0x27;
|
||||
this.VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29;
|
||||
this.VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A;
|
||||
|
||||
this.cursor_x = 0;
|
||||
this.cursor_y = 0;
|
||||
|
||||
// new blank buffer
|
||||
this.buffer = Buffer.alloc((this.WIDTH * this.HEIGHT) / 8);
|
||||
this.buffer.fill(0x00);
|
||||
|
||||
this.dirtyBytes = [];
|
||||
|
||||
var config = {
|
||||
'128x32': {
|
||||
'multiplex': 0x1F,
|
||||
'compins': 0x02,
|
||||
'coloffset': 0
|
||||
},
|
||||
'128x64': {
|
||||
'multiplex': 0x3F,
|
||||
'compins': 0x12,
|
||||
'coloffset': 0
|
||||
},
|
||||
'96x16': {
|
||||
'multiplex': 0x0F,
|
||||
'compins': 0x2,
|
||||
'coloffset': 0,
|
||||
}
|
||||
};
|
||||
|
||||
// Setup i2c
|
||||
this.rg = rg;
|
||||
this.rg.rgpio_sbc_sync();
|
||||
this.i2c_hand = this.rg.i2c_open_sync(this.BUS, this.ADDRESS);
|
||||
// console.log(`this.i2c_hand = ${this.i2c_hand}`);
|
||||
|
||||
var screenSize = this.WIDTH + 'x' + this.HEIGHT;
|
||||
this.screenConfig = config[screenSize];
|
||||
|
||||
this._initialise();
|
||||
}
|
||||
|
||||
Oled.prototype._initialise = function () {
|
||||
|
||||
// sequence of bytes to initialise with
|
||||
var initSeq = [
|
||||
this.DISPLAY_OFF,
|
||||
this.SET_DISPLAY_CLOCK_DIV, 0x80,
|
||||
this.SET_MULTIPLEX, this.screenConfig.multiplex, // set the last value dynamically based on screen size requirement
|
||||
this.SET_DISPLAY_OFFSET, 0x00, // sets offset pro to 0
|
||||
this.SET_START_LINE,
|
||||
this.CHARGE_PUMP, 0x14, // charge pump val
|
||||
this.MEMORY_MODE, 0x00, // 0x0 act like ks0108
|
||||
this.SEG_REMAP, // screen orientation
|
||||
this.COM_SCAN_DEC, // screen orientation change to INC to flip
|
||||
this.SET_COM_PINS, this.screenConfig.compins, // com pins val sets dynamically to match each screen size requirement
|
||||
this.SET_CONTRAST, 0x8F, // contrast val
|
||||
this.SET_PRECHARGE, 0xF1, // precharge val
|
||||
this.SET_VCOM_DETECT, 0x40, // vcom detect
|
||||
this.DISPLAY_ALL_ON_RESUME,
|
||||
this.NORMAL_DISPLAY,
|
||||
this.DISPLAY_ON
|
||||
];
|
||||
|
||||
var i, initSeqLen = initSeq.length;
|
||||
|
||||
// write init seq commands
|
||||
for (i = 0; i < initSeqLen; i++) {
|
||||
this._transfer('cmd', initSeq[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// writes both commands and data buffers to this device
|
||||
Oled.prototype._transfer = function (type, val, fn) {
|
||||
var control;
|
||||
if (type === 'data') {
|
||||
control = 0x40;
|
||||
} else if (type === 'cmd') {
|
||||
control = 0x00;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
var bufferForSend;
|
||||
bufferForSend = Buffer.from([control, val])
|
||||
|
||||
// send control and actual val
|
||||
this.rg.i2c_write_device_sync(this.i2c_hand, bufferForSend, 2);
|
||||
if (fn) {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
// read a byte from the oled
|
||||
Oled.prototype._readI2C = function (fn) {
|
||||
var data = this.rg.i2c_read_byte_sync(this.i2c_hand);
|
||||
fn(data);
|
||||
}
|
||||
|
||||
// sometimes the oled gets a bit busy with lots of bytes.
|
||||
// Read the response byte to see if this is the case
|
||||
Oled.prototype._waitUntilReady = function (callback) {
|
||||
var done,
|
||||
oled = this;
|
||||
|
||||
function tick(callback) {
|
||||
oled._readI2C(function (byte) {
|
||||
// read the busy byte in the response
|
||||
busy = byte >> 7 & 1;
|
||||
if (!busy) {
|
||||
// if not busy, it's ready for callback
|
||||
callback();
|
||||
} else {
|
||||
setTimeout(function () { tick(callback) }, 0);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setTimeout(function () { tick(callback) }, 0);
|
||||
}
|
||||
|
||||
// set starting position of a text string on the oled
|
||||
Oled.prototype.setCursor = function (x, y) {
|
||||
this.cursor_x = x;
|
||||
this.cursor_y = y;
|
||||
}
|
||||
|
||||
// write text to the oled
|
||||
Oled.prototype.writeString = function (font, size, string, color, wrap, sync) {
|
||||
var immed = (typeof sync === 'undefined') ? true : sync;
|
||||
var wordArr = string.split(' '),
|
||||
len = wordArr.length,
|
||||
// start x offset at cursor pos
|
||||
offset = this.cursor_x,
|
||||
padding = 0;
|
||||
|
||||
// loop through words
|
||||
for (var w = 0; w < len; w += 1) {
|
||||
// put the word space back in for all in between words or empty words
|
||||
if (w < len - 1 || !wordArr[w].length) {
|
||||
wordArr[w] += ' ';
|
||||
}
|
||||
var stringArr = wordArr[w].split(''),
|
||||
slen = stringArr.length,
|
||||
compare = (font.width * size * slen) + (size * (len - 1));
|
||||
|
||||
// wrap words if necessary
|
||||
if (wrap && len > 1 && w > 0 && (offset >= (this.WIDTH - compare))) {
|
||||
offset = 0;
|
||||
|
||||
this.cursor_y += (font.height * size) + this.LINESPACING;
|
||||
this.setCursor(offset, this.cursor_y);
|
||||
}
|
||||
|
||||
// loop through the array of each char to draw
|
||||
for (var i = 0; i < slen; i += 1) {
|
||||
if (stringArr[i] === '\n') {
|
||||
offset = 0;
|
||||
this.cursor_y += (font.height * size) + this.LINESPACING;
|
||||
this.setCursor(offset, this.cursor_y);
|
||||
}
|
||||
else {
|
||||
// look up the position of the char, pull out the buffer slice
|
||||
var charBuf = this._findCharBuf(font, stringArr[i]);
|
||||
// read the bits in the bytes that make up the char
|
||||
var charBytes = this._readCharBytes(charBuf, font.height);
|
||||
// draw the entire character
|
||||
this._drawChar(charBytes, font.height, size, false);
|
||||
|
||||
// calc new x position for the next char, add a touch of padding too if it's a non space char
|
||||
//padding = (stringArr[i] === ' ') ? 0 : this.LETTERSPACING;
|
||||
offset += (font.width * size) + this.LETTERSPACING;// padding;
|
||||
|
||||
// wrap letters if necessary
|
||||
if (wrap && (offset >= (this.WIDTH - font.width - this.LETTERSPACING))) {
|
||||
offset = 0;
|
||||
this.cursor_y += (font.height * size) + this.LINESPACING;
|
||||
}
|
||||
// set the 'cursor' for the next char to be drawn, then loop again for next char
|
||||
this.setCursor(offset, this.cursor_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (immed) {
|
||||
this._updateDirtyBytes(this.dirtyBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// draw an individual character to the screen
|
||||
Oled.prototype._drawChar = function (byteArray, charHeight, size, sync) {
|
||||
// take your positions...
|
||||
var x = this.cursor_x,
|
||||
y = this.cursor_y;
|
||||
|
||||
// loop through the byte array containing the hexes for the char
|
||||
for (var i = 0; i < byteArray.length; i += 1) {
|
||||
for (var j = 0; j < charHeight; j += 1) {
|
||||
// pull color out
|
||||
var color = byteArray[i][j],
|
||||
xpos, ypos;
|
||||
// standard font size
|
||||
if (size === 1) {
|
||||
xpos = x + i;
|
||||
ypos = y + j;
|
||||
this.drawPixel([xpos, ypos, color], false);
|
||||
} else {
|
||||
// MATH! Calculating pixel size multiplier to primitively scale the font
|
||||
xpos = x + (i * size);
|
||||
ypos = y + (j * size);
|
||||
this.fillRect(xpos, ypos, size, size, color, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get character bytes from the supplied font object in order to send to framebuffer
|
||||
Oled.prototype._readCharBytes = function (byteArray, charHeight) {
|
||||
var bitArr = [],
|
||||
bitCharArr = [];
|
||||
// loop through each byte supplied for a char
|
||||
for (var i = 0; i < byteArray.length; i += 1) {
|
||||
// set current byte
|
||||
var byte = byteArray[i];
|
||||
// read each byte
|
||||
for (var j = 0; j < charHeight; j += 1) {
|
||||
// shift bits right until all are read
|
||||
var bit = byte >> j & 1;
|
||||
bitArr.push(bit);
|
||||
}
|
||||
// push to array containing flattened bit sequence
|
||||
bitCharArr.push(bitArr);
|
||||
// clear bits for next byte
|
||||
bitArr = [];
|
||||
}
|
||||
return bitCharArr;
|
||||
}
|
||||
|
||||
// find where the character exists within the font object
|
||||
Oled.prototype._findCharBuf = function (font, c) {
|
||||
// use the lookup array as a ref to find where the current char bytes start
|
||||
var cBufPos = font.lookup.indexOf(c) * font.width;
|
||||
// slice just the current char's bytes out of the fontData array and return
|
||||
var cBuf = font.fontData.slice(cBufPos, cBufPos + font.width);
|
||||
return cBuf;
|
||||
}
|
||||
|
||||
// send the entire framebuffer to the oled
|
||||
Oled.prototype.update = function () {
|
||||
// wait for oled to be ready
|
||||
this._waitUntilReady(function () {
|
||||
// set the start and endbyte locations for oled display update
|
||||
var displaySeq = [
|
||||
this.COLUMN_ADDR,
|
||||
this.screenConfig.coloffset,
|
||||
this.screenConfig.coloffset + this.WIDTH - 1, // column start and end address
|
||||
this.PAGE_ADDR, 0, (this.HEIGHT / 8) - 1 // page start and end address
|
||||
];
|
||||
|
||||
var displaySeqLen = displaySeq.length,
|
||||
bufferLen = this.buffer.length,
|
||||
i, v;
|
||||
|
||||
// send intro seq
|
||||
for (i = 0; i < displaySeqLen; i += 1) {
|
||||
this._transfer('cmd', displaySeq[i]);
|
||||
}
|
||||
|
||||
// write buffer data
|
||||
var bufferToSend = Buffer.concat([Buffer.from([0x40]), this.buffer]);
|
||||
this.rg.i2c_write_device_sync(this.i2c_hand, bufferToSend, bufferToSend.length);
|
||||
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// send dim display command to oled
|
||||
Oled.prototype.dimDisplay = function (bool) {
|
||||
var contrast;
|
||||
|
||||
if (bool) {
|
||||
contrast = 0; // Dimmed display
|
||||
} else {
|
||||
contrast = 0xCF; // Bright display
|
||||
}
|
||||
|
||||
this._transfer('cmd', this.SET_CONTRAST);
|
||||
this._transfer('cmd', contrast);
|
||||
}
|
||||
|
||||
// turn oled off
|
||||
Oled.prototype.turnOffDisplay = function () {
|
||||
this._transfer('cmd', this.DISPLAY_OFF);
|
||||
}
|
||||
|
||||
// turn oled on
|
||||
Oled.prototype.turnOnDisplay = function () {
|
||||
this._transfer('cmd', this.DISPLAY_ON);
|
||||
}
|
||||
|
||||
// clear all pixels currently on the display
|
||||
Oled.prototype.clearDisplay = function (sync) {
|
||||
var immed = (typeof sync === 'undefined') ? true : sync;
|
||||
// write off pixels
|
||||
this.buffer.fill(0x00);
|
||||
if (immed) {
|
||||
this.update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// invert pixels on oled
|
||||
Oled.prototype.invertDisplay = function (bool) {
|
||||
if (bool) {
|
||||
this._transfer('cmd', this.INVERT_DISPLAY); // inverted
|
||||
} else {
|
||||
this._transfer('cmd', this.NORMAL_DISPLAY); // non inverted
|
||||
}
|
||||
}
|
||||
|
||||
// draw an RGBA image at the specified coordinates
|
||||
Oled.prototype.drawRGBAImage = function (image, dx, dy, sync) {
|
||||
var immed = (typeof sync === 'undefined') ? true : sync;
|
||||
// translate image data to buffer
|
||||
var x, y, dataIndex, buffIndex, buffByte, bit, pixelByte;
|
||||
var dyp = this.WIDTH * Math.floor(dy / 8); // calc once
|
||||
var dxyp = dyp + dx;
|
||||
for (x = 0; x < image.width; x++) {
|
||||
var dxx = dx + x;
|
||||
if (dxx < 0 || dxx >= this.WIDTH) {
|
||||
// negative, off the screen
|
||||
continue;
|
||||
}
|
||||
// start buffer index for image column
|
||||
buffIndex = x + dxyp;
|
||||
buffByte = this.buffer[buffIndex];
|
||||
for (y = 0; y < image.height; y++) {
|
||||
var dyy = dy + y; // calc once
|
||||
if (dyy < 0 || dyy >= this.HEIGHT) {
|
||||
// negative, off the screen
|
||||
continue;
|
||||
}
|
||||
var dyyp = Math.floor(dyy / 8); // calc once
|
||||
|
||||
// check if start of buffer page
|
||||
if (!(dyy % 8)) {
|
||||
// check if we need to save previous byte
|
||||
if ((x || y) && buffByte !== this.buffer[buffIndex]) {
|
||||
// save current byte and get next buffer byte
|
||||
this.buffer[buffIndex] = buffByte;
|
||||
this.dirtyBytes.push(buffIndex);
|
||||
}
|
||||
// new buffer page
|
||||
buffIndex = dx + x + this.WIDTH * dyyp;
|
||||
buffByte = this.buffer[buffIndex];
|
||||
}
|
||||
|
||||
// process pixel into buffer byte
|
||||
dataIndex = (image.width * y + x) << 2; // 4 bytes per pixel (RGBA)
|
||||
if (!image.data[dataIndex + 3]) {
|
||||
// transparent, continue to next pixel
|
||||
continue;
|
||||
}
|
||||
|
||||
pixelByte = 0x01 << (dyy - 8 * dyyp);
|
||||
bit = image.data[dataIndex] || image.data[dataIndex + 1] || image.data[dataIndex + 2];
|
||||
if (bit) {
|
||||
buffByte |= pixelByte;
|
||||
}
|
||||
else {
|
||||
buffByte &= ~pixelByte;
|
||||
}
|
||||
}
|
||||
if ((x || y) && buffByte !== this.buffer[buffIndex]) {
|
||||
// save current byte
|
||||
this.buffer[buffIndex] = buffByte;
|
||||
this.dirtyBytes.push(buffIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (immed) {
|
||||
this._updateDirtyBytes(this.dirtyBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// draw an image pixel array on the screen
|
||||
Oled.prototype.drawBitmap = function (pixels, sync) {
|
||||
var immed = (typeof sync === 'undefined') ? true : sync;
|
||||
var x, y,
|
||||
pixelArray = [];
|
||||
|
||||
for (var i = 0; i < pixels.length; i++) {
|
||||
x = Math.floor(i % this.WIDTH);
|
||||
y = Math.floor(i / this.WIDTH);
|
||||
|
||||
this.drawPixel([x, y, pixels[i]], false);
|
||||
}
|
||||
|
||||
if (immed) {
|
||||
this._updateDirtyBytes(this.dirtyBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// draw one or many pixels on oled
|
||||
Oled.prototype.drawPixel = function (pixels, sync) {
|
||||
var immed = (typeof sync === 'undefined') ? true : sync;
|
||||
|
||||
// handle lazy single pixel case
|
||||
if (typeof pixels[0] !== 'object') pixels = [pixels];
|
||||
|
||||
pixels.forEach(function (el) {
|
||||
// return if the pixel is out of range
|
||||
var x = el[0], y = el[1], color = el[2];
|
||||
if (x >= this.WIDTH || y >= this.HEIGHT) return;
|
||||
|
||||
// thanks, Martin Richards.
|
||||
// I wanna can this, this tool is for devs who get 0 indexes
|
||||
//x -= 1; y -=1;
|
||||
var byte = 0,
|
||||
page = Math.floor(y / 8),
|
||||
pageShift = 0x01 << (y - 8 * page);
|
||||
|
||||
// is the pixel on the first row of the page?
|
||||
(page == 0) ? byte = x : byte = x + (this.WIDTH * page);
|
||||
|
||||
// colors! Well, monochrome.
|
||||
if (color === 'BLACK' || color === 0) {
|
||||
this.buffer[byte] &= ~pageShift;
|
||||
}
|
||||
if (color === 'WHITE' || color > 0) {
|
||||
this.buffer[byte] |= pageShift;
|
||||
}
|
||||
|
||||
// push byte to dirty if not already there
|
||||
if (this.dirtyBytes.indexOf(byte) === -1) {
|
||||
this.dirtyBytes.push(byte);
|
||||
}
|
||||
|
||||
}, this);
|
||||
|
||||
if (immed) {
|
||||
this._updateDirtyBytes(this.dirtyBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// looks at dirty bytes, and sends the updated bytes to the display
|
||||
Oled.prototype._updateDirtyBytes = function (byteArray) {
|
||||
var blen = byteArray.length, i,
|
||||
displaySeq = [];
|
||||
|
||||
// check to see if this will even save time
|
||||
if (blen > (this.buffer.length / 7)) {
|
||||
// just call regular update at this stage, saves on bytes sent
|
||||
this.update();
|
||||
// now that all bytes are synced, reset dirty state
|
||||
this.dirtyBytes = [];
|
||||
|
||||
} else {
|
||||
|
||||
this._waitUntilReady(function () {
|
||||
// iterate through dirty bytes
|
||||
for (var i = 0; i < blen; i += 1) {
|
||||
|
||||
var byte = byteArray[i];
|
||||
var page = Math.floor(byte / this.WIDTH);
|
||||
var col = Math.floor(byte % this.WIDTH);
|
||||
|
||||
var displaySeq = [
|
||||
this.COLUMN_ADDR, col, col, // column start and end address
|
||||
this.PAGE_ADDR, page, page // page start and end address
|
||||
];
|
||||
|
||||
var displaySeqLen = displaySeq.length, v;
|
||||
|
||||
// send intro seq
|
||||
for (v = 0; v < displaySeqLen; v += 1) {
|
||||
this._transfer('cmd', displaySeq[v]);
|
||||
}
|
||||
// send byte, then move on to next byte
|
||||
this._transfer('data', this.buffer[byte]);
|
||||
this.buffer[byte];
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
// now that all bytes are synced, reset dirty state
|
||||
this.dirtyBytes = [];
|
||||
}
|
||||
|
||||
// using Bresenham's line algorithm
|
||||
Oled.prototype.drawLine = function (x0, y0, x1, y1, color, sync) {
|
||||
var immed = (typeof sync === 'undefined') ? true : sync;
|
||||
|
||||
var dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1,
|
||||
dy = Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1,
|
||||
err = (dx > dy ? dx : -dy) / 2;
|
||||
|
||||
while (true) {
|
||||
this.drawPixel([x0, y0, color], false);
|
||||
|
||||
if (x0 === x1 && y0 === y1) break;
|
||||
|
||||
var e2 = err;
|
||||
|
||||
if (e2 > -dx) { err -= dy; x0 += sx; }
|
||||
if (e2 < dy) { err += dx; y0 += sy; }
|
||||
}
|
||||
|
||||
if (immed) {
|
||||
this._updateDirtyBytes(this.dirtyBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// draw a filled rectangle on the oled
|
||||
Oled.prototype.fillRect = function (x, y, w, h, color, sync) {
|
||||
var immed = (typeof sync === 'undefined') ? true : sync;
|
||||
// one iteration for each column of the rectangle
|
||||
for (var i = x; i < x + w; i += 1) {
|
||||
// draws a vert line
|
||||
this.drawLine(i, y, i, y + h - 1, color, false);
|
||||
}
|
||||
if (immed) {
|
||||
this._updateDirtyBytes(this.dirtyBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// activate scrolling for rows start through stop
|
||||
Oled.prototype.startScroll = function (dir, start, stop) {
|
||||
var scrollHeader,
|
||||
cmdSeq = [];
|
||||
|
||||
switch (dir) {
|
||||
case 'right':
|
||||
cmdSeq.push(this.RIGHT_HORIZONTAL_SCROLL); break;
|
||||
case 'left':
|
||||
cmdSeq.push(this.LEFT_HORIZONTAL_SCROLL); break;
|
||||
// TODO: left diag and right diag not working yet
|
||||
case 'left diagonal':
|
||||
cmdSeq.push(
|
||||
this.SET_VERTICAL_SCROLL_AREA, 0x00,
|
||||
this.VERTICAL_AND_LEFT_HORIZONTAL_SCROLL,
|
||||
this.HEIGHT
|
||||
);
|
||||
break;
|
||||
// TODO: left diag and right diag not working yet
|
||||
case 'right diagonal':
|
||||
cmdSeq.push(
|
||||
this.SET_VERTICAL_SCROLL_AREA, 0x00,
|
||||
this.VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL,
|
||||
this.HEIGHT
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
this._waitUntilReady(function () {
|
||||
cmdSeq.push(
|
||||
0x00, start,
|
||||
0x00, stop,
|
||||
// TODO: these need to change when diagonal
|
||||
0x00, 0xFF,
|
||||
this.ACTIVATE_SCROLL
|
||||
);
|
||||
|
||||
var i, cmdSeqLen = cmdSeq.length;
|
||||
|
||||
for (i = 0; i < cmdSeqLen; i += 1) {
|
||||
this._transfer('cmd', cmdSeq[i]);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// stop scrolling display contents
|
||||
Oled.prototype.stopScroll = function () {
|
||||
this._transfer('cmd', this.DEACTIVATE_SCROLL); // stahp
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a circle outline - ported from https://www.npmjs.com/package/oled-ssd1306-i2c/v/1.0.6?activeTab=readme
|
||||
* This method is ad verbatim translation from the corresponding
|
||||
* method on the Adafruit GFX library
|
||||
* https://github.com/adafruit/Adafruit-GFX-Library
|
||||
*/
|
||||
Oled.prototype.drawCircle = function (x0, y0, r, color, sync) {
|
||||
var immed = (typeof sync === 'undefined') ? true : sync;
|
||||
|
||||
var f = 1 - r;
|
||||
var ddF_x = 1;
|
||||
var ddF_y = -2 * r;
|
||||
var x = 0;
|
||||
var y = r;
|
||||
|
||||
this.drawPixel(
|
||||
[[x0, y0 + r, color],
|
||||
[x0, y0 - r, color],
|
||||
[x0 + r, y0, color],
|
||||
[x0 - r, y0, color]],
|
||||
false
|
||||
);
|
||||
|
||||
while (x < y) {
|
||||
if (f >= 0) {
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
this.drawPixel(
|
||||
[[x0 + x, y0 + y, color],
|
||||
[x0 - x, y0 + y, color],
|
||||
[x0 + x, y0 - y, color],
|
||||
[x0 - x, y0 - y, color],
|
||||
[x0 + y, y0 + x, color],
|
||||
[x0 - y, y0 + x, color],
|
||||
[x0 + y, y0 - x, color],
|
||||
[x0 - y, y0 - x, color]],
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (immed) {
|
||||
this._updateDirtyBytes(this.dirtyBytes);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
module.exports = Oled;
|
||||
|
||||
/*
|
||||
* This code was forked from baltazor's oled-i2c-bus: https://www.npmjs.com/package/oled-i2c-bus
|
||||
*/
|
7
local_modules/ssd1306/package.json
Normal file
7
local_modules/ssd1306/package.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@ocoge/ssd1306",
|
||||
"version": "1.0.0",
|
||||
"main": "oled.js",
|
||||
"private": true,
|
||||
"license": "MIT"
|
||||
}
|
17
main.js
17
main.js
@ -297,3 +297,20 @@ ipcMain.handle('save_dialog', (ev, title, defName, filter) => {
|
||||
ipcMain.handle('get_app_path', (ev) => {
|
||||
return app.getAppPath()
|
||||
})
|
||||
|
||||
// Draw text on node-canvas : Returns PNG buffer data
|
||||
const { createCanvas, registerFont } = require('canvas')
|
||||
const PNG = require('pngjs').PNG
|
||||
registerFont(path.join(__dirname, 'fonts', 'PixelMplus12-Regular.ttf'), { family: '' })
|
||||
registerFont(path.join(__dirname, 'fonts', 'PixelMplus10-Regular.ttf'), { family: '' })
|
||||
registerFont(path.join(__dirname, 'fonts', 'misaki_gothic.ttf'), { family: '' })
|
||||
ipcMain.handle('text_to_rgba', (ev, text, font, color, start_x, start_y) => {
|
||||
const canvas = createCanvas(128, 64)
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx.antialias = 'none'
|
||||
ctx.font = font
|
||||
ctx.fillStyle = color;
|
||||
ctx.textBaseline = "top";
|
||||
ctx.fillText(text, start_x, start_y);
|
||||
return PNG.sync.read(canvas.toBuffer());
|
||||
})
|
||||
|
285
oled-i2c-rgpio/README.md
Normal file
285
oled-i2c-rgpio/README.md
Normal file
@ -0,0 +1,285 @@
|
||||
![‘npm version’](http://img.shields.io/npm/v/oled-js.svg?style=flat) ![‘downloads over month’](http://img.shields.io/npm/dm/oled-js.svg?style=flat)
|
||||
|
||||
OLED JS Pi over i2c-bus
|
||||
========================
|
||||
|
||||
## What is this?
|
||||
|
||||
This is fork of package [`oled-js-pi`](https://github.com/kd7yva/oled-js-pi) that works thru `i2c-bus` package and not use package `i2c`.
|
||||
|
||||
A NodeJS driver for I2C/SPI compatible monochrome OLED screens; to be used on the Raspberry Pi! Works with 128 x 32, 128 x 64 and 96 x 16 sized screens, of the SSD1306 OLED/PLED Controller (read the [datasheet here](http://www.adafruit.com/datasheets/SSD1306.pdf)).
|
||||
|
||||
This based on the Blog Post and code by Suz Hinton - [Read her blog post about how OLED screens work](http://meow.noopkat.com/oled-js/)!
|
||||
|
||||
OLED screens are really cool - now you can control them with JavaScript!
|
||||
|
||||
## Install
|
||||
|
||||
If you haven't already, install [NodeJS](http://nodejs.org/).
|
||||
|
||||
`npm install oled-i2c-bus`
|
||||
|
||||
## I2C screens
|
||||
Hook up I2C compatible oled to the Raspberry Pi. Pins: SDL and SCL
|
||||
|
||||
### I2C example
|
||||
|
||||
```javascript
|
||||
var i2c = require('i2c-bus'),
|
||||
i2cBus = i2c.openSync(1),
|
||||
oled = require('oled-i2c-bus');
|
||||
|
||||
var opts = {
|
||||
width: 128,
|
||||
height: 64,
|
||||
address: 0x3D
|
||||
};
|
||||
|
||||
var oled = new oled(i2cBus, opts);
|
||||
|
||||
// do cool oled things here
|
||||
|
||||
```
|
||||
|
||||
### Wait, how do I find out the I2C address of my OLED screen?
|
||||
Check your screen's documentation...
|
||||
|
||||
## Available methods
|
||||
|
||||
### clearDisplay
|
||||
Fills the buffer with 'off' pixels (0x00). Optional bool argument specifies whether screen updates immediately with result. Default is true.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
oled.clearDisplay();
|
||||
```
|
||||
|
||||
### dimDisplay
|
||||
Lowers the contrast on the display. This method takes one argument, a boolean. True for dimming, false to restore normal contrast.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
oled.dimDisplay(true|false);
|
||||
```
|
||||
|
||||
### invertDisplay
|
||||
Inverts the pixels on the display. Black becomes white, white becomes black. This method takes one argument, a boolean. True for inverted state, false to restore normal pixel colors.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
oled.invertDisplay(true|false);
|
||||
```
|
||||
|
||||
### turnOffDisplay
|
||||
Turns the display off.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
oled.turnOffDisplay();
|
||||
```
|
||||
|
||||
### turnOnDisplay
|
||||
Turns the display on.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
oled.turnOnDisplay();
|
||||
```
|
||||
|
||||
|
||||
### drawPixel
|
||||
Draws a pixel at a specified position on the display. This method takes one argument: a multi-dimensional array containing either one or more sets of pixels.
|
||||
|
||||
Each pixel needs an x position, a y position, and a color. Colors can be specified as either 0 for 'off' or black, and 1 or 255 for 'on' or white.
|
||||
|
||||
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
// draws 4 white pixels total
|
||||
// format: [x, y, color]
|
||||
oled.drawPixel([
|
||||
[128, 1, 1],
|
||||
[128, 32, 1],
|
||||
[128, 16, 1],
|
||||
[64, 16, 1]
|
||||
]);
|
||||
```
|
||||
|
||||
### drawLine
|
||||
Draws a one pixel wide line.
|
||||
|
||||
Arguments:
|
||||
+ int **x0, y0** - start location of line
|
||||
+ int **x1, y1** - end location of line
|
||||
+ int **color** - can be specified as either 0 for 'off' or black, and 1 or 255 for 'on' or white.
|
||||
|
||||
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
// args: (x0, y0, x1, y1, color)
|
||||
oled.drawLine(1, 1, 128, 32, 1);
|
||||
```
|
||||
|
||||
### fillRect
|
||||
Draws a filled rectangle.
|
||||
|
||||
Arguments:
|
||||
+ int **x0, y0** - top left corner of rectangle
|
||||
+ int **w, h** - width and height of rectangle
|
||||
+ int **color** - can be specified as either 0 for 'off' or black, and 1 or 255 for 'on' or white.
|
||||
|
||||
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
// args: (x0, y0, x1, y1, color)
|
||||
oled.fillRect(1, 1, 10, 20, 1);
|
||||
```
|
||||
|
||||
### drawBitmap
|
||||
Draws a bitmap using raw pixel data returned from an image parser. The image sourced must be monochrome, and indexed to only 2 colors. Resize the bitmap to your screen dimensions first. Using an image editor or ImageMagick might be required.
|
||||
|
||||
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
|
||||
|
||||
Tip: use a NodeJS image parser to get the pixel data, such as [pngparse](https://www.npmjs.org/package/pngparse). A demonstration of using this is below.
|
||||
|
||||
|
||||
Example usage:
|
||||
```
|
||||
npm install pngparse
|
||||
```
|
||||
|
||||
```javascript
|
||||
var pngparse = require('pngparse');
|
||||
|
||||
pngparse.parseFile('indexed_file.png', function(err, image) {
|
||||
oled.drawBitmap(image.data);
|
||||
});
|
||||
```
|
||||
|
||||
This method is provided as a primitive convenience. A better way to display images is to use NodeJS package [png-to-lcd](https://www.npmjs.org/package/png-to-lcd) instead. It's just as easy to use as drawBitmap, but is compatible with all image depths (lazy is good!). It will also auto-dither if you choose. You should still resize your image to your screen dimensions. This alternative method is covered below:
|
||||
|
||||
```
|
||||
npm install png-to-lcd
|
||||
```
|
||||
|
||||
```javascript
|
||||
var pngtolcd = require('png-to-lcd');
|
||||
|
||||
pngtolcd('nyan-cat.png', true, function(err, bitmap) {
|
||||
oled.buffer = bitmap;
|
||||
oled.update();
|
||||
});
|
||||
```
|
||||
|
||||
### drawRGBAImage
|
||||
Draw an RGBA coded image at specific coordinates. This only supports a monochrome
|
||||
OLED so transparent pixels must be 100% transparent, off pixels should have an
|
||||
RGB value of (0, 0, 0), and pixels with any color value will be considered on.
|
||||
|
||||
Use a library such as [pngjs](https://www.npmjs.com/package/pngjs) to read a png
|
||||
file into the required rgba data structure.
|
||||
|
||||
Example:
|
||||
```JavaScript
|
||||
const fs = require('fs');
|
||||
const PNG = require('pngjs').PNG;
|
||||
const i2c = require('i2c-bus');
|
||||
const oled = require('oled-i2c-bus');
|
||||
|
||||
var i2cBus = i2c.openSync(0);
|
||||
|
||||
var opts = {
|
||||
width: 128,
|
||||
height: 64,
|
||||
address: 0x3C
|
||||
};
|
||||
|
||||
var display = new oled(i2cBus, opts);
|
||||
|
||||
display.clearDisplay();
|
||||
display.turnOnDisplay();
|
||||
|
||||
fs.createReadStream('./test.png')
|
||||
.pipe(new PNG({ filterType: 4 }))
|
||||
.on('parsed', function () {
|
||||
setInterval(() => { drawImage(this) }, 1000);
|
||||
});
|
||||
|
||||
function drawImage(image) {
|
||||
let x = Math.floor(Math.random() * (display.WIDTH) - image.width / 2);
|
||||
let y = Math.floor(Math.random() * (display.HEIGHT) - image.height / 2);
|
||||
display.drawRGBAImage(image, x, y);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### startScroll
|
||||
Scrolls the current display either left or right.
|
||||
Arguments:
|
||||
+ string **direction** - direction of scrolling. 'left' or 'right'
|
||||
+ int **start** - starting row of scrolling area
|
||||
+ int **stop** - end row of scrolling area
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
// args: (direction, start, stop)
|
||||
oled.startscroll('left', 0, 15); // this will scroll an entire 128 x 32 screen
|
||||
```
|
||||
|
||||
### stopScroll
|
||||
Stops all current scrolling behaviour.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
oled.stopscroll();
|
||||
```
|
||||
|
||||
### setCursor
|
||||
Sets the x and y position of 'cursor', when about to write text. This effectively helps tell the display where to start typing when writeString() method is called.
|
||||
|
||||
Call setCursor just before writeString().
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
// sets cursor to x = 1, y = 1
|
||||
oled.setCursor(1, 1);
|
||||
```
|
||||
|
||||
### writeString
|
||||
Writes a string of text to the display.
|
||||
Call setCursor() just before, if you need to set starting text position.
|
||||
|
||||
Arguments:
|
||||
+ obj **font** - font object in JSON format (see note below on sourcing a font)
|
||||
+ int **size** - font size, as multiplier. Eg. 2 would double size, 3 would triple etc.
|
||||
+ string **text** - the actual text you want to show on the display.
|
||||
+ int **color** - color of text. Can be specified as either 0 for 'off' or black, and 1 or 255 for 'on' or white.
|
||||
+ bool **wrapping** - true applies word wrapping at the screen limit, false for no wrapping. If a long string without spaces is supplied as the text, just letter wrapping will apply instead.
|
||||
|
||||
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
|
||||
|
||||
Before all of this text can happen, you need to load a font buffer for use. A good font to start with is NodeJS package [oled-font-5x7](https://www.npmjs.org/package/oled-font-5x7).
|
||||
|
||||
Usage:
|
||||
```
|
||||
npm install oled-font-5x7
|
||||
```
|
||||
|
||||
```javascript
|
||||
var font = require('oled-font-5x7');
|
||||
|
||||
// sets cursor to x = 1, y = 1
|
||||
oled.setCursor(1, 1);
|
||||
oled.writeString(font, 1, 'Cats and dogs are really cool animals, you know.', 1, true);
|
||||
```
|
||||
|
||||
### update
|
||||
Sends the entire buffer in its current state to the oled display, effectively syncing the two. This method generally does not need to be called, unless you're messing around with the framebuffer manually before you're ready to sync with the display. It's also needed if you're choosing not to draw on the screen immediately with the built in methods.
|
||||
|
||||
Usage:
|
||||
```javascript
|
||||
oled.update();
|
||||
```
|
15
oled-i2c-rgpio/examples/README.md
Normal file
15
oled-i2c-rgpio/examples/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
OLED JS Pi over i2c-bus
|
||||
========================
|
||||
|
||||
## What is this directory?
|
||||
|
||||
This directory contains a working example of NodeJS, a (typically) ARM board (Orange Pi Zero), and a 128x64 I2C SSD1306 display.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install
|
||||
cp ../oled.js node_modules/oled-i2c-bus/
|
||||
node clock.js
|
||||
```
|
25
oled-i2c-rgpio/examples/package.json
Normal file
25
oled-i2c-rgpio/examples/package.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "examples",
|
||||
"version": "1.0.0",
|
||||
"description": "Testing OLED SSD1306 display with nodeJS",
|
||||
"main": "clock.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/haraldkubota/oled-i2c-bus"
|
||||
},
|
||||
"keywords": [
|
||||
"oled",
|
||||
"i2c"
|
||||
],
|
||||
"author": "Harald Kubota",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"i2c-bus": "^1.1.2",
|
||||
"oled-font-5x7": "^1.0.0",
|
||||
"oled-i2c-bus": "^1.0.11",
|
||||
"pngjs": "^3.3.3"
|
||||
}
|
||||
}
|
39
oled-i2c-rgpio/examples/rgba.js
Normal file
39
oled-i2c-rgpio/examples/rgba.js
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* rgba.js
|
||||
* Display an RGBA image at random locations on a small I2C connected display
|
||||
*
|
||||
* 2018-08-19 v1.0 Bryan Nielsen
|
||||
*/
|
||||
|
||||
|
||||
"use strict";
|
||||
|
||||
const fs = require('fs');
|
||||
const PNG = require('pngjs').PNG;
|
||||
const i2c = require('i2c-bus');
|
||||
const oled = require('../oled');// 'oled-i2c-bus');
|
||||
|
||||
var i2cBus = i2c.openSync(0);
|
||||
|
||||
var opts = {
|
||||
width: 128,
|
||||
height: 64,
|
||||
address: 0x3C
|
||||
};
|
||||
|
||||
var display = new oled(i2cBus, opts);
|
||||
|
||||
display.clearDisplay();
|
||||
display.turnOnDisplay();
|
||||
|
||||
fs.createReadStream('./test.png')
|
||||
.pipe(new PNG({ filterType: 4 }))
|
||||
.on('parsed', function () {
|
||||
setInterval(() => { drawImage(this) }, 1000);
|
||||
});
|
||||
|
||||
function drawImage(image) {
|
||||
let x = Math.floor(Math.random() * (display.WIDTH) - image.width / 2);
|
||||
let y = Math.floor(Math.random() * (display.HEIGHT) - image.height / 2);
|
||||
display.drawRGBAImage(image, x, y);
|
||||
}
|
BIN
oled-i2c-rgpio/examples/test.png
Normal file
BIN
oled-i2c-rgpio/examples/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 648 B |
108
oled-i2c-rgpio/package-lock.json
generated
Normal file
108
oled-i2c-rgpio/package-lock.json
generated
Normal file
@ -0,0 +1,108 @@
|
||||
{
|
||||
"name": "oled-i2c-bus",
|
||||
"version": "1.0.12",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "oled-i2c-bus",
|
||||
"version": "1.0.12",
|
||||
"dependencies": {
|
||||
"rgpio": "file:local_modules/rgpio"
|
||||
},
|
||||
"devDependencies": {
|
||||
"oled-font-5x7": "~1.0.0",
|
||||
"png-to-lcd": "~1.0.2",
|
||||
"pngjs": "^3.3.3",
|
||||
"pngparse": "~2.0.1",
|
||||
"temporal": "^0.3.8"
|
||||
}
|
||||
},
|
||||
"local_modules/rgpio": {
|
||||
"version": "0.0.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
"node-addon-api": "^1.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dependencies": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-shim": {
|
||||
"version": "0.35.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.8.tgz",
|
||||
"integrity": "sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"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=="
|
||||
},
|
||||
"node_modules/floyd-steinberg": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/floyd-steinberg/-/floyd-steinberg-1.0.6.tgz",
|
||||
"integrity": "sha512-gzlre+taSQzEY+nCusbHJFQ3zHXBkRAX4fe3szssPY/N/t1ClBX9hnHZM4o8ZvpdqLLUPEavuZ/Noj71ZaA8+A==",
|
||||
"dev": true
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"node_modules/oled-font-5x7": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/oled-font-5x7/-/oled-font-5x7-1.0.3.tgz",
|
||||
"integrity": "sha512-l25WvKft8CgXYxtaqKdYrAS1P91rnUUUIiOXojAOvjNCsfFzIl1aEsE2JuaRgMh1Euo7slm5lX0w+1qNkL8PpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/png-to-lcd": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/png-to-lcd/-/png-to-lcd-1.0.3.tgz",
|
||||
"integrity": "sha512-y4X4mRvZUoMv1ruQimuXixC72HfPyPZHCxlSiQkwVjBAdYlQSnkp1N3EZkgVoS+CngJdTGGW9nMw9VBkfSH39Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"floyd-steinberg": "~1.0.4",
|
||||
"pngparse": "~2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
|
||||
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pngparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pngparse/-/pngparse-2.0.1.tgz",
|
||||
"integrity": "sha512-RyB1P0BBwt3CNIZ5wT53lR1dT3CUtopnMOuP8xZdHjPhI/uXNNRnkx1yQb/3MMMyyMeo6p19fiIRHcLopWIkxA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/rgpio": {
|
||||
"resolved": "local_modules/rgpio",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/temporal": {
|
||||
"version": "0.3.8",
|
||||
"resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz",
|
||||
"integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es6-shim": "latest"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
oled-i2c-rgpio/package.json
Normal file
19
oled-i2c-rgpio/package.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "oled-i2c-bus",
|
||||
"version": "1.0.12",
|
||||
"description": "NodeJS module for controlling oled devices on the Raspbery Pi (including the SSD1306 OLED screens)",
|
||||
"main": "oled.js",
|
||||
"devDependencies": {
|
||||
"oled-font-5x7": "~1.0.0",
|
||||
"png-to-lcd": "~1.0.2",
|
||||
"pngjs": "^3.3.3",
|
||||
"pngparse": "~2.0.1",
|
||||
"temporal": "^0.3.8"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"rgpio": "file:local_modules/rgpio"
|
||||
}
|
||||
}
|
23
oled_circle.js
Normal file
23
oled_circle.js
Normal file
@ -0,0 +1,23 @@
|
||||
const main = async () => {
|
||||
var oled;
|
||||
|
||||
const _rg = require('rgpio');
|
||||
|
||||
const _oled = require('/home/ichij/ocogeclub/ocoge/blocks/sensors/ssd1306/oled.js');
|
||||
|
||||
|
||||
await _rg.rgpio_sbc();
|
||||
var _opts = {
|
||||
width: 128,
|
||||
height: 64,
|
||||
address: 0x3c,
|
||||
bus: 5
|
||||
};
|
||||
oled = new _oled(_rg, _opts);
|
||||
oled.clearDisplay();
|
||||
oled.turnOnDisplay();
|
||||
|
||||
oled.drawCircle(63, 31, 8, 1)
|
||||
|
||||
}
|
||||
main();
|
1615
package-lock.json
generated
1615
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
37
package.json
37
package.json
@ -22,28 +22,37 @@
|
||||
},
|
||||
"homepage": "https://git.ocoge.club/ocoge.club/ocoge#readme",
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "^6.2.1",
|
||||
"@electron-forge/maker-deb": "^6.2.1",
|
||||
"@electron-forge/cli": "^6.3.0",
|
||||
"@electron-forge/maker-deb": "^6.3.0",
|
||||
"@electron/rebuild": "^3.2.13",
|
||||
"electron": "^25.2.0"
|
||||
"electron": "^26.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blockly/field-slider": "^4.0.18",
|
||||
"@tensorflow-models/blazeface": "^0.0.7",
|
||||
"@tensorflow-models/knn-classifier": "^1.2.4",
|
||||
"@tensorflow-models/mobilenet": "^2.1.0",
|
||||
"@blockly/field-slider": "^6.0.3",
|
||||
"@napi-rs/canvas": "^0.1.43",
|
||||
"@ocoge/amg8833": "file:local_modules/amg8833",
|
||||
"@ocoge/bme280": "file:local_modules/bme280",
|
||||
"@ocoge/paj7620": "file:local_modules/paj7620",
|
||||
"@ocoge/ssd1306": "file:local_modules/ssd1306",
|
||||
"@tensorflow-models/blazeface": "^0.1.0",
|
||||
"@tensorflow-models/knn-classifier": "^1.2.5",
|
||||
"@tensorflow-models/mobilenet": "^2.1.1",
|
||||
"@tensorflow-models/speech-commands": "^0.5.4",
|
||||
"@tensorflow/tfjs-node": "^4.8.0",
|
||||
"@tensorflow/tfjs-node": "^4.10.0",
|
||||
"amg8833": "file:local_modules/amg8833",
|
||||
"axios": "^1.4.0",
|
||||
"blockly": "^9.3.3",
|
||||
"blockly": "^10.1.2",
|
||||
"canvas": "^2.11.2",
|
||||
"dracula-prism": "^2.1.13",
|
||||
"js-beautify": "^1.14.8",
|
||||
"node-abi": "^3.45.0",
|
||||
"nodemailer": "^6.9.3",
|
||||
"js-beautify": "^1.14.9",
|
||||
"node-abi": "^3.47.0",
|
||||
"nodemailer": "^6.9.4",
|
||||
"oled-font-pack": "^1.0.1",
|
||||
"pngjs": "^7.0.0",
|
||||
"prismjs": "^1.29.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"rgpio": "file:local_modules/rgpio"
|
||||
"@ocoge/rgpio": "file:local_modules/rgpio"
|
||||
},
|
||||
"config": {
|
||||
"forge": {
|
||||
@ -64,4 +73,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user