diff --git a/README.md b/README.md index 866c0d2..76ac78d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ ![‘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 +OLED JS Pi over i2c-bus ======================== -![oled-cat](http://f.cl.ly/items/2G041X2C1o2A1n2D3S18/cat-oled.png) - ## What is this? -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 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/SH1106 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/)! @@ -15,25 +15,44 @@ OLED screens are really cool - now you can control them with JavaScript! ## Install +Raspberry Pi allows for software I2C. To enable software I2C, add `dtoverlay=i2c-gpio,bus=3` to `/boot.config.txt`. The software I2C would be available on `bus` no `3` +where the `SDA` is on pin `GPIO23`/`BCM 16` and `SCK` is on pun `GPIO24`/`BCM 18`. + If you haven't already, install [NodeJS](http://nodejs.org/). -`npm install oled-js-pi` +`npm install oled-i2c-bus` + +For `SH1106`, if you get an error: +``` +"Error: , Remote I/O error" +``` + +You might have to lower the baudrate by adding the following line to `/boot/config.txt` and rebooting the Pi +``` +dtparam=i2c_baudrate=10000 +``` + +This is a known issue with Raspberry Pi as noted in [Raspberry Pi I2C hardware bug](https://github.com/fivdi/i2c-bus/issues/36). Alternatively, use software I2C. ## I2C screens -Hook up I2C compatible oled to the Raspberry Pi. Pins: SDL and SCL +Hook up I2C compatible oled to the Raspberry Pi. Pins: SDA and SCL ### I2C example ```javascript -var oled = require('oled-js-pi'); +var i2c = require('i2c-bus'); +var oled = require('oled-i2c-bus'); var opts = { width: 128, height: 64, - address: 0x3D + address: 0x3D, + bus: 1, + driver:"SSD1306" }; -var oled = new oled(opts); +var i2cbus = i2c.openSync(opts.bus) +var oled = new oled(i2cBus, opts); // do cool oled things here @@ -125,7 +144,7 @@ Draws a filled rectangle. Arguments: + int **x0, y0** - top left corner of rectangle -+ int **x1, y1** - bottom right 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. @@ -172,6 +191,48 @@ pngtolcd('nyan-cat.png', true, function(err, bitmap) { }); ``` +### 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: @@ -232,6 +293,8 @@ oled.setCursor(1, 1); oled.writeString(font, 1, 'Cats and dogs are really cool animals, you know.', 1, true); ``` +Checkout https://www.npmjs.com/package/oled-font-pack for all-in-one font package. + ### 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. @@ -239,3 +302,67 @@ Usage: ```javascript oled.update(); ``` + +### battery +Draw a battery level in percentage indicator. This method allows for up to 4 different states of the battery: +- 0 bar : battery < 10% +- 1 bar : 10% >= battery < 40% +- 2 bar : 40% >= battery < 70% +- 3 bar : battery >= 70% + +Arguments: +* int **x** - start column +* int **y** - start row +* int **percentage** - battery level percentage + +usage: +```javascript +// args: (x,y,percentage) +oled.battery(1,1,20); +``` + +### bluetooth +Draw a bluetooth icon + +usage: +```javascript +//args: (x,y) +oled.bluetooth(1,1); +``` + +### wifi +Draw a WiFi signal strength in percentage indicator. This method allows for up to 4 different signal strength of the WiFi signal: +- 0 bar : signal < 10% +- 1 bar : 10% >= signal < 40% +- 2 bar : 40% >= signal < 70% +- 3 bar : signal >= 70% + +Arguments: +* int **x** - start column +* int **y** - start row +* int **percentage** - signal strength in percentage + +usage: +```javascript +// args: (x,y,percentage) +oled.wifi(1,1,20); +``` + +### image +A wrapper for `drawRGBAImage` that supports a fix animation. The animation always start from `x=1` and `y=1`. + +Arguments: +* int **x** - start column (ignored on `animation = true`) +* int **y** - start row (ignored on `animation=true`) +* string **image** - full path to the image or the filename of the image in the `resources` folder +* object **font** - font to draw "error" message +* boolean **clear** - clear the display before the draw +* boolean **reset** - stop all animations +* boolean **animated** - enable/disable animation +* boolean **wrapping** - enable/disable of the error message wrapping + +usage: +```javascript +var font = require('oled-font-pack') +oled.image(1,1,'rpi-frambuesa.png',font.oled_5x7,true,false,false,true); +``` \ No newline at end of file diff --git a/drivers/sh1106.js b/drivers/sh1106.js new file mode 100644 index 0000000..4969b64 --- /dev/null +++ b/drivers/sh1106.js @@ -0,0 +1,659 @@ + +var SH1106 = function (i2c, opts) { + this.HEIGHT = opts.height || 64; + this.WIDTH = opts.width || 128; + this.ADDRESS = opts.address || 0x3C; + + this.MAX_PAGE_COUNT = this.HEIGHT / 8; + this.LINESPACING = typeof opts.linespacing !== 'undefined' ? opts.linespacing : 1; + this.LETTERSPACING = typeof opts.letterspacing !== 'undefined' ? opts.letterspacing : 1; + + var config = { + '128x32': { + 'multiplex': 0x1F, + 'compins': 0x02, + 'coloffset': 0x02 + }, + '128x64': { + 'multiplex': 0x3F, + 'compins': 0x12, + 'coloffset': 0x02 + }, + '96x16': { + 'multiplex': 0x0F, + 'compins': 0x02, + 'coloffset': 0x02, + } + }; + + var screenSize = this.WIDTH + 'x' + this.HEIGHT; + this.screenConfig = config[screenSize]; + + // 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 = 0x40; + this.CHARGE_PUMP = 0xAD; + this.EXTERNAL_VCC = false; + this.MEMORY_MODE = 0x20; + this.SEG_REMAP = 0xA1; + 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_LOW_START_ADDR = 0x02; + this.COLUMN_HIGH_START_ADDR = 0x10; + this.PAGE_ADDR = 0xB0; + this.INVERT_DISPLAY = 0xA7; + this.SET_CONTRAST_CTRL_MODE = 0x81; + + this.cursor_x = 0; + this.cursor_y = 0; + + // new blank buffer (1 byte per pixel) + //For version <6.0.0 + if (typeof Buffer.alloc == "undefined") { + this.buffer = new Buffer((this.WIDTH * this.HEIGHT) / 8); + } + //For version >=6.0.0 + else { + this.buffer = Buffer.alloc((this.WIDTH * this.HEIGHT) / 8); + } + this.buffer.fill(0xFF); + this.dirtyBytes = []; + + this.wire = i2c; + this._initialise(); +} + +/* ################################################################################################## + * OLED controls + * ################################################################################################## + */ +// turn oled on +SH1106.prototype.turnOnDisplay = function () { + this._transfer('cmd', this.DISPLAY_ON); +} + +// turn oled off +SH1106.prototype.turnOffDisplay = function () { + this._transfer('cmd', this.DISPLAY_OFF); +} + +// send dim display command to oled +SH1106.prototype.dimDisplay = function (bool) { + var contrast; + + if (bool) { + contrast = 0; // Dimmed display + } else { + contrast = 0xFF; // Bright display + } + + this._transfer('cmd', this.SET_CONTRAST_CTRL_MODE); + this._transfer('cmd', contrast); +} + +// invert pixels on oled +SH1106.prototype.invertDisplay = function (bool) { + if (bool) { + this._transfer('cmd', this.INVERT_DISPLAY); // inverted + } else { + this._transfer('cmd', this.NORMAL_DISPLAY); // non inverted + } +} + +// activate scrolling for rows start through stop +SH1106.prototype.startScroll = function (dir, start, stop) { + console.log("SH1106 do not support this command"); +} + +// stop scrolling display contents +SH1106.prototype.stopScroll = function () { + console.log("SH1106 do not support this command"); +} + +// send the entire framebuffer to the oled +SH1106.prototype.update = function () { + // wait for oled to be ready + this._waitUntilReady(function () { + // set the start and endbyte locations for oled display update + for (var pageIdx = 0; pageIdx <= this.MAX_PAGE_COUNT; pageIdx++) { + const displaySeq = [ + this.PAGE_ADDR + pageIdx, + this.COLUMN_LOW_START_ADDR, + this.COLUMN_HIGH_START_ADDR, + ]; + // send intro seq + for (var i = 0; i < displaySeq.length; i += 1) { + this._transfer('cmd', displaySeq[i]); + } + const start = pageIdx * this.WIDTH; + const end = start + this.WIDTH; + + //For version <6.0.0 + if (typeof this.buffer.subarray == "undefined") { + var pagedBuffer = this.buffer.slice(start, end) + } + //For version >=6.0.0 + else { + var pagedBuffer = this.buffer.subarray(start, end) + } + for (var i = 0; i < pagedBuffer.length; i++) { + this._transfer('data', pagedBuffer[i]); + } + } + }.bind(this)); +} + +/* ################################################################################################## + * OLED drawings + * ################################################################################################## + */ + +// clear all pixels currently on the display +SH1106.prototype.clearDisplay = function (sync) { + for (let i = 0; i < this.buffer.length; i += 1) { + if (this.buffer[i] !== 0x00) { + this.buffer[i] = 0x00; + if (this.dirtyBytes.indexOf(i) === -1) { + this.dirtyBytes.push(i); + } + } + } + if (sync) { + this._updateDirtyBytes(this.dirtyBytes); + } +} + +// set starting position of a text string on the oled +SH1106.prototype.setCursor = function (x, y) { + this.cursor_x = x; + this.cursor_y = y; +} + +// buffer/ram test +SH1106.prototype.drawPageCol = function (page, col, byte) { + // wait for oled to be ready + this._waitUntilReady(function () { + // set the start and endbyte locations for oled display update + var bufferIndex = col + (page * this.WIDTH); + this.buffer[bufferIndex] = byte; + + // Ensure that column is only 0..127. + col &= 0x7F; + col += this.screenConfig.coloffset; // Column Bias for a SH1106. + + var lowAddress = (col & 0x0F); + var highAddress = this.COLUMN_HIGH_START_ADDR | (col >>> 4); + var displaySeq = [ + this.PAGE_ADDR + page, + lowAddress, + highAddress + ]; + + for (var v = 0; v < displaySeq.length; v += 1) { + this._transfer('cmd', displaySeq[v]); + } + this._transfer('data', this.buffer[bufferIndex]); + + }.bind(this)); +} + +SH1106.prototype.drawPageSeg = function (page, seg, byte, sync) { + if (page < 0 || page >= this.MAX_PAGE_COUNT || seg < 0 || seg >= this.WIDTH) { + return + } + // wait for oled to be ready + this._waitUntilReady(function () { + // set the start and endbyte locations for oled display update + var bufferIndex = seg + (page * this.WIDTH); + // console.log(`drawPageSeg -> page:${page}, seg:${seg}, index:${bufferIndex}, byte:${byte.toString(2)}`); + + this.buffer[bufferIndex] = byte; + if (this.dirtyBytes.indexOf(bufferIndex) === -1) { + this.dirtyBytes.push(bufferIndex); + } + if (sync) { + this._updateDirtyBytes(this.dirtyBytes); + } + }.bind(this)); +} + +// draw one or many pixels on oled +SH1106.prototype.drawPixel = function (pixels, 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 + const x = el[0]; + const y = el[1]; + const color = el[2]; + + if (x < 0 || x >= this.WIDTH || y < 0 || y >= this.HEIGHT) { + return; + } + + // thanks, Martin Richards. + // I wanna can this, this tool is for devs who get 0 indexes + // x -= 1; y -=1; + let byte = 0; + const page = Math.floor(y / 8); + const pageShift = 0x01 << (y - 8 * page); + + // is the pixel on the first row of the page? + if (page === 0) { + byte = x; + } else { + byte = x + (this.WIDTH * page); + } + + // colors! Well, monochrome. + if (color === 'BLACK' || !color) { + this.buffer[byte] &= ~pageShift; + } else if (color === 'WHITE' || color) { + this.buffer[byte] |= pageShift; + } + + // push byte to dirty if not already there + if (this.dirtyBytes.indexOf(byte) === -1) { + this.dirtyBytes.push(byte); + } + }, this); + + if (sync) { + this._updateDirtyBytes(this.dirtyBytes); + } +} + +// using Bresenham's line algorithm +SH1106.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 +SH1106.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); + } +} + +// write text to the oled +SH1106.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 RGBA image at the specified coordinates +SH1106.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 +SH1106.prototype.drawBitmap = function (pixels, sync) { + let x; + let y; + + for (let 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 (sync) { + this._updateDirtyBytes(this.dirtyBytes); + } +} + +/* ################################################################################################## + * Private utilities + * ################################################################################################## + */ + +SH1106.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, + this.SET_START_LINE, + this.CHARGE_PUMP, 0x8B, // charge pump val + 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, 0x80, // contrast val + this.SET_PRECHARGE, 0x22, // precharge val + this.SET_VCOM_DETECT, 0x35, // vcom detect + this.NORMAL_DISPLAY, + this.DISPLAY_ON + ]; + + // write init seq commands + for (var i = 0; i < initSeq.length; i++) { + this._transfer('cmd', initSeq[i]); + } +} + +// writes both commands and data buffers to this device +SH1106.prototype._transfer = function (type, val, fn) { + var control; + if (type === 'data') { + control = 0x40; + } else if (type === 'cmd') { + control = 0x00; + } else { + return; + } + + var bufferForSend; + //For version <6.0.0 + if (typeof Buffer.from == "undefined") { + bufferForSend = new Buffer([control, val]); + } + //For version >=6.0.0 + else { + bufferForSend = Buffer.from([control, val]) + } + + // send control and actual val + this.wire.i2cWriteSync(this.ADDRESS, 2, bufferForSend); + if (fn) { + fn(); + } +} + +// read a byte from the oled +SH1106.prototype._readI2C = function (fn) { + //For version <6.0.0 + if (typeof Buffer.from == "undefined") { + this.wire.i2cRead(this.ADDRESS, 0, new Buffer([0]), function (_err, _bytesRead, data) { + // result is single byte + if (typeof data === "object") { + fn(data[0]); + } + else { + fn(0); + } + }); + } + //For version >=6.0.0 + else { + var data = [0]; + this.wire.i2cReadSync(this.ADDRESS, 1, Buffer.from(data)); + fn(data[0]); + } +} + +// draw an individual character to the screen +SH1106.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 +SH1106.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 +SH1106.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; +} + +// looks at dirty bytes, and sends the updated bytes to the display +SH1106.prototype._updateDirtyBytes = function (dirtyByteArray) { + var dirtyByteArrayLen = dirtyByteArray.length + + // check to see if this will even save time + if (dirtyByteArrayLen > (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 < dirtyByteArrayLen; i += 1) { + + var dirtyByteIndex = dirtyByteArray[i]; + var page = Math.floor(dirtyByteIndex / this.WIDTH); + var col = Math.floor(dirtyByteIndex % this.WIDTH); + + // Ensure that column is only 0..127. + col &= 0x7F; + col += this.screenConfig.coloffset; // Column Bias for a SH1106 + + // Compute the lower and high column addresses + var lowAddress = (col & 0x0F); // lower address ranges from 0 to 0x0F + var highAddress = this.COLUMN_HIGH_START_ADDR | (col >>> 4); // high address ranges from 0x10 to 0x18 + var displaySeq = [ + this.PAGE_ADDR + page, + lowAddress, + highAddress + ]; + + for (var v = 0; v < displaySeq.length; v += 1) { + this._transfer('cmd', displaySeq[v]); + } + this._transfer('data', this.buffer[dirtyByteIndex]); + } + // now that all bytes are synced, reset dirty state + this.dirtyBytes = []; + }.bind(this)); + } +} + +// sometimes the oled gets a bit busy with lots of bytes. +// Read the response byte to see if this is the case +SH1106.prototype._waitUntilReady = function (callback) { + var 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); +} + + +module.exports = SH1106; diff --git a/drivers/ssd1306.js b/drivers/ssd1306.js new file mode 100644 index 0000000..9093e2f --- /dev/null +++ b/drivers/ssd1306.js @@ -0,0 +1,663 @@ + +var SSD1306 = function (i2c, opts) { + this.HEIGHT = opts.height || 64; + this.WIDTH = opts.width || 128; + this.ADDRESS = opts.address || 0x3C; + + this.MAX_PAGE_COUNT = this.HEIGHT / 8; + 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; + 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 = 0x02; + this.SET_CONTRAST_CTRL_MODE = 0x81; + + this.cursor_x = 0; + this.cursor_y = 0; + + // new blank buffer (1 byte per pixel) + //For version <6.0.0 + if (typeof Buffer.alloc == "undefined") { + this.buffer = new Buffer((this.WIDTH * this.HEIGHT) / 8); + } + //For version >=6.0.0 + else { + this.buffer = Buffer.alloc((this.WIDTH * this.HEIGHT) / 8); + } + this.buffer.fill(0xFF); + this.dirtyBytes = []; + + var config = { + '128x32': { + 'multiplex': 0x1F, + 'compins': 0x02, + 'coloffset': 0 + }, + '128x64': { + 'multiplex': 0x3F, + 'compins': 0x12, + 'coloffset': 0 + }, + '96x16': { + 'multiplex': 0x0F, + 'compins': 0x02, + 'coloffset': 0, + } + }; + + this.wire = i2c; + var screenSize = this.WIDTH + 'x' + this.HEIGHT; + this.screenConfig = config[screenSize]; + this._initialise(); +} + +/* ################################################################################################## + * OLED controls + * ################################################################################################## + */ +// turn oled on +SSD1306.prototype.turnOnDisplay = function () { + this._transfer('cmd', this.DISPLAY_ON); +} + +// turn oled off +SSD1306.prototype.turnOffDisplay = function () { + this._transfer('cmd', this.DISPLAY_OFF); +} + +// send dim display command to oled +SSD1306.prototype.dimDisplay = function (bool) { + var contrast; + + if (bool) { + contrast = 0; // Dimmed display + } else { + contrast = 0xFF; // Bright display + } + + this._transfer('cmd', this.SET_CONTRAST_CTRL_MODE); + this._transfer('cmd', contrast); +} + +// invert pixels on oled +SSD1306.prototype.invertDisplay = function (bool) { + if (bool) { + this._transfer('cmd', this.INVERT_DISPLAY); // inverted + } else { + this._transfer('cmd', this.NORMAL_DISPLAY); // non inverted + } +} + +// activate scrolling for rows start through stop +SSD1306.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 +SSD1306.prototype.stopScroll = function () { + this._transfer('cmd', this.DEACTIVATE_SCROLL); // stahp +} + +// send the entire framebuffer to the oled +SSD1306.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 + // 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.wire.i2cWriteSync(this.ADDRESS, bufferToSend.length, bufferToSend); + }.bind(this)); +} + +/* ################################################################################################## + * OLED drawings + * ################################################################################################## + */ + +// clear all pixels currently on the display +SSD1306.prototype.clearDisplay = function (sync) { + for (let i = 0; i < this.buffer.length; i += 1) { + if (this.buffer[i] !== 0x00) { + this.buffer[i] = 0x00; + if (this.dirtyBytes.indexOf(i) === -1) { + this.dirtyBytes.push(i); + } + } + } + if (sync) { + this._updateDirtyBytes(this.dirtyBytes); + } +} + +// set starting position of a text string on the oled +SSD1306.prototype.setCursor = function (x, y) { + this.cursor_x = x; + this.cursor_y = y; +} + +// buffer/ram test +SSD1306.prototype.drawPageSeg = function (page, seg, byte, sync) { + if (page < 0 || page >= this.MAX_PAGE_COUNT || seg < 0 || seg >= this.WIDTH) { + return + } + // wait for oled to be ready + this._waitUntilReady(function () { + // set the start and endbyte locations for oled display update + var bufferIndex = seg + (page * this.WIDTH); + // console.log(`drawPageSeg -> page:${page}, seg:${seg}, index:${bufferIndex}, byte:${byte.toString(2)}`); + + this.buffer[bufferIndex] = byte; + if (this.dirtyBytes.indexOf(bufferIndex) === -1) { + this.dirtyBytes.push(bufferIndex); + } + if (sync) { + this._updateDirtyBytes(this.dirtyBytes); + } + }.bind(this)); +} + +// draw one or many pixels on oled +SSD1306.prototype.drawPixel = function (pixels, 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 + const x = el[0]; + const y = el[1]; + const color = el[2]; + + if (x < 0 || x >= this.WIDTH || y < 0 || y >= this.HEIGHT) { + return; + } + + // thanks, Martin Richards. + // I wanna can this, this tool is for devs who get 0 indexes + // x -= 1; y -=1; + let byte = 0; + const page = Math.floor(y / 8); + const pageShift = 0x01 << (y - 8 * page); + + // is the pixel on the first row of the page? + if (page === 0) { + byte = x; + } else { + byte = x + (this.WIDTH * page); + } + + // colors! Well, monochrome. + if (color === 'BLACK' || !color) { + this.buffer[byte] &= ~pageShift; + } else if (color === 'WHITE' || color) { + this.buffer[byte] |= pageShift; + } + + // push byte to dirty if not already there + if (this.dirtyBytes.indexOf(byte) === -1) { + this.dirtyBytes.push(byte); + } + }, this); + + if (sync) { + this._updateDirtyBytes(this.dirtyBytes); + } +} + +// using Bresenham's line algorithm +SSD1306.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 +SSD1306.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); + } +} + +// write text to the oled +SSD1306.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 RGBA image at the specified coordinates +SSD1306.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 +SSD1306.prototype.drawBitmap = function (pixels, sync) { + let x; + let y; + + for (let 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 (sync) { + this._updateDirtyBytes(this.dirtyBytes); + } +} + +/* ################################################################################################## + * Private utilities + * ################################################################################################## + */ + +SSD1306.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 + ]; + + // write init seq commands + for (var i = 0; i < initSeq.length; i++) { + this._transfer('cmd', initSeq[i]); + } +} + +// writes both commands and data buffers to this device +SSD1306.prototype._transfer = function (type, val, fn) { + var control; + if (type === 'data') { + control = 0x40; + } else if (type === 'cmd') { + control = 0x00; + } else { + return; + } + + var bufferForSend; + //For version <6.0.0 + if (typeof Buffer.from == "undefined") { + bufferForSend = new Buffer([control, val]); + } + //For version >=6.0.0 + else { + bufferForSend = Buffer.from([control, val]) + } + + // send control and actual val + this.wire.i2cWriteSync(this.ADDRESS, 2, bufferForSend); + if (fn) { + fn(); + } +} + +// read a byte from the oled +SSD1306.prototype._readI2C = function (fn) { + //For version <6.0.0 + if (typeof Buffer.from == "undefined") { + this.wire.i2cRead(this.ADDRESS, 0, new Buffer([0]), function (_err, _bytesRead, data) { + // result is single byte + if (typeof data === "object") { + fn(data[0]); + } + else { + fn(0); + } + }); + } + //For version >=6.0.0 + else { + var data = [0]; + this.wire.i2cReadSync(this.ADDRESS, 1, Buffer.from(data)); + fn(data[0]); + } +} + +// sometimes the oled gets a bit busy with lots of bytes. +// Read the response byte to see if this is the case +SSD1306.prototype._waitUntilReady = function (callback) { + var 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); +} + +// draw an individual character to the screen +SSD1306.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 +SSD1306.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 +SSD1306.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; +} + +// looks at dirty bytes, and sends the updated bytes to the display +SSD1306.prototype._updateDirtyBytes = function (dirtyByteArray) { + var dirtyByteArrayLen = dirtyByteArray.length + + // check to see if this will even save time + if (dirtyByteArrayLen > (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 < dirtyByteArrayLen; i += 1) { + + var dirtyByteIndex = dirtyByteArray[i]; + var page = Math.floor(dirtyByteIndex / this.WIDTH); + var col = Math.floor(dirtyByteIndex % this.WIDTH); + + var displaySeq = [ + this.COLUMN_ADDR, col, col, // column start and end address + this.PAGE_ADDR, page, page // page start and end address + ]; + + // send intro seq + for (var v = 0; v < displaySeq.length; v += 1) { + this._transfer('cmd', displaySeq[v]); + } + // send byte, then move on to next byte + this._transfer('data', this.buffer[dirtyByteIndex]); + this.buffer[dirtyByteIndex]; + } + // now that all bytes are synced, reset dirty state + this.dirtyBytes = []; + }.bind(this)); + } +} + +module.exports = SSD1306; diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..adcbb5d --- /dev/null +++ b/examples/README.md @@ -0,0 +1,23 @@ + +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 and SH1106 display. + +Raspberry Pi allows for software I2C. To enable software I2C, add `dtoverlay=i2c-gpio,bus=3` to `/boot.config.txt`. The software I2C would be available on `bus` no `3` +where the `SDA` is on pin `GPIO23`/`BCM 16` and `SCK` is on pun `GPIO24`/`BCM 18`. In this examples, the `SSD1306` is using the hardware I2C on bus `1` while the `SH1106` +is using software I2C on bus `3`. + +## Install + +``` +git clone +cd /git/directory +npm install +cd examples +npm install +node ./ssd1306_clock.js +node ./sh1106_clock.js +``` diff --git a/examples/package-lock.json b/examples/package-lock.json new file mode 100644 index 0000000..4e50139 --- /dev/null +++ b/examples/package-lock.json @@ -0,0 +1,171 @@ +{ + "name": "examples", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "examples", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "i2c-bus": "^5.2.2", + "oled-font-pack": "^1.0.1", + "png-to-lcd": "~1.0.2", + "pngjs": "^3.3.3", + "pngparse": "~2.0.1", + "temporal": "^0.3.8" + } + }, + "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==" + }, + "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==" + }, + "node_modules/i2c-bus": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz", + "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "node_modules/oled-font-pack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/oled-font-pack/-/oled-font-pack-1.0.1.tgz", + "integrity": "sha512-vu10Fx63RJfKXcuYdgd9/6T0+u8D4GW3NP4yTJiI4pe/GV384p+O3sLxfpEYIszZjrtBxEZh/u8xXU7S9FMH6w==" + }, + "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==", + "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==", + "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==" + }, + "node_modules/temporal": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz", + "integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==", + "dependencies": { + "es6-shim": "latest" + }, + "engines": { + "node": ">=0.8.0" + } + } + }, + "dependencies": { + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "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==" + }, + "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==" + }, + "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==" + }, + "i2c-bus": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz", + "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==", + "requires": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + } + }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "oled-font-pack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/oled-font-pack/-/oled-font-pack-1.0.1.tgz", + "integrity": "sha512-vu10Fx63RJfKXcuYdgd9/6T0+u8D4GW3NP4yTJiI4pe/GV384p+O3sLxfpEYIszZjrtBxEZh/u8xXU7S9FMH6w==" + }, + "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==", + "requires": { + "floyd-steinberg": "~1.0.4", + "pngparse": "~2.0.1" + } + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + }, + "pngparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pngparse/-/pngparse-2.0.1.tgz", + "integrity": "sha512-RyB1P0BBwt3CNIZ5wT53lR1dT3CUtopnMOuP8xZdHjPhI/uXNNRnkx1yQb/3MMMyyMeo6p19fiIRHcLopWIkxA==" + }, + "temporal": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz", + "integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==", + "requires": { + "es6-shim": "latest" + } + } + } +} diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000..8acee95 --- /dev/null +++ b/examples/package.json @@ -0,0 +1,27 @@ +{ + "name": "examples", + "version": "1.0.0", + "description": "Testing OLED SSD1306 and SH1106 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": "^5.2.2", + "oled-font-pack": "^1.0.1", + "png-to-lcd": "~1.0.2", + "pngjs": "^3.3.3", + "pngparse": "~2.0.1", + "temporal": "^0.3.8" + } +} diff --git a/examples/sh1106_clock.js b/examples/sh1106_clock.js new file mode 100644 index 0000000..4866b9e --- /dev/null +++ b/examples/sh1106_clock.js @@ -0,0 +1,68 @@ + +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../oled'); +const font = require('oled-font-pack'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +var battery = 0; +var signal = 0; +var _oled; +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + _oled = oled; + oled.clearDisplay(true); + + + oled.drawLine(0,0,WIDTH-1,0,1,false); + oled.drawLine(0,HEIGHT-1,WIDTH-1,HEIGHT-1,1,false); + oled.drawLine(0,0,0,HEIGHT-1,1,false); + oled.drawLine(WIDTH-1,0,WIDTH-1,HEIGHT-1,1,false); + oled.bluetooth(25,2); + + oled.image(54,3,"OledImage.png",font.oled_5x7,false,false,false,false); + setInterval(displayClock, 1000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err); + process.exit(1); +} + + +function displayClock() { + var date = new Date(); + var hour = date.getHours(); + hour = (hour < 10 ? "0" : "") + hour; + var min = date.getMinutes(); + min = (min < 10 ? "0" : "") + min; + var sec = date.getSeconds(); + sec = (sec < 10 ? "0" : "") + sec; + + var month = date.getMonth() + 1; + month = (month < 10 ? "0" : "") + month; + var day = date.getDate(); + day = (day < 10 ? "0" : "") + day; + + oled.setCursor(20, Math.floor(HEIGHT / 2) +5); + oled.writeString(font.oled_5x7, 2, hour + ":" + min + ":" + sec, 1, true); + + battery = (battery+20)%100; + signal = (signal+20)%100; + oled.battery(5,4,battery); + oled.wifi(105,2,signal); +} \ No newline at end of file diff --git a/examples/sh1106_rgba.js b/examples/sh1106_rgba.js new file mode 100644 index 0000000..a2777d4 --- /dev/null +++ b/examples/sh1106_rgba.js @@ -0,0 +1,40 @@ +/* + * 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 opts = { + width: 128, + height: 64, + address: 0x3C, + bus:3, + driver: 'SH1106' +}; +var i2cBus = i2c.openSync(opts.bus); +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); +} diff --git a/examples/ssd1306_clock.js b/examples/ssd1306_clock.js new file mode 100644 index 0000000..271fabd --- /dev/null +++ b/examples/ssd1306_clock.js @@ -0,0 +1,68 @@ + +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../oled'); +const font = require('oled-font-pack'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 1, + driver: 'SSD1306' +}; + +var battery = 0; +var signal = 0; +var _oled; +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + _oled = oled; + oled.clearDisplay(true); + + + oled.drawLine(0,0,WIDTH-1,0,1,false); + oled.drawLine(0,HEIGHT-1,WIDTH-1,HEIGHT-1,1,false); + oled.drawLine(0,0,0,HEIGHT-1,1,false); + oled.drawLine(WIDTH-1,0,WIDTH-1,HEIGHT-1,1,false); + oled.bluetooth(25,2); + + oled.image(54,3,"OledImage.png",font.oled_5x7,false,false,false,false); + setInterval(displayClock, 1000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err); + process.exit(1); +} + + +function displayClock() { + var date = new Date(); + var hour = date.getHours(); + hour = (hour < 10 ? "0" : "") + hour; + var min = date.getMinutes(); + min = (min < 10 ? "0" : "") + min; + var sec = date.getSeconds(); + sec = (sec < 10 ? "0" : "") + sec; + + var month = date.getMonth() + 1; + month = (month < 10 ? "0" : "") + month; + var day = date.getDate(); + day = (day < 10 ? "0" : "") + day; + + oled.setCursor(20, Math.floor(HEIGHT / 2) +5); + oled.writeString(font.oled_5x7, 2, hour + ":" + min + ":" + sec, 1, true); + + battery = (battery+20)%100; + signal = (signal+20)%100; + oled.battery(5,4,battery); + oled.wifi(105,2,signal); +} \ No newline at end of file diff --git a/examples/ssd1306_rgba.js b/examples/ssd1306_rgba.js new file mode 100644 index 0000000..3fbfee5 --- /dev/null +++ b/examples/ssd1306_rgba.js @@ -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 opts = { + width: 128, + height: 64, + address: 0x3C, + bus:1, + driver: 'SSD1306' +}; + +var i2cBus = i2c.openSync(opts.bus); +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); +} diff --git a/examples/test.png b/examples/test.png new file mode 100644 index 0000000..ebc5858 Binary files /dev/null and b/examples/test.png differ diff --git a/oled.js b/oled.js index c8fbf17..329302d 100644 --- a/oled.js +++ b/oled.js @@ -1,543 +1,297 @@ -var i2c = require('i2c'); - -var Oled = function(opts) { - - this.HEIGHT = opts.height || 32; - this.WIDTH = opts.width || 128; - this.ADDRESS = opts.address || 0x3C; - this.PROTOCOL = 'I2C'; - - // 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 = new Buffer((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, +const SSD1306 = require('./drivers/ssd1306'); +const SH1106 = require('./drivers/sh1106'); +const fs = require('fs'); +const PNG = require('pngjs').PNG; + +var pdxb = null; +var pdyb = null; +var timers = []; + +var Oled = function (i2c, opts) { + this.DRIVER = opts.driver || "SSD1306"; + this.HEIGHT = opts.height || 64; + this.WIDTH = opts.width || 128; + + switch (this.DRIVER) { + case "SSD1306": + this.api = new SSD1306(i2c, opts); + break; + case "SH1106": + this.api = new SH1106(i2c, opts); + break; + default: + throw new Error("Unknown Driver"); } - }; - // Setup i2c - console.log('this.ADDRESS: ' + this.ADDRESS); - this.wire = new i2c(this.ADDRESS, {device: '/dev/i2c-0'}); // point to your i2c address, debug provides REPL interface +} - var screenSize = this.WIDTH + 'x' + this.HEIGHT; - this.screenConfig = config[screenSize]; +/* ###################################################################### + * OLED Controls + * ###################################################################### + */ +// turn oled on +Oled.prototype.turnOnDisplay = function () { + this.api.turnOnDisplay(); +} - this._initialise(); +// turn oled off +Oled.prototype.turnOffDisplay = function () { + this.api.turnOffDisplay(); } -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]); - } +// send dim display command to oled +Oled.prototype.dimDisplay = function (bool) { + this.api.dimDisplay(bool); } -// 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; - } - - // send control and actual val - // this.board.io.i2cWrite(this.ADDRESS, [control, val]); - this.wire.writeByte(control, function(err) { - this.wire.writeByte(val, function(err) { - fn(); - }); - }); +// invert pixels on oled +Oled.prototype.invertDisplay = function (bool) { + this.api.invertDisplay(bool); } -// read a byte from the oled -Oled.prototype._readI2C = function(fn) { - this.wire.readByte(function(err, data) { - // result is single byte - fn(data); - }); +// activate scrolling for rows start through stop +Oled.prototype.startScroll = function (dir, start, stop) { + this.api.startScroll(dir, start, stop); } -// 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 { - console.log('I\'m busy!'); - setTimeout(tick, 0); - } - }); - }; - - setTimeout(tick(callback), 0); +// stop scrolling display contents +Oled.prototype.stopScroll = function () { + this.api.stopScroll(); } -// set starting position of a text string on the oled -Oled.prototype.setCursor = function(x, y) { - this.cursor_x = x; - this.cursor_y = y; +// send the entire framebuffer to the oled +Oled.prototype.update = function () { + // wait for oled to be ready + this.api.update(); } -// 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, letspace = 1, leading = 2; - - // loop through words - for (var w = 0; w < len; w += 1) { - // put the word space back in - 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 && (offset >= (this.WIDTH - compare)) ) { - offset = 1; - this.cursor_y += (font.height * size) + size + leading; - this.setCursor(offset, this.cursor_y); - } +/* ###################################################################### + * OLED Drawings + * ###################################################################### + */ - // loop through the array of each char to draw - for (var i = 0; i < slen; i += 1) { - // 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); - // draw the entire character - this._drawChar(charBytes, 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 : size + letspace; - offset += (font.width * size) + padding; - - // wrap letters if necessary - if (wrap && (offset >= (this.WIDTH - font.width - letspace))) { - offset = 1; - this.cursor_y += (font.height * size) + size + leading; - } - // 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); - } +// clear all pixels currently on the display +Oled.prototype.clearDisplay = function (sync) { + this.api.clearDisplay(sync); } -// draw an individual character to the screen -Oled.prototype._drawChar = function(byteArray, 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 < 8; 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); - } - } - } +// set starting position of a text string on the oled +Oled.prototype.setCursor = function (x, y) { + this.api.setCursor(x, y); } -// get character bytes from the supplied font object in order to send to framebuffer -Oled.prototype._readCharBytes = function(byteArray) { - 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 < 8; 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; +Oled.prototype.drawPageCol = function (page, col, byte) { + this.api.drawPageCol(page, col, byte); } -// 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; +// buffer/ram test +Oled.prototype.drawPageSeg = function (page, seg, byte, sync) { + this.api.drawPageSeg(page, seg, byte, sync); } -// 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 - for (v = 0; v < bufferLen; v += 1) { - this._transfer('data', this.buffer[v]); - } - - }.bind(this)); +// draw one or many pixels on oled +Oled.prototype.drawPixel = function (pixels, sync) { + this.api.drawPixel(pixels, sync); } -// 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); +// using Bresenham's line algorithm +Oled.prototype.drawLine = function (x0, y0, x1, y1, color, sync) { + this.api.drawLine(x0, y0, x1, y1, color, sync); } -// turn oled off -Oled.prototype.turnOffDisplay = function() { - this._transfer('cmd', this.DISPLAY_OFF); +// draw a filled rectangle on the oled +Oled.prototype.fillRect = function (x, y, w, h, color, sync) { + this.api.fillRect(x, y, w, h, color, sync); } -// turn oled on -Oled.prototype.turnOnDisplay = function() { - this._transfer('cmd', this.DISPLAY_ON); +// write text to the oled +Oled.prototype.writeString = function (font, size, string, color, wrap, sync) { + this.api.writeString(font, size, string, color, wrap, sync); } -// 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); - for (var i = 0; i < this.buffer.length; i += 1) { - if (this.buffer[i] !== 0x00) { - this.buffer[i] = 0x00; - if (this.dirtyBytes.indexOf(i) === -1) { - this.dirtyBytes.push(i); - } - } - } - if (immed) { - this._updateDirtyBytes(this.dirtyBytes); - } -} - -// 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) { + this.api.drawRGBAImage(image, dx, dy, sync); } // 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); - } +Oled.prototype.drawBitmap = function (pixels, sync) { + this.api.drawBitmap(pixels, sync); } -// 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; +/* ###################################################################### + * OLED Shape/Indicators + * ###################################################################### + */ + +Oled.prototype.battery = function (x, y, percentage) { + this.drawLine(x, y, x + 16, y, 1) + this.drawLine(x, y + 8, x + 16, y + 8, 1) + this.drawLine(x, y, x, y + 8, 1) + this.drawPixel([[x + 17, y + 1, 1], [x + 17, y + 7, 1]]) + this.drawLine(x + 18, y + 1, x + 18, y + 7, 1) + + if (percentage >= 70) { + this.fillRect(x + 2, y + 2, 3, 5, 1, false) + this.fillRect(x + 7, y + 2, 3, 5, 1, false) + this.fillRect(x + 12, y + 2, 3, 5, 1, true) } - // push byte to dirty if not already there - if (this.dirtyBytes.indexOf(byte) === -1) { - this.dirtyBytes.push(byte); + if (percentage >= 40 && percentage < 70) { + this.fillRect(x + 2, y + 2, 3, 5, 1, false) + this.fillRect(x + 7, y + 2, 3, 5, 1, false) + this.fillRect(x + 12, y + 2, 3, 5, 0, true) } - }, this); + if (percentage >= 10 && percentage < 40) { + this.fillRect(x + 2, y + 2, 3, 5, 1, false) + this.fillRect(x + 7, y + 2, 3, 5, 0, false) + this.fillRect(x + 12, y + 2, 3, 5, 0, true) + } - if (immed) { - this._updateDirtyBytes(this.dirtyBytes); - } + if (percentage < 10) { + this.fillRect(x + 2, y + 2, 3, 5, 0, false) + this.fillRect(x + 7, y + 2, 3, 5, 0, false) + this.fillRect(x + 12, y + 2, 3, 5, 0, true) + } } -// 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 { +Oled.prototype.bluetooth = function (x, y) { + this.drawLine(x + 5, y + 1, x + 5, y + 11, 1) + this.drawLine(x + 2, y + 3, x + 9, y + 8, 1) + this.drawLine(x + 2, y + 9, x + 8, y + 3, 1) + this.drawLine(x + 5, y + 1, x + 9, y + 3, 1) + this.drawLine(x + 5, y + 11, x + 8, y + 9, 1) +} - this._waitUntilReady(function() { - // iterate through dirty bytes - for (var i = 0; i < blen; i += 1) { +Oled.prototype.wifi = function (x, y, percentage) { + this.drawLine(x, y, x + 8, y, 1) + this.drawLine(x, y, x + 4, y + 4, 1) + this.drawLine(x + 8, y, x + 4, y + 4, 1) + this.drawLine(x + 4, y, x + 4, y + 9, 1) - var byte = byteArray[i]; - var page = Math.floor(byte / this.WIDTH); - var col = Math.floor(byte % this.WIDTH); + if (percentage >= 70) { + this.fillRect(x + 6, y + 8, 2, 2, 1, true) + this.fillRect(x + 10, y + 6, 2, 4, 1, true) + this.fillRect(x + 14, y + 4, 2, 6, 1, true) + } - var displaySeq = [ - this.COLUMN_ADDR, col, col, // column start and end address - this.PAGE_ADDR, page, page // page start and end address - ]; + if (percentage >= 40 && percentage < 70) { + this.fillRect(x + 6, y + 8, 2, 2, 1, true) + this.fillRect(x + 10, y + 6, 2, 4, 1, true) + this.fillRect(x + 14, y + 4, 2, 6, 0, true) + } - var displaySeqLen = displaySeq.length, v; + if (percentage >= 10 && percentage < 40) { + this.fillRect(x + 6, y + 8, 2, 2, 1, true) + this.fillRect(x + 10, y + 6, 2, 4, 0, true) + this.fillRect(x + 14, y + 4, 2, 6, 0, true) + } - // 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 = []; + if (percentage < 10) { + this.fillRect(x + 6, y + 8, 2, 2, 0, true) + this.fillRect(x + 10, y + 6, 2, 4, 0, true) + this.fillRect(x + 14, y + 4, 2, 6, 0, true) + } } -// 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); +Oled.prototype.image = function (x, y, image, font, clear, reset, animated, wrapping) { + + var dirresources = __dirname + "/resources/"; + // console.log(dirresources) + if (typeof reset === 'boolean' && reset) { + timers.forEach(function (entry) { + clearInterval(entry); + entry = null; + }); + timers = []; + if (typeof clear === 'boolean' && clear) { + this.clearDisplay(); + } + if (typeof pdxb === 'number') { pdxb = null } + if (typeof pdyb === 'number') { pdyb = null } + return + } - if (x0 === x1 && y0 === y1) break; + if (typeof image === 'string' && !image.includes("/")) { + tryImage = image; + image = dirresources + image; + } - var e2 = err; + try { + if (!fs.statSync(image).isFile()) { + console.log("file " + image + "not exist."); + } + } catch (err) { + image = dirresources + "notafile.png"; + x = 0; + y = 17; + this.clearDisplay(); + this.writeString(font, 1, tryImage, 1, wrapping) + } - if (e2 > -dx) {err -= dy; x0 += sx;} - if (e2 < dy) {err += dx; y0 += sy;} - } + if (typeof clear === 'boolean' && clear) { + this.clearDisplay(); + } - if (immed) { - this._updateDirtyBytes(this.dirtyBytes); - } + try { + const _oled = this; + fs.createReadStream(image) + .pipe(new PNG({ filterType: 4 })) + .on('parsed', function () { + if (typeof animated === 'boolean' && animated) { + pdxb = 1; + pdyb = -1; + try { + let myInterval = setInterval(() => { _drawPseudo(_oled, clear, this, pdxb, pdyb) }, 10); + timers.push(myInterval); + } catch (e) { console.log(e) } + + } + else { + _oled.api.drawRGBAImage(this, x || Math.floor((_oled.WIDTH - this.width) / 2), y || Math.floor((_oled.HEIGHT - this.height) / 2), true); + } + }); + } catch (err) { + console.error(err) + } } -// 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); - } -} +function _drawPseudo(display, clear, image, pdxb, pdyb) { + var image; + if (typeof this.init === "undefined" || this.init === true || this.image !== image) { + this.init = false; + this.image = image; + this.x = 1; + this.y = 1; + this.prevX = 1; + this.prevY = 1; + this.dx = pdxb; + this.dy = pdyb; + //console.log("entra drawPseudo this.x " + this.x + " this.y " + this.y + " this.dx " + this.dx + " this.dy " + this.dy); + } + if (clear) { + display.fillRect(0, 0, display.WIDTH, display.HEIGHT, 1, true) + display.fillRect(1, 1, display.WIDTH - 2, display.HEIGHT - 2, 0, true) + + } else { + display.fillRect(this.prevX, this.prevY, image.width, image.height, 0, false); + this.prevX = this.x; + this.prevY = this.y; + // display.fillRect(0,0,display.WIDTH , display.HEIGHT ,1,true) + // display.fillRect(1,1,display.WIDTH - 2, display.HEIGHT - 2 ,0,true) + } -// 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]); + display.drawRGBAImage(image, this.x, this.y, true); + if (this.x + this.dx > display.WIDTH - image.width || this.x < 1) { + this.dx = -this.dx; + } + if (this.y + this.dy > display.HEIGHT - image.height || this.y < 1) { + this.dy = -this.dy; } - }.bind(this)); -} -// stop scrolling display contents -Oled.prototype.stopScroll = function() { - this._transfer('cmd', this.DEACTIVATE_SCROLL); // stahp + this.x += this.dx; + this.y += this.dy; } module.exports = Oled; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7e75a39 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,185 @@ +{ + "name": "oled-rpi-i2c-bus", + "version": "1.1.2", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "oled-rpi-i2c-bus", + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "i2c-bus": "^5.2.2", + "pngjs": "^3.3.3" + }, + "devDependencies": { + "oled-font-5x7": "~1.0.0", + "png-to-lcd": "~1.0.2", + "pngparse": "~2.0.1", + "temporal": "^0.3.8" + } + }, + "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/i2c-bus": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz", + "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "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==", + "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/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" + } + } + }, + "dependencies": { + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "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 + }, + "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==" + }, + "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 + }, + "i2c-bus": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz", + "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==", + "requires": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + } + }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "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 + }, + "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, + "requires": { + "floyd-steinberg": "~1.0.4", + "pngparse": "~2.0.1" + } + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + }, + "pngparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pngparse/-/pngparse-2.0.1.tgz", + "integrity": "sha512-RyB1P0BBwt3CNIZ5wT53lR1dT3CUtopnMOuP8xZdHjPhI/uXNNRnkx1yQb/3MMMyyMeo6p19fiIRHcLopWIkxA==", + "dev": true + }, + "temporal": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz", + "integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==", + "dev": true, + "requires": { + "es6-shim": "latest" + } + } + } +} diff --git a/package.json b/package.json index 6b43e40..77d4a10 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,10 @@ { - "name": "oled-js-pi", - "version": "1.0.5", - "description": "NodeJS module for controlling oled devices on the Raspbery Pi (including the SSD1306 OLED screens)", + "name": "oled-i2c-bus", + "version": "1.1.0", + "description": "NodeJS module for controlling oled devices on the Raspbery Pi (including the SSD1306 and SH1106 OLED screens)", "main": "oled.js", - "dependencies": {"i2c": "~0.2.1"}, "devDependencies": { - "oled-font-5x7": "~1.0.0", + "oled-font-pack": "^1.0.1", "png-to-lcd": "~1.0.2", "pngparse": "~2.0.1", "temporal": "^0.3.8" @@ -15,19 +14,29 @@ }, "repository": { "type": "git", - "url": "https://github.com/kd7yva/oled-js-pi.git" + "url": "https://github.com/baltazorr/oled-i2c-bus.git" }, "keywords": [ "Raspbery Pi", "Pi", "NodeJS", "oled", - "SSD1306" + "SSD1306", + "128x64" + ], + "author": [ + "Judd Flamm", + "Suz Hinton", + "Bogdan Symchych", + "Abdul Hadi Fikri" ], - "author": ["Judd Flamm", "Suz Hinton"], "license": "MIT", "bugs": { - "url": "https://github.com/kd7yva/oled-js-pi/issues" + "url": "https://github.com/kd7yva/oled-i2c-bus/issues" }, - "homepage": "https://github.com/kd7yva/oled-js-pi" + "homepage": "https://github.com/baltazorr/oled-i2c-bus", + "dependencies": { + "i2c-bus": "^5.2.2", + "pngjs": "^3.3.3" + } } diff --git a/resources/OledBattery.png b/resources/OledBattery.png new file mode 100644 index 0000000..0a4f498 Binary files /dev/null and b/resources/OledBattery.png differ diff --git a/resources/OledBluetooth.png b/resources/OledBluetooth.png new file mode 100644 index 0000000..5075850 Binary files /dev/null and b/resources/OledBluetooth.png differ diff --git a/resources/OledClear.png b/resources/OledClear.png new file mode 100644 index 0000000..c6ee3a8 Binary files /dev/null and b/resources/OledClear.png differ diff --git a/resources/OledCleardigit.png b/resources/OledCleardigit.png new file mode 100644 index 0000000..abd9645 Binary files /dev/null and b/resources/OledCleardigit.png differ diff --git a/resources/OledClock.png b/resources/OledClock.png new file mode 100644 index 0000000..4f26e2a Binary files /dev/null and b/resources/OledClock.png differ diff --git a/resources/OledClockWhite.png b/resources/OledClockWhite.png new file mode 100644 index 0000000..626b5ee Binary files /dev/null and b/resources/OledClockWhite.png differ diff --git a/resources/OledDim.png b/resources/OledDim.png new file mode 100644 index 0000000..ead31a2 Binary files /dev/null and b/resources/OledDim.png differ diff --git a/resources/OledEight.png b/resources/OledEight.png new file mode 100644 index 0000000..5635dbc Binary files /dev/null and b/resources/OledEight.png differ diff --git a/resources/OledEightWhite.png b/resources/OledEightWhite.png new file mode 100644 index 0000000..6669777 Binary files /dev/null and b/resources/OledEightWhite.png differ diff --git a/resources/OledEightWhiteT.png b/resources/OledEightWhiteT.png new file mode 100644 index 0000000..6b5b7ea Binary files /dev/null and b/resources/OledEightWhiteT.png differ diff --git a/resources/OledFive.png b/resources/OledFive.png new file mode 100644 index 0000000..1e8f732 Binary files /dev/null and b/resources/OledFive.png differ diff --git a/resources/OledFiveWhite.png b/resources/OledFiveWhite.png new file mode 100644 index 0000000..aaf9ad0 Binary files /dev/null and b/resources/OledFiveWhite.png differ diff --git a/resources/OledFiveWhiteT.png b/resources/OledFiveWhiteT.png new file mode 100644 index 0000000..c1ea553 Binary files /dev/null and b/resources/OledFiveWhiteT.png differ diff --git a/resources/OledFour.png b/resources/OledFour.png new file mode 100644 index 0000000..ce39360 Binary files /dev/null and b/resources/OledFour.png differ diff --git a/resources/OledFourWhite.png b/resources/OledFourWhite.png new file mode 100644 index 0000000..5f98653 Binary files /dev/null and b/resources/OledFourWhite.png differ diff --git a/resources/OledFourWhiteT.png b/resources/OledFourWhiteT.png new file mode 100644 index 0000000..e18c2e1 Binary files /dev/null and b/resources/OledFourWhiteT.png differ diff --git a/resources/OledImage.png b/resources/OledImage.png new file mode 100644 index 0000000..d0c19c2 Binary files /dev/null and b/resources/OledImage.png differ diff --git a/resources/OledInvert.png b/resources/OledInvert.png new file mode 100644 index 0000000..b2225a4 Binary files /dev/null and b/resources/OledInvert.png differ diff --git a/resources/OledLine.png b/resources/OledLine.png new file mode 100644 index 0000000..5c8827f Binary files /dev/null and b/resources/OledLine.png differ diff --git a/resources/OledNine.png b/resources/OledNine.png new file mode 100644 index 0000000..7819125 Binary files /dev/null and b/resources/OledNine.png differ diff --git a/resources/OledNineWhite.png b/resources/OledNineWhite.png new file mode 100644 index 0000000..ebb77eb Binary files /dev/null and b/resources/OledNineWhite.png differ diff --git a/resources/OledNineWhiteT.png b/resources/OledNineWhiteT.png new file mode 100644 index 0000000..27121d6 Binary files /dev/null and b/resources/OledNineWhiteT.png differ diff --git a/resources/OledOne.png b/resources/OledOne.png new file mode 100644 index 0000000..afe8d28 Binary files /dev/null and b/resources/OledOne.png differ diff --git a/resources/OledOneWhite.png b/resources/OledOneWhite.png new file mode 100644 index 0000000..e71cb21 Binary files /dev/null and b/resources/OledOneWhite.png differ diff --git a/resources/OledOneWhiteT.png b/resources/OledOneWhiteT.png new file mode 100644 index 0000000..40b86f7 Binary files /dev/null and b/resources/OledOneWhiteT.png differ diff --git a/resources/OledPixel.png b/resources/OledPixel.png new file mode 100644 index 0000000..be88d3b Binary files /dev/null and b/resources/OledPixel.png differ diff --git a/resources/OledRectangle.png b/resources/OledRectangle.png new file mode 100644 index 0000000..c7ab148 Binary files /dev/null and b/resources/OledRectangle.png differ diff --git a/resources/OledScroll.png b/resources/OledScroll.png new file mode 100644 index 0000000..dc1b83b Binary files /dev/null and b/resources/OledScroll.png differ diff --git a/resources/OledSeven.png b/resources/OledSeven.png new file mode 100644 index 0000000..648873f Binary files /dev/null and b/resources/OledSeven.png differ diff --git a/resources/OledSevenWhite.png b/resources/OledSevenWhite.png new file mode 100644 index 0000000..aca8a8a Binary files /dev/null and b/resources/OledSevenWhite.png differ diff --git a/resources/OledSevenWhiteT.png b/resources/OledSevenWhiteT.png new file mode 100644 index 0000000..5fc94da Binary files /dev/null and b/resources/OledSevenWhiteT.png differ diff --git a/resources/OledSix.png b/resources/OledSix.png new file mode 100644 index 0000000..65cf8e4 Binary files /dev/null and b/resources/OledSix.png differ diff --git a/resources/OledSixWhite.png b/resources/OledSixWhite.png new file mode 100644 index 0000000..b9167b5 Binary files /dev/null and b/resources/OledSixWhite.png differ diff --git a/resources/OledSixWhiteT.png b/resources/OledSixWhiteT.png new file mode 100644 index 0000000..4b4e2ac Binary files /dev/null and b/resources/OledSixWhiteT.png differ diff --git a/resources/OledString.png b/resources/OledString.png new file mode 100644 index 0000000..c3adcfe Binary files /dev/null and b/resources/OledString.png differ diff --git a/resources/OledThree.png b/resources/OledThree.png new file mode 100644 index 0000000..a19413a Binary files /dev/null and b/resources/OledThree.png differ diff --git a/resources/OledThreeWhite.png b/resources/OledThreeWhite.png new file mode 100644 index 0000000..8faf8fb Binary files /dev/null and b/resources/OledThreeWhite.png differ diff --git a/resources/OledThreeWhiteT.png b/resources/OledThreeWhiteT.png new file mode 100644 index 0000000..3ae96c5 Binary files /dev/null and b/resources/OledThreeWhiteT.png differ diff --git a/resources/OledTurnOff.png b/resources/OledTurnOff.png new file mode 100644 index 0000000..51e0d23 Binary files /dev/null and b/resources/OledTurnOff.png differ diff --git a/resources/OledTurnOn.png b/resources/OledTurnOn.png new file mode 100644 index 0000000..22f3bfb Binary files /dev/null and b/resources/OledTurnOn.png differ diff --git a/resources/OledTwo.png b/resources/OledTwo.png new file mode 100644 index 0000000..41ebcdb Binary files /dev/null and b/resources/OledTwo.png differ diff --git a/resources/OledTwoWhite.png b/resources/OledTwoWhite.png new file mode 100644 index 0000000..3389cab Binary files /dev/null and b/resources/OledTwoWhite.png differ diff --git a/resources/OledTwoWhiteT.png b/resources/OledTwoWhiteT.png new file mode 100644 index 0000000..eacbab4 Binary files /dev/null and b/resources/OledTwoWhiteT.png differ diff --git a/resources/OledTwopoints.png b/resources/OledTwopoints.png new file mode 100644 index 0000000..7ac8be6 Binary files /dev/null and b/resources/OledTwopoints.png differ diff --git a/resources/OledTwopointsWhite.png b/resources/OledTwopointsWhite.png new file mode 100644 index 0000000..9fa01a3 Binary files /dev/null and b/resources/OledTwopointsWhite.png differ diff --git a/resources/OledWifi.png b/resources/OledWifi.png new file mode 100644 index 0000000..a6e21f6 Binary files /dev/null and b/resources/OledWifi.png differ diff --git a/resources/OledZero.png b/resources/OledZero.png new file mode 100644 index 0000000..965b76c Binary files /dev/null and b/resources/OledZero.png differ diff --git a/resources/OledZeroWhite.png b/resources/OledZeroWhite.png new file mode 100644 index 0000000..769b3fd Binary files /dev/null and b/resources/OledZeroWhite.png differ diff --git a/resources/OledZeroWhiteT.png b/resources/OledZeroWhiteT.png new file mode 100644 index 0000000..39d90a9 Binary files /dev/null and b/resources/OledZeroWhiteT.png differ diff --git a/resources/Oledrpi32x32.png b/resources/Oledrpi32x32.png new file mode 100644 index 0000000..5f4e815 Binary files /dev/null and b/resources/Oledrpi32x32.png differ diff --git a/resources/Oledrpi48x48.png b/resources/Oledrpi48x48.png new file mode 100644 index 0000000..f70f16b Binary files /dev/null and b/resources/Oledrpi48x48.png differ diff --git a/resources/Oledrpi64x64.png b/resources/Oledrpi64x64.png new file mode 100644 index 0000000..4b72700 Binary files /dev/null and b/resources/Oledrpi64x64.png differ diff --git a/resources/WaterBrain.png b/resources/WaterBrain.png new file mode 100644 index 0000000..6e30862 Binary files /dev/null and b/resources/WaterBrain.png differ diff --git a/resources/icon_128x64_kiss.png b/resources/icon_128x64_kiss.png new file mode 100644 index 0000000..ad12c40 Binary files /dev/null and b/resources/icon_128x64_kiss.png differ diff --git a/resources/notafile.png b/resources/notafile.png new file mode 100644 index 0000000..02abd1a Binary files /dev/null and b/resources/notafile.png differ diff --git a/resources/raspberrypi-logo.png b/resources/raspberrypi-logo.png new file mode 100644 index 0000000..f626904 Binary files /dev/null and b/resources/raspberrypi-logo.png differ diff --git a/resources/rpi frambuesa.png b/resources/rpi frambuesa.png new file mode 100644 index 0000000..4b72700 Binary files /dev/null and b/resources/rpi frambuesa.png differ diff --git a/resources/rpi-frambuesa.png b/resources/rpi-frambuesa.png new file mode 100644 index 0000000..4b72700 Binary files /dev/null and b/resources/rpi-frambuesa.png differ diff --git a/resources/yahabommlogo-2-102x16.png b/resources/yahabommlogo-2-102x16.png new file mode 100644 index 0000000..b25d2b2 Binary files /dev/null and b/resources/yahabommlogo-2-102x16.png differ diff --git a/resources/yahabommlogo-2-128x20.png b/resources/yahabommlogo-2-128x20.png new file mode 100644 index 0000000..fcbdabe Binary files /dev/null and b/resources/yahabommlogo-2-128x20.png differ diff --git a/tests/readme.md b/tests/readme.md new file mode 100644 index 0000000..3341b8c --- /dev/null +++ b/tests/readme.md @@ -0,0 +1,3 @@ +Raspberry Pi allows for software I2C. To enable software I2C, add `dtoverlay=i2c-gpio,bus=3` to `/boot.config.txt`. The software I2C would be available on `bus` no `3` +where the `SDA` is on pin `GPIO23`/`BCM 16` and `SCK` is on pun `GPIO24`/`BCM 18`. In this tests, the `SSD1306` is using the hardware I2C on bus `1` while the `SH1106` +is using software I2C on bus `3`. \ No newline at end of file diff --git a/tests/sh1106/battery.js b/tests/sh1106/battery.js new file mode 100644 index 0000000..9c476bc --- /dev/null +++ b/tests/sh1106/battery.js @@ -0,0 +1,40 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +var percentage = 0; +try { + const i2cBus = i2c.openSync(opts.bus || 3); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.battery(5,4,percentage); + setInterval(update, 1000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + +function update() { + percentage = (percentage+20)%100; + oled.battery(5,4,percentage); + } + + + diff --git a/tests/sh1106/bluetooth.js b/tests/sh1106/bluetooth.js new file mode 100644 index 0000000..fcbaf59 --- /dev/null +++ b/tests/sh1106/bluetooth.js @@ -0,0 +1,34 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.bluetooth(5,4); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + diff --git a/tests/sh1106/control.js b/tests/sh1106/control.js new file mode 100644 index 0000000..72fd378 --- /dev/null +++ b/tests/sh1106/control.js @@ -0,0 +1,78 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const path = require('path'); +const dirresources = path.join(__dirname,"../..", "resources/"); +var fs = require('fs'); +var PNG = require('pngjs').PNG; + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + const piLogo = "rpi-frambuesa.png"; + var image; + if (typeof piLogo === 'string' && !piLogo.includes("/")) { + image = dirresources + piLogo; + } else { + console.log("Invalid image filename"); + process.exit(1); + } + if (!fs.statSync(image).isFile()) { + console.log("file " + image + "not exist."); + process.exit(1); + } + fs.createReadStream(image) + .pipe(new PNG({ filterType: 4 })) + .on('parsed', function () { + oled.drawRGBAImage( + this, + Math.floor((WIDTH - this.width) / 2), //x-pos center width + Math.floor((HEIGHT - this.height) / 2),//y-pos center height + true + ); + setTimeout(()=>{ + oled.turnOffDisplay(); + },2000) + setTimeout(()=>{ + oled.turnOnDisplay(); + },3000) + setTimeout(()=>{ + oled.dimDisplay(true); + },4000) + setTimeout(()=>{ + oled.dimDisplay(false); + },5000) + setTimeout(()=>{ + oled.invertDisplay(true); + },6000) + setTimeout(()=>{ + oled.invertDisplay(false); + },7000); + }); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/sh1106/drawBitmap.js b/tests/sh1106/drawBitmap.js new file mode 100644 index 0000000..76da9d8 --- /dev/null +++ b/tests/sh1106/drawBitmap.js @@ -0,0 +1,39 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const pngparse = require('pngparse'); +const path = require('path'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + const image_file = path.join(__dirname,'../../resources','icon_128x64_kiss.png'); + pngparse.parseFile(image_file, function(err, image) { + if(err){ + process.exit(1); + } + oled.drawBitmap(image.data,true); + }); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + diff --git a/tests/sh1106/drawLine.js b/tests/sh1106/drawLine.js new file mode 100644 index 0000000..8e8d5af --- /dev/null +++ b/tests/sh1106/drawLine.js @@ -0,0 +1,42 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + + oled.drawLine(0,0,WIDTH-1,0,1,false); + oled.drawLine(0,HEIGHT-1,WIDTH-1,HEIGHT-1,1,false); + oled.drawLine(0,1,0,HEIGHT-2,1,true); + oled.drawLine(WIDTH-1,1,WIDTH-1,HEIGHT-2,1,false); + + oled.drawLine(1,1,WIDTH-2,HEIGHT-2,1,false); + oled.drawLine(WIDTH-2,2,2,HEIGHT-2,1,true); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/sh1106/drawPageSeg.js b/tests/sh1106/drawPageSeg.js new file mode 100644 index 0000000..57c1904 --- /dev/null +++ b/tests/sh1106/drawPageSeg.js @@ -0,0 +1,45 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + oled.clearDisplay(true); + + var p = 0, s = 0; + oled.drawPageSeg(p, s, 0xFF, 1, true); + setInterval(() => { + oled.drawPageSeg(p, s, 0x00, false); + if (s + 1 >= WIDTH) { + p = (p + 1) % 8; + } + s = (s + 1) % WIDTH; + oled.drawPageSeg(p, s, 0xFF, 1, true); + }, 10); + +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/sh1106/drawPixel.js b/tests/sh1106/drawPixel.js new file mode 100644 index 0000000..b246153 --- /dev/null +++ b/tests/sh1106/drawPixel.js @@ -0,0 +1,55 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.drawPixel([ + [0, 0, 1], + [WIDTH - 1, 0, 1], + [0, HEIGHT - 1, 1], + [WIDTH - 1, HEIGHT - 1, 1] + ], true); + setTimeout(()=>{ + oled.clearDisplay(true); + },4000); + setTimeout(() => { + var x = 0, y = 0; + oled.drawPixel([x, y, 1], true); + setInterval(() => { + oled.drawPixel([x, y, 0], false); + if ((x + 1) % WIDTH == 0) { + y = (y + 1) % HEIGHT; + } + x = (x + 1) % WIDTH; + oled.drawPixel([x, y, 1], true); + }, 10); + }, 5000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/sh1106/drawRGBAImage.js b/tests/sh1106/drawRGBAImage.js new file mode 100644 index 0000000..e8f3223 --- /dev/null +++ b/tests/sh1106/drawRGBAImage.js @@ -0,0 +1,56 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const path = require('path'); +const dirresources = path.join(__dirname,"../..","resources/"); +var fs = require('fs'); +var PNG = require('pngjs').PNG; + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + const piLogo = "rpi-frambuesa.png"; + var image; + if (typeof piLogo === 'string' && !piLogo.includes("/")) { + image = dirresources + piLogo; + } else { + console.log("Invalid image filename"); + process.exit(1); + } + if (!fs.statSync(image).isFile()) { + console.log("file " + image + "not exist."); + process.exit(1); + } + fs.createReadStream(image) + .pipe(new PNG({ filterType: 4 })) + .on('parsed', function () { + oled.drawRGBAImage( + this, + Math.floor((WIDTH - this.width) / 2), //x-pos center width + Math.floor((HEIGHT - this.height) / 2),//y-pos center height + true + ); + }); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + diff --git a/tests/sh1106/fillRect.js b/tests/sh1106/fillRect.js new file mode 100644 index 0000000..9c72309 --- /dev/null +++ b/tests/sh1106/fillRect.js @@ -0,0 +1,41 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + + oled.fillRect(0,0,7,5,1,false); + oled.fillRect(WIDTH-7,0,7,5,1,false); + oled.fillRect(0,HEIGHT-5,7,5,1,false); + oled.fillRect(WIDTH-7,HEIGHT-5,7,5,1,false); + + oled.fillRect(7,5,114,54,1,true); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/sh1106/image.js b/tests/sh1106/image.js new file mode 100644 index 0000000..9448f3a --- /dev/null +++ b/tests/sh1106/image.js @@ -0,0 +1,36 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const font = require('oled-font-pack'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.image(0,0,"WaterBrain.png",font.oled_5x7,false,false,true,false); + setTimeout(()=>{ + oled.image(0,0,"",font.oled_5x7,true,true,false,false); + oled.image(30,3,"rpi-frambuesa.png",font.oled_5x7,true,false,false,false); + },5000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + diff --git a/tests/sh1106/package-lock.json b/tests/sh1106/package-lock.json new file mode 100644 index 0000000..4e50139 --- /dev/null +++ b/tests/sh1106/package-lock.json @@ -0,0 +1,171 @@ +{ + "name": "examples", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "examples", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "i2c-bus": "^5.2.2", + "oled-font-pack": "^1.0.1", + "png-to-lcd": "~1.0.2", + "pngjs": "^3.3.3", + "pngparse": "~2.0.1", + "temporal": "^0.3.8" + } + }, + "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==" + }, + "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==" + }, + "node_modules/i2c-bus": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz", + "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "node_modules/oled-font-pack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/oled-font-pack/-/oled-font-pack-1.0.1.tgz", + "integrity": "sha512-vu10Fx63RJfKXcuYdgd9/6T0+u8D4GW3NP4yTJiI4pe/GV384p+O3sLxfpEYIszZjrtBxEZh/u8xXU7S9FMH6w==" + }, + "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==", + "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==", + "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==" + }, + "node_modules/temporal": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz", + "integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==", + "dependencies": { + "es6-shim": "latest" + }, + "engines": { + "node": ">=0.8.0" + } + } + }, + "dependencies": { + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "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==" + }, + "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==" + }, + "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==" + }, + "i2c-bus": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz", + "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==", + "requires": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + } + }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "oled-font-pack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/oled-font-pack/-/oled-font-pack-1.0.1.tgz", + "integrity": "sha512-vu10Fx63RJfKXcuYdgd9/6T0+u8D4GW3NP4yTJiI4pe/GV384p+O3sLxfpEYIszZjrtBxEZh/u8xXU7S9FMH6w==" + }, + "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==", + "requires": { + "floyd-steinberg": "~1.0.4", + "pngparse": "~2.0.1" + } + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + }, + "pngparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pngparse/-/pngparse-2.0.1.tgz", + "integrity": "sha512-RyB1P0BBwt3CNIZ5wT53lR1dT3CUtopnMOuP8xZdHjPhI/uXNNRnkx1yQb/3MMMyyMeo6p19fiIRHcLopWIkxA==" + }, + "temporal": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz", + "integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==", + "requires": { + "es6-shim": "latest" + } + } + } +} diff --git a/tests/sh1106/package.json b/tests/sh1106/package.json new file mode 100644 index 0000000..ce15f6a --- /dev/null +++ b/tests/sh1106/package.json @@ -0,0 +1,27 @@ +{ + "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": "^5.2.2", + "oled-font-pack": "^1.0.1", + "png-to-lcd": "~1.0.2", + "pngjs": "^3.3.3", + "pngparse": "~2.0.1", + "temporal": "^0.3.8" + } +} diff --git a/tests/sh1106/update.js b/tests/sh1106/update.js new file mode 100644 index 0000000..db5a530 --- /dev/null +++ b/tests/sh1106/update.js @@ -0,0 +1,47 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + oled.clearDisplay(true); + + var p = 0, s = 0; + oled.drawPageSeg(p, s, 0xFF, 1,false); + oled.update(); + setInterval(() => { + oled.drawPageSeg(p, s, 0x00, false); + if (s + 1 >= WIDTH) { + p = (p + 1) % 8; + } + s = (s + 1) % WIDTH; + oled.drawPageSeg(p, s, 0xFF, 1,false); + oled.update(); + }, 10); + +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/sh1106/wifi.js b/tests/sh1106/wifi.js new file mode 100644 index 0000000..b9be6c1 --- /dev/null +++ b/tests/sh1106/wifi.js @@ -0,0 +1,40 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +var percentage = 0; +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.wifi(5,4,percentage); + setInterval(update, 1000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + +function update() { + percentage = (percentage+20)%100; + oled.wifi(5,4,percentage); + } + + + diff --git a/tests/sh1106/writeString.js b/tests/sh1106/writeString.js new file mode 100644 index 0000000..f0eaf8e --- /dev/null +++ b/tests/sh1106/writeString.js @@ -0,0 +1,47 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const font = require('oled-font-pack'); + + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C, + bus: 3, + driver: 'SH1106' +}; + +try { + const i2cBus = i2c.openSync(opts.bus); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + + oled.setCursor(10,0); + oled.writeString(font.oled_5x7,1,"Hello",1,false,false); + oled.setCursor(10,10); + oled.writeString(font.oled_5x7,2,"Hello",1,false,false); + oled.setCursor(10,40); + oled.writeString(font.oled_3x5,1,"Hello",1,false,false); + oled.setCursor(10,50); + oled.writeString(font.oled_3x5,2,"Hello",1,false,false); + oled.setCursor(70,40); + oled.writeString(font.oled_3x5,3,"Hello",1,false,true); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/ssd1306/battery.js b/tests/ssd1306/battery.js new file mode 100644 index 0000000..a2e6101 --- /dev/null +++ b/tests/ssd1306/battery.js @@ -0,0 +1,38 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +var percentage = 0; +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.battery(5,4,percentage); + setInterval(update, 1000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + +function update() { + percentage = (percentage+20)%100; + oled.battery(5,4,percentage); + } + + + diff --git a/tests/ssd1306/bluetooth.js b/tests/ssd1306/bluetooth.js new file mode 100644 index 0000000..a02c119 --- /dev/null +++ b/tests/ssd1306/bluetooth.js @@ -0,0 +1,32 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.bluetooth(5,4); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + diff --git a/tests/ssd1306/control.js b/tests/ssd1306/control.js new file mode 100644 index 0000000..ee649ca --- /dev/null +++ b/tests/ssd1306/control.js @@ -0,0 +1,82 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const path = require("path"); +const dirresources = path.join(__dirname,"../..","resources/"); +var fs = require('fs'); +var PNG = require('pngjs').PNG; + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + const piLogo = "rpi-frambuesa.png"; + var image; + if (typeof piLogo === 'string' && !piLogo.includes("/")) { + image = dirresources + piLogo; + } else { + console.log("Invalid image filename"); + process.exit(1); + } + if (!fs.statSync(image).isFile()) { + console.log("file " + image + "not exist."); + process.exit(1); + } + fs.createReadStream(image) + .pipe(new PNG({ filterType: 4 })) + .on('parsed', function () { + oled.drawRGBAImage( + this, + Math.floor((WIDTH - this.width) / 2), //x-pos center width + Math.floor((HEIGHT - this.height) / 2),//y-pos center height + true + ); + setTimeout(()=>{ + oled.turnOffDisplay(); + },2000) + setTimeout(()=>{ + oled.turnOnDisplay(); + },3000) + setTimeout(()=>{ + oled.dimDisplay(true); + },4000) + setTimeout(()=>{ + oled.dimDisplay(false); + },5000) + setTimeout(()=>{ + oled.invertDisplay(true); + },6000) + setTimeout(()=>{ + oled.invertDisplay(false); + },7000); + setTimeout(()=>{ + oled.startScroll("right",0,127); + },8000); + setTimeout(()=>{ + oled.stopScroll(); + },17000) + }); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/ssd1306/drawBitmap.js b/tests/ssd1306/drawBitmap.js new file mode 100644 index 0000000..f6e9854 --- /dev/null +++ b/tests/ssd1306/drawBitmap.js @@ -0,0 +1,37 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const pngparse = require('pngparse'); +const path = require('path'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + const image_file = path.join(__dirname,'../../resources','icon_128x64_kiss.png'); + pngparse.parseFile(image_file, function(err, image) { + if(err){ + process.exit(1); + } + oled.drawBitmap(image.data,true); + }); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + diff --git a/tests/ssd1306/drawLine.js b/tests/ssd1306/drawLine.js new file mode 100644 index 0000000..88c90a2 --- /dev/null +++ b/tests/ssd1306/drawLine.js @@ -0,0 +1,40 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + + oled.drawLine(0,0,WIDTH-1,0,1,false); + oled.drawLine(0,HEIGHT-1,WIDTH-1,HEIGHT-1,1,false); + oled.drawLine(0,1,0,HEIGHT-2,1,true); + oled.drawLine(WIDTH-1,1,WIDTH-1,HEIGHT-2,1,false); + + oled.drawLine(1,1,WIDTH-2,HEIGHT-2,1,false); + oled.drawLine(WIDTH-2,2,2,HEIGHT-2,1,true); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/ssd1306/drawPageSeg.js b/tests/ssd1306/drawPageSeg.js new file mode 100644 index 0000000..d8e3c5e --- /dev/null +++ b/tests/ssd1306/drawPageSeg.js @@ -0,0 +1,43 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + + var p=0,s=0; + oled.drawPageSeg(p,s,0xFF,1,true); + setInterval(()=>{ + oled.drawPageSeg(p,s,0x00,false); + if(s+1 >= WIDTH){ + p = (p+1)%8; + } + s = (s+1)%WIDTH; + oled.drawPageSeg(p,s,0xFF,1,true); + },10); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/ssd1306/drawPixel.js b/tests/ssd1306/drawPixel.js new file mode 100644 index 0000000..740e68e --- /dev/null +++ b/tests/ssd1306/drawPixel.js @@ -0,0 +1,53 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.drawPixel([ + [0, 0, 1], + [WIDTH - 1, 0, 1], + [0, HEIGHT - 1, 1], + [WIDTH - 1, HEIGHT - 1, 1] + ], true); + setTimeout(()=>{ + oled.clearDisplay(true); + },4000); + setTimeout(() => { + var x = 0, y = 0; + oled.drawPixel([x, y, 1], true); + setInterval(() => { + oled.drawPixel([x, y, 0], false); + if ((x + 1) % WIDTH == 0) { + y = (y + 1) % HEIGHT; + } + x = (x + 1) % WIDTH; + oled.drawPixel([x, y, 1], true); + }, 10); + }, 5000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/ssd1306/drawRGBAImage.js b/tests/ssd1306/drawRGBAImage.js new file mode 100644 index 0000000..a80d3b3 --- /dev/null +++ b/tests/ssd1306/drawRGBAImage.js @@ -0,0 +1,54 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const path = require('path'); +const dirresources = path.join(__dirname,"../..", "resources/"); +var fs = require('fs'); +var PNG = require('pngjs').PNG; + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + const piLogo = "rpi-frambuesa.png"; + var image; + if (typeof piLogo === 'string' && !piLogo.includes("/")) { + image = dirresources + piLogo; + } else { + console.log("Invalid image filename"); + process.exit(1); + } + if (!fs.statSync(image).isFile()) { + console.log("file " + image + "not exist."); + process.exit(1); + } + fs.createReadStream(image) + .pipe(new PNG({ filterType: 4 })) + .on('parsed', function () { + oled.drawRGBAImage( + this, + Math.floor((WIDTH - this.width) / 2), //x-pos center width + Math.floor((HEIGHT - this.height) / 2),//y-pos center height + true + ); + }); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + diff --git a/tests/ssd1306/fillRect.js b/tests/ssd1306/fillRect.js new file mode 100644 index 0000000..a23d559 --- /dev/null +++ b/tests/ssd1306/fillRect.js @@ -0,0 +1,39 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + + oled.fillRect(0,0,7,5,1,false); + oled.fillRect(WIDTH-7,0,7,5,1,false); + oled.fillRect(0,HEIGHT-5,7,5,1,false); + oled.fillRect(WIDTH-7,HEIGHT-5,7,5,1,false); + + oled.fillRect(7,5,114,54,1,true); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + + diff --git a/tests/ssd1306/image.js b/tests/ssd1306/image.js new file mode 100644 index 0000000..240d078 --- /dev/null +++ b/tests/ssd1306/image.js @@ -0,0 +1,34 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const font = require('oled-font-pack'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.image(0,0,"WaterBrain.png",font.oled_5x7,false,false,true,false); + setTimeout(()=>{ + oled.image(0,0,"",font.oled_5x7,true,true,false,false); + oled.image(30,3,"rpi-frambuesa.png",font.oled_5x7,true,false,false,false); + },5000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + diff --git a/tests/ssd1306/package-lock.json b/tests/ssd1306/package-lock.json new file mode 100644 index 0000000..f1aa85e --- /dev/null +++ b/tests/ssd1306/package-lock.json @@ -0,0 +1,182 @@ +{ + "name": "examples", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "examples", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "i2c-bus": "^5.2.2", + "oled-font-3x5": "^1.0.0", + "oled-font-5x7": "~1.0.0", + "png-to-lcd": "~1.0.2", + "pngjs": "^3.3.3", + "pngparse": "~2.0.1", + "temporal": "^0.3.8" + } + }, + "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==" + }, + "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==" + }, + "node_modules/i2c-bus": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz", + "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "node_modules/oled-font-3x5": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/oled-font-3x5/-/oled-font-3x5-1.0.0.tgz", + "integrity": "sha512-/lxmbxy52EwHEYinSly1D+7kMVMKrWOZ9Uy5GUeRMwA8Clvx7ocNazZ62ZQkhIKOrR/nmNDHxY80ip7Ra/MdpA==" + }, + "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==" + }, + "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==", + "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==", + "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==" + }, + "node_modules/temporal": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz", + "integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==", + "dependencies": { + "es6-shim": "latest" + }, + "engines": { + "node": ">=0.8.0" + } + } + }, + "dependencies": { + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "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==" + }, + "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==" + }, + "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==" + }, + "i2c-bus": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz", + "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==", + "requires": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + } + }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "oled-font-3x5": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/oled-font-3x5/-/oled-font-3x5-1.0.0.tgz", + "integrity": "sha512-/lxmbxy52EwHEYinSly1D+7kMVMKrWOZ9Uy5GUeRMwA8Clvx7ocNazZ62ZQkhIKOrR/nmNDHxY80ip7Ra/MdpA==" + }, + "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==" + }, + "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==", + "requires": { + "floyd-steinberg": "~1.0.4", + "pngparse": "~2.0.1" + } + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + }, + "pngparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pngparse/-/pngparse-2.0.1.tgz", + "integrity": "sha512-RyB1P0BBwt3CNIZ5wT53lR1dT3CUtopnMOuP8xZdHjPhI/uXNNRnkx1yQb/3MMMyyMeo6p19fiIRHcLopWIkxA==" + }, + "temporal": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz", + "integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==", + "requires": { + "es6-shim": "latest" + } + } + } +} diff --git a/tests/ssd1306/package.json b/tests/ssd1306/package.json new file mode 100644 index 0000000..ce15f6a --- /dev/null +++ b/tests/ssd1306/package.json @@ -0,0 +1,27 @@ +{ + "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": "^5.2.2", + "oled-font-pack": "^1.0.1", + "png-to-lcd": "~1.0.2", + "pngjs": "^3.3.3", + "pngparse": "~2.0.1", + "temporal": "^0.3.8" + } +} diff --git a/tests/ssd1306/wifi.js b/tests/ssd1306/wifi.js new file mode 100644 index 0000000..d24bc88 --- /dev/null +++ b/tests/ssd1306/wifi.js @@ -0,0 +1,38 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +var percentage = 0; +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + oled.wifi(5,4,percentage); + setInterval(update, 1000); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + +function update() { + percentage = (percentage+20)%100; + oled.wifi(5,4,percentage); + } + + + diff --git a/tests/ssd1306/writeString.js b/tests/ssd1306/writeString.js new file mode 100644 index 0000000..12c111a --- /dev/null +++ b/tests/ssd1306/writeString.js @@ -0,0 +1,44 @@ +"use strict"; + +// NOTE: On newer versions of Raspberry Pi the I2C is set to 1 for hardware I2C and 3 for software I2C, +// however on other platforms you may need to adjust if to +// another value, for example 0. +const i2c = require('i2c-bus'); +const display = require('../../oled'); +const font= require('oled-font-pack'); + +const HEIGHT = 64; +const WIDTH = 128; +var opts = { + width: WIDTH, + height: HEIGHT, + address: 0x3C +}; + +try { + const i2cBus = i2c.openSync(opts.bus || 1); + var oled = new display(i2cBus, opts); + + oled.clearDisplay(true); + + oled.setCursor(10,0); + oled.writeString(font.oled_5x7,1,"Hello",1,false,false); + oled.setCursor(10,10); + oled.writeString(font.oled_5x7,2,"Hello",1,false,false); + oled.setCursor(10,40); + oled.writeString(font.oled_3x5,1,"Hello",1,false,false); + oled.setCursor(10,50); + oled.writeString(font.oled_3x5,2,"Hello",1,false,false); + oled.setCursor(70,40); + oled.writeString(font.oled_3x5,3,"Hello",1,false,true); +} +catch (err) { + // Print an error message and terminate the application + console.log(err.message); + process.exit(1); +} + + + + +