obniz
Version:
obniz sdk for javascript
313 lines (280 loc) • 7.52 kB
JavaScript
class SharpMemoryTFT {
constructor() {
this.keys = [
'vcc',
'gnd',
'vcc_a',
'gnd_a',
'sclk',
'mosi',
'cs',
'disp',
'extcomin',
'extmode',
'width',
'height',
];
this.requiredKeys = ['sclk', 'mosi', 'cs', 'width', 'height'];
this.commands = {};
this.commands.write = 0x80;
this.commands.clear = 0x20;
this.commands.vcom = 0x40;
this._canvas = null;
this._reset();
}
static info() {
return {
name: 'SharpMemoryTFT',
};
}
wired(obniz) {
this.obniz = obniz;
this.io_cs = obniz.getIO(this.params.cs);
if (this.params.disp && this.params.extcomin && this.params.extmode) {
this.io_disp = obniz.getIO(this.params.disp);
this.io_extcomin = obniz.getIO(this.params.extcomin);
this.io_extmode = obniz.getIO(this.params.extmode);
this.io_disp.output(true);
this.io_extcomin.output(false);
this.io_extmode.output(false);
}
obniz.setVccGnd(this.params.vcc, this.params.gnd, '5v');
obniz.setVccGnd(this.params.vcc_a, this.params.gnd_a, '5v');
this.params.mode = 'master';
this.params.frequency = parseInt(1000 * 1000);
this.params.clk = this.params.sclk;
this.params.drive = '5v'; // It over spec for frequency. But VIN-HI require 0.7VCC<=.
this.spi = this.obniz.getSpiWithConfig(this.params);
this.width = this.params.width;
this.height = this.params.height;
this.obniz.wait(100);
}
_reverseBits(data) {
let revData = 0;
for (let i = 0; i < 8; i++) {
revData += data & 0x01;
data >>= 1;
if (i < 7) revData <<= 1;
}
return revData;
}
sendLSB(data) {
this.spi.write([this._reverseBits(data)]);
}
sendClear() {
this.io_cs.output(true);
this.spi.write([this.commands.clear | 0x00, 0x00]);
this.io_cs.output(false);
}
raw(rawData) {
let oldline, currentline;
let totalbytes = (this.width * this.height) / 8;
let array = new Array(1024);
let index = 0;
array[index++] = this.commands.write | this.commands.vcom;
oldline = currentline = 1;
array[index++] = this._reverseBits(currentline);
this.io_cs.output(true);
for (let i = 0; i < totalbytes; i++) {
array[index++] = rawData[i]; //lsb
currentline = parseInt((i + 1) / (this.width / 8) + 1, 10);
if (currentline != oldline) {
array[index++] = 0x00;
if (currentline <= this.height)
array[index++] = this._reverseBits(currentline);
oldline = currentline;
}
if (index >= 1021) {
// regarding SPI max.
this.spi.write(array.slice(0, index));
array = new Array(1024);
index = 0;
}
}
if (index > 0) {
this.spi.write(array.slice(0, index));
}
this.spi.write([0x00]);
this.io_cs.output(false);
}
// copy from display.js
_reset() {
this._pos = { x: 0, y: 0 };
this.autoFlush = true;
}
warnCanvasAvailability() {
if (this.obniz.isNode) {
throw new Error(
'MemoryDisplay require node-canvas to draw rich contents. see more detail on docs'
);
} else {
throw new Error('MemoryDisplay cant create canvas element to body');
}
}
_preparedCanvas() {
if (this._canvas) {
return this._canvas;
}
if (this.obniz.isNode) {
try {
const { createCanvas } = require('canvas');
this._canvas = createCanvas(this.width, this.height);
} catch (e) {
// this.warnCanvasAvailability();
return null;
}
} else {
const identifier = 'MemoryDispCanvas-' + this.obniz.id;
let canvas = document.getElementById(identifier);
if (!canvas) {
canvas = document.createElement('canvas');
canvas.setAttribute('id', identifier);
canvas.style.visibility = 'hidden';
canvas.width = this.width;
canvas.height = this.height;
canvas.style['-webkit-font-smoothing'] = 'none';
let body = document.getElementsByTagName('body')[0];
body.appendChild(canvas);
}
this._canvas = canvas;
}
const ctx = this._canvas.getContext('2d');
ctx.fillStyle = '#FFF';
ctx.fillRect(0, 0, this.width, this.height);
ctx.fillStyle = '#000';
ctx.strokeStyle = '#000';
this._pos.x = 0;
this._pos.y = 0;
this.fontSize = 16;
ctx.font = `${this.fontSize}px Arial`;
return this._canvas;
}
_ctx() {
const canvas = this._preparedCanvas();
if (canvas) {
return canvas.getContext('2d');
}
}
font(font, size) {
const ctx = this._ctx();
if (typeof size !== 'number') {
size = 16;
}
if (typeof font !== 'string') {
font = 'Arial';
}
this.fontSize = size;
ctx.font = '' + +' ' + size + 'px ' + font;
}
clear() {
const ctx = this._ctx();
this._pos.x = 0;
this._pos.y = 0;
if (ctx) {
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, this.width, this.height);
ctx.fillStyle = '#000';
ctx.strokeStyle = '#000';
this.draw(ctx);
} else {
this.sendClear();
}
}
pos(x, y) {
this._ctx(); //crete first
if (typeof x == 'number') {
this._pos.x = x;
}
if (typeof y == 'number') {
this._pos.y = y;
}
return this._pos;
}
print(text) {
const ctx = this._ctx();
if (ctx) {
ctx.fillText(text, this._pos.x, this._pos.y + this.fontSize);
this.draw(ctx);
this._pos.y += this.fontSize;
} else {
/*
let obj = {};
obj['display'] = {
text: '' + text,
};
this.obniz.send(obj);
*/
}
}
line(x_0, y_0, x_1, y_1) {
const ctx = this._ctx();
if (ctx) {
ctx.beginPath();
ctx.moveTo(x_0, y_0);
ctx.lineTo(x_1, y_1);
ctx.stroke();
this.draw(ctx);
} else {
this.warnCanvasAvailability();
}
}
rect(x, y, width, height, mustFill) {
const ctx = this._ctx();
if (ctx) {
if (mustFill) {
ctx.fillRect(x, y, width, height);
} else {
ctx.strokeRect(x, y, width, height);
}
this.draw(ctx);
} else {
this.warnCanvasAvailability();
}
}
circle(x, y, r, mustFill) {
const ctx = this._ctx();
if (ctx) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
if (mustFill) {
ctx.fill();
} else {
ctx.stroke();
}
this.draw(ctx);
} else {
this.warnCanvasAvailability();
}
}
_draw(ctx) {
const stride = this.width / 8;
let vram = new Array(stride * 64);
const imageData = ctx.getImageData(0, 0, this.width, this.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
let brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
let index = parseInt(i / 4);
let line = parseInt(index / this.width);
let col = parseInt((index - line * this.width) / 8);
let bits = parseInt(index - line * this.width) % 8;
if (bits == 0) vram[line * stride + col] = 0x00;
if (brightness > 0x73) vram[line * stride + col] |= 0x80 >> bits;
}
this.raw(vram);
}
draw(ctx) {
if (this.autoFlush) {
this._draw(ctx);
}
}
drawing(autoFlush) {
this.autoFlush = autoFlush == true;
const ctx = this._ctx();
if (ctx) {
this.draw(ctx);
}
}
}
if (typeof module === 'object') {
module.exports = SharpMemoryTFT;
}