Unverified Commit b41667b8 authored by Marcel Stör's avatar Marcel Stör Committed by GitHub
Browse files

Master drop #2486

Dev -> Master Release 10
parents f99f295d 0abb2617
......@@ -2,3 +2,45 @@
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-06-12 | [Mike Wen](https://github.com/mikewen) | - | [rc.c](../../../app/modules/rc.c)|
Module to generate series of impulses for remote control via 433/315Mhz radio transmitter.
Superseded by **[rfswitch](./rfswitch.md)** module which have same functionality, and supports more transmission protocols.
For more detailed description see [rfswitch module documentation](./rfswitch.md).
## rc.send()
Sends series of impulses
#### Syntax
`rc.send(pin, value, length, pulse_length, protocol_id, repeat)`
which is similar to:
`rfswitch.send(protocol_id, pulse_length, repeat, pin, value, length)`
#### Parameters
- `pin` 0~12, I/O index of pin, example 6 is for GPIO12, see [details](../modules/gpio/)
- `value` positive integer value, this is the primary data which will be sent
- `length` bit length of value, if value length is 3 bytes, then length is 24
- `pulse_length` length of one pulse in microseconds, usually from 100 to 650
- `protocol_id` positive integer value, from 1-3
- `repeat` repeat value, usually from 1 to 5. This is a synchronous task. Setting the repeat count to a large value will cause problems.
The recommended limit is about 1-4.
#### Returns
`1` always 1
#### Example
```lua
-- Lua transmit radio code using protocol #1
-- pulse_length 300 microseconds
-- repeat 5 times
-- use pin #7 (GPIO13)
-- value to send is 560777
-- value length is 24 bits (3 bytes)
rc.send(7, 560777, 24, 300, 1, 5)
```
which is similar to:
```lua
rfswitch.send(1, 300, 5, 7, 560777, 24)
```
# u8g Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-01-30 | [Oli Kraus](https://github.com/olikraus/u8glib), [Arnim Läuger](https://github.com/devsaurus) | [Arnim Läuger](https://github.com/devsaurus) | [u8glib](../../../app/u8glib/)|
U8glib is a graphics library developed at [olikraus/u8glib](https://github.com/olikraus/u8glib) with support for many different displays. The NodeMCU firmware supports a subset of these.
I²C and SPI mode:
- sh1106_128x64
- ssd1306 - 128x32, 128x64, and 64x48 variants
- ssd1309_128x64
- ssd1327_96x96_gr
- uc1611 - dogm240 and dogxl240 variants
SPI only:
- ld7032_60x32
- pcd8544_84x48
- pcf8812_96x65
- ssd1322_nhd31oled - bw and gr variants
- ssd1325_nhd27oled - bw and gr variants
- ssd1351_128x128 - gh and hicolor variants
- st7565_64128n - variants 64128n, dogm128/132, lm6059/lm6063, c12832/c12864
- uc1601_c128032
- uc1608 - 240x128 and 240x64 variants
- uc1610_dogxl160 - bw and gr variants
- uc1611 - dogm240 and dogxl240 variants
- uc1701 - dogs102 and mini12864 variants
This integration is based on [v1.19.1](https://github.com/olikraus/U8glib_Arduino/releases/tag/1.19.1).
## Overview
### I²C Connection
Hook up SDA and SCL to any free GPIOs. Eg. [u8g_graphics_test.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_graphics_test.lua) expects SDA=5 (GPIO14) and SCL=6 (GPIO12). They are used to set up nodemcu's I²C driver before accessing the display:
```lua
sda = 5
scl = 6
i2c.setup(0, sda, scl, i2c.SLOW)
```
### SPI connection
The HSPI module is used ([more information](http://d.av.id.au/blog/esp8266-hardware-spi-hspi-general-info-and-pinout/)), so certain pins are fixed:
- HSPI CLK = GPIO14
- HSPI MOSI = GPIO13
- HSPI MISO = GPIO12 (not used)
All other pins can be assigned to any available GPIO:
- CS
- D/C
- RES (optional for some displays)
Also refer to the initialization sequence eg in [u8g_graphics_test.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_graphics_test.lua):
```lua
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
```
### Library Usage
The Lua bindings for this library closely follow u8glib's object oriented C++ API. Based on the u8g class, you create an object for your display type.
SSD1306 via I²C:
```lua
sla = 0x3c
disp = u8g.ssd1306_128x64_i2c(sla)
```
SSD1306 via SPI:
```lua
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
```
This object provides all of u8glib's methods to control the display. Again, refer to [u8g_graphics_test.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_graphics_test.lua) to get an impression how this is achieved with Lua code. Visit the [u8glib homepage](https://github.com/olikraus/u8glib) for technical details.
### Displays
I²C and HW SPI based displays with support in u8glib can be enabled. To get access to the respective constructors, add the desired entries to the I²C or SPI display tables in [app/include/u8g_config.h](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/u8g_config.h):
```c
#define U8G_DISPLAY_TABLE_I2C \
U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_i2c) \
#define U8G_DISPLAY_TABLE_SPI \
U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_hw_spi) \
U8G_DISPLAY_TABLE_ENTRY(pcd8544_84x48_hw_spi) \
U8G_DISPLAY_TABLE_ENTRY(pcf8812_96x65_hw_spi) \
```
### Fonts
u8glib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in [app/include/u8g_config.h](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/u8g_config.h) and recompile. Simply add the desired fonts to the font table:
```c
#define U8G_FONT_TABLE \
U8G_FONT_TABLE_ENTRY(font_6x10) \
U8G_FONT_TABLE_ENTRY(font_chikita)
```
They'll become available as `u8g.<font_name>` in Lua.
### Bitmaps
Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This off-loads all data handling from the u8g module to generic methods for binary files. See [u8g_bitmaps.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_bitmaps.lua).
In contrast to the source code based inclusion of XBMs into u8glib, it's required to provide precompiled binary files. This can be performed online with [Online-Utility's Image Converter](http://www.online-utility.org/image_converter.jsp): Convert from XBM to MONO format and upload the binary result with [nodemcu-uploader.py](https://github.com/kmpm/nodemcu-uploader).
## I²C Display Drivers
Initialize a display via I²C.
The init sequence would insert delays to match the display specs. These can destabilize the overall system if wifi service is blocked for too long. It is therefore advisable to disable such delays unless the specific use case can exclude wifi traffic while initializing the display driver.
- `u8g.sh1106_128x64_i2c()`
- `u8g.ssd1306_128x32_i2c()`
- `u8g.ssd1306_128x64_i2c()`
- `u8g.ssd1306_64x48_i2c()`
- `u8g.ssd1309_128x64_i2c()`
- `u8g.ssd1327_96x96_gr_i2c()`
- `u8g.uc1611_dogm240_i2c()`
- `u8g.uc1611_dogxl240_i2c()`
####Syntax
`u8g.ssd1306_128x64_i2c(address[, use_delay])`
####Parameters
- `address` I²C slave address of display
- `use_delay` '1': use delays in init sequence, '0' if omitted
####Returns
u8g display object
####Example
```lua
sda = 5
scl = 6
i2c.setup(0, sda, scl, i2c.SLOW)
sla = 0x3c
disp = u8g.ssd1306_128x64_i2c(sla)
```
####See also
[SPI Display Drivers](#spi-display-drivers)
## SPI Display Drivers
Initialize a display via Hardware SPI.
The init sequence would insert delays to match the display specs. These can destabilize the overall system if wifi service is blocked for too long. It is therefore advisable to disable such delays unless the specific use case can exclude wifi traffic while initializing the display driver.
- `u8g.ld7032_60x32_hw_spi()`
- `u8g.pcd8544_84x48_hw_spi()`
- `u8g.pcf8812_96x65_hw_spi()`
- `u8g.sh1106_128x64_hw_spi()`
- `u8g.ssd1306_128x32_hw_spi()`
- `u8g.ssd1306_128x64_hw_spi()`
- `u8g.ssd1306_64x48_hw_spi()`
- `u8g.ssd1309_128x64_hw_spi()`
- `u8g.ssd1322_nhd31oled_bw_hw_spi()`
- `u8g.ssd1322_nhd31oled_gr_hw_spi()`
- `u8g.ssd1325_nhd27oled_bw_hw_spi()`
- `u8g.ssd1325_nhd27oled_gr_hw_spi()`
- `u8g.ssd1327_96x96_gr_hw_spi()`
- `u8g.ssd1351_128x128_332_hw_spi()`
- `u8g.ssd1351_128x128gh_332_hw_spi()`
- `u8g.ssd1351_128x128_hicolor_hw_spi()`
- `u8g.ssd1351_128x128gh_hicolor_hw_spi()`
- `u8g.ssd1353_160x128_332_hw_spi()`
- `u8g.ssd1353_160x128_hicolor_hw_spi()`
- `u8g.st7565_64128n_hw_spi()`
- `u8g.st7565_dogm128_hw_spi()`
- `u8g.st7565_dogm132_hw_spi()`
- `u8g.st7565_lm6059_hw_spi()`
- `u8g.st7565_lm6063_hw_spi()`
- `u8g.st7565_nhd_c12832_hw_spi()`
- `u8g.st7565_nhd_c12864_hw_spi()`
- `u8g.uc1601_c128032_hw_spi()`
- `u8g.uc1608_240x128_hw_spi()`
- `u8g.uc1608_240x64_hw_spi()`
- `u8g.uc1610_dogxl160_bw_hw_spi()`
- `u8g.uc1610_dogxl160_gr_hw_spi()`
- `u8g.uc1611_dogm240_hw_spi()`
- `u8g.uc1611_dogxl240_hw_spi()`
- `u8g.uc1701_dogs102_hw_spi()`
- `u8g.uc1701_mini12864_hw_spi()`
#### Syntax
`u8g.ssd1306_128x64_spi(cs, dc[, res[, use_delay]])`
#### Parameters
- `cs` GPIO pin for /CS
- `dc` GPIO pin for DC
- `res` GPIO pin for /RES, none if omitted
- `use_delay` '1': use delays in init sequence, '0' if omitted
#### Returns
u8g display object
#### Example
```lua
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
```
#### See also
[I²C Display Drivers](#i2c-display-drivers)
## u8g.fb_rle
Initialize a virtual display that provides run-length encoded framebuffer contents to a Lua callback.
The callback function can be used to process the framebuffer line by line. It's called with either `nil` as parameter to indicate the start of a new frame or with a string containing a line of the framebuffer with run-length encoding. First byte in the string specifies how many pairs of (x, len) follow, while each pair defines the start (leftmost x-coordinate) and length of a sequence of lit pixels. All other pixels in the line are dark.
```lua
n = struct.unpack("B", rle_line)
print(n.." pairs")
for i = 0,n-1 do
print(string.format(" x: %d len: %d", struct.unpack("BB", rle_line, 1+1 + i*2)))
end
```
#### Syntax
`u8g.fb_rle(cb_fn, width, height)`
#### Parameters
- `cb_fn([rle_line])` callback function. `rle_line` is a string containing a run-length encoded framebuffer line, or `nil` to indicate start of frame.
- `width` of display. Must be a multiple of 8, less than or equal to 248.
- `height` of display. Must be a multiple of 8, less than or equal to 248.
#### Returns
u8g display object
___
## Constants
Constants for various functions.
`u8g.DRAW_UPPER_RIGHT`, `u8g.DRAW_UPPER_LEFT`, `u8g.DRAW_LOWER_RIGHT`, `u8g.DRAW_LOWER_LEFT`, `u8g.DRAW_ALL`,
`u8g.MODE_BW`, `u8g.MODE_GRAY2BIT`
`u8g.font_6x10`, ...
# u8g.disp Sub-Module
## u8g.disp:begin()
See [u8glib begin()](https://github.com/olikraus/u8glib/wiki/userreference#begin).
## u8g.disp:drawBitmap()
Draw a bitmap at the specified x/y position (upper left corner of the bitmap).
Parts of the bitmap may be outside the display boundaries. The bitmap is specified by the array bitmap. A cleared bit means: Do not draw a pixel. A set bit inside the array means: Write pixel with the current color index. For a monochrome display, the color index 0 will usually clear a pixel and the color index 1 will set a pixel.
#### Syntax
`disp:drawBitmap(x, y, cnt, h, bitmap)`
#### Parameters
- `x` X-position (left position of the bitmap)
- `y` Y-position (upper position of the bitmap)
- `cnt` number of bytes of the bitmap in horizontal direction. The width of the bitmap is cnt*8.
- `h` height of the bitmap
- `bitmap` bitmap data supplied as string
#### Returns
`nil`
#### See also
- [u8glib drawBitmap()](https://github.com/olikraus/u8glib/wiki/userreference#drawbitmap)
- [lua_examples/u8glib/u8g_bitmaps.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_bitmaps.lua)
- [u8g.disp:drawXBM()](#u8gdispdrawxbm)
## u8g.disp:drawBox()
See [u8glib drawBox()](https://github.com/olikraus/u8glib/wiki/userreference#drawbox).
## u8g.disp:drawCircle()
See [u8glib drawCircle()](https://github.com/olikraus/u8glib/wiki/userreference#drawcircle).
## u8g.disp:drawDisc()
See [u8glib drawDisc()](https://github.com/olikraus/u8glib/wiki/userreference#drawdisc).
## u8g.disp:drawEllipse()
See [u8glib drawEllipse()](https://github.com/olikraus/u8glib/wiki/userreference#drawellipse).
## u8g.disp:drawFilledEllipse()
See [u8glib drawFilledEllipse](https://github.com/olikraus/u8glib/wiki/userreference#drawfilledellipse).
## u8g.disp:drawFrame()
See [u8glib drawFrame()](https://github.com/olikraus/u8glib/wiki/userreference#drawframe).
## u8g.disp:drawHLine()
See [u8glib drawHLine()](https://github.com/olikraus/u8glib/wiki/userreference#drawhline).
## u8g.disp:drawLine()
See [u8glib drawLine()](https://github.com/olikraus/u8glib/wiki/userreference#drawline).
## u8g.disp:drawPixel()
See [u8glib drawPixel()](https://github.com/olikraus/u8glib/wiki/userreference#drawpixel).
## u8g.disp:drawRBox()
See [u8glib drawRBox()](https://github.com/olikraus/u8glib/wiki/userreference#drawrbox).
## u8g.disp:drawRFrame()
See [u8glib drawRFrame()](https://github.com/olikraus/u8glib/wiki/userreference#drawrframe).
## u8g.disp:drawStr()
See [u8glib drawStr()](https://github.com/olikraus/u8glib/wiki/userreference#drawstr).
## u8g.disp:drawStr90()
See [u8glib drawStr90](https://github.com/olikraus/u8glib/wiki/userreference#drawstr90).
## u8g.disp:drawStr180()
See [u8glib drawStr180()](https://github.com/olikraus/u8glib/wiki/userreference#drawstr180).
## u8g.disp:drawStr270()
See [u8glib drawStr270()](https://github.com/olikraus/u8glib/wiki/userreference#drawstr270).
## u8g.disp:drawTriangle()
See [u8glib drawTriangle()](https://github.com/olikraus/u8glib/wiki/userreference#drawtriangle).
## u8g.disp:drawVLine()
See [u8glib drawVLine()](https://github.com/olikraus/u8glib/wiki/userreference#drawvline).
## u8g.disp:drawXBM()
Draw a XBM Bitmap. Position (x,y) is the upper left corner of the bitmap.
XBM contains monochrome, 1-bit bitmaps. This procedure only draws pixel values 1. The current color index is used for drawing (see setColorIndex). Pixel with value 0 are not drawn (transparent).
Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This off-loads all data handling from the u8g module to generic methods for binary files. In contrast to the source code based inclusion of XBMs into u8glib, it's required to provide precompiled binary files. This can be performed online with [Online-Utility's Image Converter](http://www.online-utility.org/image_converter.jsp): Convert from XBM to MONO format and upload the binary result with [nodemcu-uploader.py](https://github.com/kmpm/nodemcu-uploader) or [ESPlorer](http://esp8266.ru/esplorer/).
#### Syntax
`disp:drawXBM(x, y, w, h, bitmap)`
#### Parameters
- `x` X-position (left position of the bitmap)
- `y` Y-position (upper position of the bitmap)
- `w` width of the bitmap
- `h` height of the bitmap
- `bitmap` XBM data supplied as string
#### Returns
`nil`
#### See also
- [u8glib drawXBM()](https://github.com/olikraus/u8glib/wiki/userreference#drawxbm)
- [lua_examples/u8glib/u8g_bitmaps.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_bitmaps.lua)
- [u8g.disp:drawBitmap()](#u8gdispdrawbitmap)
## u8g.disp:firstPage()
See [u8glib firstPage()](https://github.com/olikraus/u8glib/wiki/userreference#firstpage).
## u8g.disp:getColorIndex()
See [u8glib getColorIndex()](https://github.com/olikraus/u8glib/wiki/userreference#getcolorindex).
## u8g.disp:getFontAscent()
See [u8glib getFontAscent()](https://github.com/olikraus/u8glib/wiki/userreference#getfontascent).
## u8g.disp:getFontDescent()
See [u8glib getFontDescent()](https://github.com/olikraus/u8glib/wiki/userreference#getfontdescent).
## u8g.disp:getFontLineSpacing()
See [u8glib getFontLineSpacing()](https://github.com/olikraus/u8glib/wiki/userreference#getfontlinespacing).
## u8g.disp:getHeight()
See [u8glib getHeight()](https://github.com/olikraus/u8glib/wiki/userreference#getheight).
## u8g.disp:getMode()
See [u8glib getMode()](https://github.com/olikraus/u8glib/wiki/userreference#getmode).
## u8g.disp:getWidth()
See [u8glib getWidth()](https://github.com/olikraus/u8glib/wiki/userreference#getwidth).
## u8g.disp:getStrWidth()
See [u8glib getStrWidth](https://github.com/olikraus/u8glib/wiki/userreference#getstrwidth).
## u8g.disp:nextPage()
See [u8glib nextPage()](https://github.com/olikraus/u8glib/wiki/userreference#nextpage).
## u8g.disp:setColorIndex()
See [u8glib setColorIndex()](https://github.com/olikraus/u8glib/wiki/userreference#setcolortndex).
## u8g.disp:setContrast()
See [u8glib setContrast()](https://github.com/olikraus/u8glib/wiki/userreference#setcontrast).
## u8g.disp:setDefaultBackgroundColor()
See [u8glib setDefaultBackgroundColor()](https://github.com/olikraus/u8glib/wiki/userreference#setdefaultbackgroundcolor).
## u8g.disp:setDefaultForegroundColor()
See [u8glib setDefaultForegroundColor()](https://github.com/olikraus/u8glib/wiki/userreference#setdefaultforegroundcolor).
## u8g.disp:setFont()
u8glib comes with a wide range of fonts for small displays.
Since they need to be compiled into the firmware image, you'd need to include them in `app/include/u8g_config.h` and recompile. Simply add the desired fonts to the font table:
```c
#define U8G_FONT_TABLE \
U8G_FONT_TABLE_ENTRY(font_6x10) \
U8G_FONT_TABLE_ENTRY(font_chikita)
```
They'll be available as `u8g.<font_name>` in Lua.
#### Syntax
`disp:setFont(font)`
#### Parameters
`font` Constant to indentify pre-compiled font
#### Returns
`nil`
#### Example
```lua
disp:setFont(u8g.font_6x10)
```
#### See also
- [u8glib setFont()](https://github.com/olikraus/u8glib/wiki/userreference#setfont)
## u8g.disp:setFontLineSpacingFactor()
See [u8glib setFontLineSpacingFactor()](https://github.com/olikraus/u8glib/wiki/userreference#setfontlinespacingfactor).
## u8g.disp:setFontPosBaseline()
See [u8glib setFontPosBaseline()](https://github.com/olikraus/u8glib/wiki/userreference#setfontposbaseline).
## u8g.disp:setFontPosBottom()
See [u8glib setFontPosBottom()](https://github.com/olikraus/u8glib/wiki/userreference#setfontposbottom).
## u8g.disp:setFontPosCenter()
See [u8glib setFontPosCenter()](https://github.com/olikraus/u8glib/wiki/userreference#setfontposcenter).
## u8g.disp:setFontPosTop()
See [u8glib setFontPosTop()](https://github.com/olikraus/u8glib/wiki/userreference#setfontpostop).
## u8g.disp:setFontRefHeightAll()
See [u8glib setFontRefHeightAll()](https://github.com/olikraus/u8glib/wiki/userreference#setfontrefheightall).
## u8g.disp:setFontRefHeightExtendedText()
See [u8glib setFontRefHeightExtendedText()](https://github.com/olikraus/u8glib/wiki/userreference#setfontrefheightextendedtext).
## u8g.disp:setFontRefHeightText()
See [u8glib setFontRefHeightText()](https://github.com/olikraus/u8glib/wiki/userreference#setfontrefheighttext).
## u8g.disp:setRot90()
See [u8glib setRot90()](https://github.com/olikraus/u8glib/wiki/userreference#setrot90).
## u8g.disp:setRot180()
See [u8glib setRot180()](https://github.com/olikraus/u8glib/wiki/userreference#setrot180).
## u8g.disp:setRot270()
See [u8glib setRot270()](https://github.com/olikraus/u8glib/wiki/userreference#setrot270).
## u8g.disp:setScale2x2()
See [u8glib setScale2x2()](https://github.com/olikraus/u8glib/wiki/userreference#setscale2x2).
## u8g.disp:sleepOn()
See [u8glib sleepOn()](https://github.com/olikraus/u8glib/wiki/userreference#sleepon).
## u8g.disp:sleepOff()
See [u8glib sleepOff()](https://github.com/olikraus/u8glib/wiki/userreference#sleepoff).
## u8g.disp:undoRotation()
See [u8glib undoRotation()](https://github.com/olikraus/u8glib/wiki/userreference#undorotation).
## u8g.disp:undoScale()
See [u8glib undoScale()](https://github.com/olikraus/u8glib/wiki/userreference#undoscale).
## Unimplemented Functions
- Cursor handling
- disableCursor()
- enableCursor()
- setCursorColor()
- setCursorFont()
- setCursorPos()
- setCursorStyle()
- General functions
- setPrintPos()
- setHardwareBackup()
- setRGB()
- setDefaultMidColor()
# u8g2 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2017-06-02 | [Oli Kraus](https://github.com/olikraus/u8glib), [Arnim Läuger](https://github.com/devsaurus) | [Arnim Läuger](https://github.com/devsaurus) | [u8g2.c](../../../apps/modules/u8g2.c)|
U8g2 is a graphics library developed at [olikraus/u8g2](https://github.com/olikraus/u8g2) with support for many different displays. It is the successor of [U8glib](https://github.com/olikraus/u8glib) which is not developed any further. Please see [How to port U8g code](https://github.com/olikraus/u8g2/wiki/u8gvsu8g2) for generic porting instructions.
!!! note "BSD License for U8g2lib Code"
Universal 8bit Graphics Library (http://code.google.com/p/u8g2/)
Copyright (c) 2016, olikraus@gmail.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The NodeMCU firmware supports the following displays in I²C and SPI mode:
- ld7032 60x32
- sh1106 128x64
- ssd1305 128x32
- ssd1306 - variants 128x32, 128x64, 64x48, and 96x16
- ssd1309 128x64
- ssd1325 128x63
- ssd1327 96x96
- st7588 jlx12864
- uc1601 128x32
- uc1604 jlx19264
- uc1608 - 240x180 and erc24064 variants
- ux1610 dogxl160
- uc1611 - variants dogm240, dogxl240, and ew50850
SPI only:
- il3820 v2 296x128
- ist3020 erc19264
- ls013b7dh03 128x128
- max7219 32x8
- nt7534 tg12864r
- pcd8544 84x48
- pcf8812 96x65
- sed1520 122x32
- ssd1322 nhd 256x64
- ssd1329 128x96
- ssd1606 172x72
- ssd1607 200x200
- st7565 - variants 64128n, dogm128/132, erc12864, lm6059, c12832/c12864, and zolen 128x64
- st7567 - 132x64 and jlx12864 variants
- st75256 - jlx172104 and jlx256128 variants
- uc1701 - dogs102 and mini12864 variants
This integration uses full "RAM" memory buffer without picture loop and calls u8g2's `begin()` internally when creating a display object. It is based on [v2.19.8](https://github.com/olikraus/U8g2_Arduino/releases/tag/2.19.8).
## Overview
### Library Usage
The Lua bindings for this library closely follow u8g2's object oriented C++ API. Based on the u8g2 class, you create an object for your display type. The communication interface has to be initialized up front, refer to the examples below on how to do this.
SSD1306 via I²C:
```lua
sla = 0x3c
disp = u8g2.ssd1306_i2c_128x64_noname(id, sla)
```
SSD1306 via SPI:
```lua
cs = 22
dc = 16
res = 0 -- RES is optional YMMV
disp = u8g2.ssd1306_128x64_noname(bus, cs, dc, res)
```
This object provides all of u8g2's methods to control the display. Refer to [graphics_test.lua](../../../lua_examples/u8g2/graphics_test.lua) to get an impression how this is achieved with Lua code. Visit the [u8g2 homepage](https://github.com/olikraus/u8g2) for technical details.
### Displays selection
I²C and HW SPI based displays with support in u8g2 can be enabled.
The procedure is different for ESP8266 and ESP32 platforms.
#### ESP8266
Add the desired entries to the I²C or SPI display tables in [app/include/u8g2_displays.h](../../../app/include/u8g2_displays.h):
```c
#define U8G2_DISPLAY_TABLE_I2C \
U8G2_DISPLAY_TABLE_ENTRY(u8g2_Setup_ssd1306_i2c_128x64_noname_f, ssd1306_i2c_128x64_noname) \
#define U8G2_DISPLAY_TABLE_SPI \
U8G2_DISPLAY_TABLE_ENTRY(u8g2_Setup_ssd1306_128x64_noname_f, ssd1306_128x64_noname) \
U8G2_DISPLAY_TABLE_ENTRY(u8g2_Setup_pcd8544_84x48_f, pcd8544_84x48) \
U8G2_DISPLAY_TABLE_ENTRY(u8g2_Setup_pcf8812_96x65_f, pcf8812_96x65) \
```
Alternatively, you can define them as `U8G2_DISPLAY_TABLE_I2C_EXTRA` and `U8G2_DISPLAY_TABLE_SPI_EXTRA` in an external file to avoid changing the source tree. Include the extra file on the `make` command line:
```
make EXTRA_CCFLAGS='-include $(TOP_DIR)/my_extras.h'
```
#### ESP32
Enable the desired entries for I²C and SPI displays in u8g2's sub-menu (run `make menuconfig`).
### Fonts selection
U8g2 comes with a wide range of fonts for small displays. Fonts can be supplied as strings or compiled into the firmware image to decrease the RAM footprint. If compiled into the firmware they become available as `u8g2.<font_name>` in Lua.
The procedure is different for ESP8266 and ESP32 platforms.
#### ESP8266
Add the desired fonts to the font table in [app/include/u8g2_fonts.h](../../../app/include/u8g2_fonts.h):
```c
#define U8G2_FONT_TABLE \
U8G2_FONT_TABLE_ENTRY(font_6x10_tf) \
U8G2_FONT_TABLE_ENTRY(font_unifont_t_symbols) \
```
Alternatively, you can define this as `U8G2_FONT_TABLE_EXTRA` in an external file to avoid changing the source tree. Include the extra file on the `make` command line:
```
make EXTRA_CCFLAGS='-include $(TOP_DIR)/my_extras.h'
```
#### ESP32
Add the desired fonts to the font selection sub-entry via `make menuconfig`.
### Bitmaps
XBM bitmaps are supplied as strings to `drawXBM()` in contrast to the source code based inclusion of XBMs in upstream u8g2 library. This off-loads all data handling from the u8g2 module to generic methods for binary files. See [graphics_test.lua](../../../lua_examples/u8g2/graphics_test.lua).
Conversion of XBM bitmaps can be performed online with [Online-Utility's Image Converter](http://www.online-utility.org/image_converter.jsp): Convert from XBM to MONO format and upload the binary result.
## I²C Display Drivers
Initialize a display via I²C.
- `u8g2.ld7032_i2c_60x32()`
- `u8g2.sh1106_i2c_128x64_noname()`
- `u8g2.sh1106_i2c_128x64_vcomh0()`
- `u8g2.ssd1305_i2c_128x32_noname()`
- `u8g2.ssd1306_i2c_128x32_univision()`
- `u8g2.ssd1306_i2c_128x64_noname()`
- `u8g2.ssd1306_i2c_128x64_vcomh0()`
- `u8g2.ssd1309_i2c_128x64_noname0()`
- `u8g2.ssd1309_i2c_128x64_noname2()`
- `u8g2.ssd1306_i2c_64x48_er()`
- `u8g2.ssd1306_i2c_96x16_er()`
- `u8g2.ssd1325_i2c_nhd_128x64()`
- `u8g2.ssd1327_i2c_seeed_96x96()`
- `u8g2.st7588_i2c_jlx12864()`
- `u8g2.uc1602_i2c_128X32()`
- `u8g2.uc1604_i2c_jlx19264()`
- `u8g2.uc1608_i2c_erc24064()`
- `u8g2.uc1608_i2c_240x128()`
- `u8g2.uc1610_i2c_ea_dogxl160()`
- `u8g2.uc1611_i2c_ea_dogm240()`
- `u8g2.uc1611_i2c_ea_dogxl240()`
- `u8g2.uc1611_i2c_ew50850()`
#### Syntax
`u8g2.ssd1306_i2c_128x64_noname(id, address[, cb_fn])`
#### Parameters
- `id` i2c interface id, see [i2c module](i2c.md)
- `address` I²C slave address of display (unshifted)
- `cb_fn` optional callback function, see [Framebuffer callback](#framebuffer-callback)
#### Returns
u8g2 display object
#### Example for ESP8266
```lua
id = 0
sda = 5 -- GPIO14
scl = 6 -- GPIO12
sla = 0x3c
i2c.setup(id, sda, scl, i2c.SLOW)
disp = u8g2.ssd1306_i2c_128x64_noname(id, sla)
```
#### Example for ESP32
```lua
id = i2c.HW0
sda = 16
scl = 17
sla = 0x3c
i2c.setup(id, sda, scl, i2c.FAST)
disp = u8g2.ssd1306_i2c_128x64_noname(id, sla)
```
## SPI Display Drivers
Initialize a display via Hardware SPI.
- `u8g2.il3820_v2_296x128()`
- `u8g2.ist3020_erc19264()`
- `u8g2.ld7032_60x32()`
- `u8g2.ls013b7dh03_128x128()`
- `u8g2.max7219_32x8()`
- `u8g2.nt7534_tg12864r()`
- `u8g2.pcd8544_84x48()`
- `u8g2.pcf8812_96x65()`
- `u8g2.sh1106_128x64_noname()`
- `u8g2.sh1106_128x64_vcomh0()`
- `u8g2.ssd1305_128x32_noname()`
- `u8g2.ssd1306_128x32_univision()`
- `u8g2.ssd1306_128x64_noname()`
- `u8g2.ssd1306_128x64_vcomh0()`
- `u8g2.ssd1306_64x48_er()`
- `u8g2.ssd1306_96x16_er()`
- `u8g2.ssd1309_128x64_noname0()`
- `u8g2.ssd1309_128x64_noname2()`
- `u8g2.sed1520_122x32()`
- `u8g2.ssd1322_nhd_256x64()`
- `u8g2.ssd1325_nhd_128x64()`
- `u8g2.ssd1327_seeed_96x96()`
- `u8g2.ssd1329_128x96_noname()`
- `u8g2.ssd1606_172x72()`
- `u8g2.ssd1607_200x200()`
- `u8g2.st7565_64128n()`
- `u8g2.st7565_ea_dogm128()`
- `u8g2.st7565_ea_dogm132()`
- `u8g2.st7565_erc12864()`
- `u8g2.st7565_lm6059()`
- `u8g2.st7565_nhd_c12832()`
- `u8g2.st7565_nhd_c12864()`
- `u8g2.st7565_zolen_128x64()`
- `u8g2.st7567_jxl12864()`
- `u8g2.st7567_pi_132x64()`
- `u8g2.st7588_jlx12864()`
- `u8g2.st7920_s_128x64()`
- `u8g2.st7920_s_192x32()`
- `u8g2.st75256_jlx172104()`
- `u8g2.st75256_jlx256128()`
- `u8g2.uc1601_128X32()`
- `u8g2.uc1604_jlx19264()`
- `u8g2.uc1608_240x128()`
- `u8g2.uc1608_erc24064()`
- `u8g2.uc1610_ea_dogxl160()`
- `u8g2.uc1611_ea_dogm240()`
- `u8g2.uc1611_ea_dogxl240()`
- `u8g2.uc1611_ew50850()`
- `u8g2.uc1701_ea_dogs102()`
- `u8g2.uc1701_mini12864()`
#### Syntax
`u8g2.ssd1306_128x64_noname(bus, cs, dc[, [res][, cb_fn]])`
#### Parameters
- `bus` SPI master bus
- `cs` GPIO pin for CS
- `dc` GPIO pin for DC
- `res` GPIO pin for RES, none if omitted
- `cb_fn` optional callback function, see [Framebuffer callback](#framebuffer-callback)
#### Returns
u8g2 display object
#### Example for ESP8266
```lua
-- Hardware SPI CLK = GPIO14
-- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used)
-- Hardware SPI /CS = GPIO15 (not used)
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16
bus = 1
spi.setup(bus, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
-- we won't be using the HSPI /CS line, so disable it again
gpio.mode(8, gpio.INPUT, gpio.PULLUP)
disp = u8g2.ssd1306_128x64_noname(bus, cs, dc, res)
```
#### Example for ESP32
```lua
sclk = 19
mosi = 23
cs = 22
dc = 16
res = 17
bus = spi.master(spi.HSPI, {sclk=sclk, mosi=mosi})
disp = u8g2.ssd1306_128x64_noname(bus, cs, dc, res)
```
## Framebuffer callback
Each display type can be initialized to provide the framebuffer contents in run-length encoded format to a Lua callback. This mode is enabled when a callback function is specified for the setup function. Hardware display and framebuffer callback can be operated in parallel. If the callback function is the only parameter then no signals for a hardware display are generated, leaving a virtual display.
The callback function can be used to process the framebuffer line by line. It's called with either `nil` as parameter to indicate the start of a new frame or with a string containing a line of the framebuffer with run-length encoding. First byte in the string specifies how many pairs of (x, len) follow, while each pair defines the start (leftmost x-coordinate) and length of a sequence of lit pixels. All other pixels in the line are dark.
```lua
n = struct.unpack("B", rle_line)
print(n.." pairs")
for i = 0,n-1 do
print(string.format(" x: %d len: %d", struct.unpack("BB", rle_line, 1+1 + i*2)))
end
```
#### Syntax
```lua
u8g2.ssd1306_i2c_128x64_noname(id, address[, cb_fn])
u8g2.ssd1306_i2c_128x64_noname(cb_fn)
u8g2.ssd1306_128x64_noname(bus, cs, dc[, [res][, cb_fn]])
u8g2.ssd1306_128x64_noname(cb_fn)
```
#### Parameters
- `id`, `address`, `bus`, `cs`, `dc`, `res` see above
- `cb_fn([rle_line])` callback function. `rle_line` is a string containing a run-length encoded framebuffer line, or `nil` to indicate start of frame.
## Constants
Constants for various functions.
`u8g2.DRAW_UPPER_RIGHT`, `u8g2.DRAW_UPPER_LEFT`, `u8g2.DRAW_LOWER_RIGHT`, `u8g2.DRAW_LOWER_LEFT`, `u8g2.DRAW_ALL`,
`u8g2.R0`, `u8g2.R1`, `u8g2.R2`, `u8g2.R3`, `u8g2.MIRROR`,
`u8g2.font_6x10`, ...
# u8g2.disp Sub-Module
## u8g2.disp:clearBuffer()
Clears all pixel in the memory frame buffer.
See [u8g2 clearBuffer()](https://github.com/olikraus/u8g2/wiki/u8g2reference#clearbuffer).
## u8g2.disp:drawBox()
Draw a box (filled frame).
See [u8g2 drawBox()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawbox).
## u8g2.disp:drawCircle()
Draw a circle.
See [u8g2 drawCircle()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawcircle).
Note that parameter `opt` is optional and defaults to `u8g2.DRAW_ALL` if omitted.
## u8g2.disp:drawDisc()
Draw a filled circle.
See [u8g2 drawDisc()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawdisc).
Note that parameter `opt` is optional and defaults to `u8g2.DRAW_ALL` if omitted.
## u8g2.disp:drawEllipse()
Draw an ellipse.
See [u8g2 drawEllipse()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawellipse).
Note that parameter `opt` is optional and defaults to `u8g2.DRAW_ALL` if omitted.
## u8g2.disp:drawFilledEllipse()
Draw a filled ellipse.
See [u8g2 drawFilledEllipse()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawfilledellipse).
Note that parameter `opt` is optional and defaults to `u8g2.DRAW_ALL` if omitted.
## u8g2.disp:drawFrame()
Draw a frame (empty box).
See [u8g2 drawFrame()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawframe).
## u8g2.disp:drawGlyph()
Draw a single character.
See [u8g2 drawGlyph()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawglyph).
## u8g2.disp:drawHLine()
Draw a horizontal line.
See [u8g2 drawHLine()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawhline).
## u8g2.disp:drawLine()
Draw a line between two points.
See [u8g2 drawLine()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawline).
## u8g2.disp:drawPixel()
Draw a pixel.
See [u8g2 drawPixel()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawpixel).
## u8g2.disp:drawRBox()
Draw a box with round edges.
See [u8g2 drawRBox()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawrbox).
## u8g2.disp:drawRFrame()
Draw a frame with round edges.
See [u8g2 drawRFrame()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawrframe).
## u8g2.disp:drawStr()
Draw a string.
See [u8g2 drawStr()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawstr).
## u8g2.disp:drawTriangle()
Draw a triangle (filled polygon).
See [u8g2 drawTriangle()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawtriangle).
## u8g2.disp:drawUTF8()
Draw a string which is encoded as UTF-8.
See [u8g2 drawUTF8()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawutf8).
## u8g2.disp:drawVLine()
Draw a vertical line.
See [u8g2 drawVLine()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawvline).
## u8g2.disp:drawXBM()
Draw a XBM Bitmap.
See [u8g2 drawXBM()](https://github.com/olikraus/u8g2/wiki/u8g2reference#drawxbm).
XBM bitmaps are supplied as strings to `drawXBM()`. This off-loads all data handling from the u8g2 module to generic methods for binary files. See [graphics_test.lua](../../../lua_examples/u8glib/u8g_graphics_test.lua).
In contrast to the source code based inclusion of XBMs in upstream u8g2 library, it's required to provide precompiled binary files. This can be performed online with [Online-Utility's Image Converter](http://www.online-utility.org/image_converter.jsp): Convert from XBM to MONO format and upload the binary result.
## u8g2.disp:getAscent()
Returns the reference height of the glyphs above the baseline (ascent).
See [u8g2 getAscent()](https://github.com/olikraus/u8g2/wiki/u8g2reference#getascent).
## u8g2.disp:getDescent()
Returns the reference height of the glyphs below the baseline (descent).
See [u8g2 getDescent()](https://github.com/olikraus/u8g2/wiki/u8g2reference#getdescent).
## u8g2.disp:getStrWidth()
Return the pixel width of string.
See [u8g2 getStrWidth()](https://github.com/olikraus/u8g2/wiki/u8g2reference#getstrwidth).
## u8g2.disp:getUTF8Width()
Return the pixel width of an UTF-8 encoded string.
See [u8g2 getUTF8Width()](https://github.com/olikraus/u8g2/wiki/u8g2reference#getutf8width).
## u8g2.disp:sendBuffer()
Send the content of the memory frame buffer to the display.
See [u8g2 sendBuffer()](https://github.com/olikraus/u8g2/wiki/u8g2reference#sendbuffer).
## u8g2.disp:setBitmapMode()
Define bitmap background color mode.
See [u8g2 setBitmapMode()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setbitmapmode).
## u8g2.disp:setContrast()
Set the contrast or brightness.
See [u8g2 setContrast()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setconstrast).
## u8g2.disp:setDisplayRotation()
Changes the display rotation.
See [u8g2 setDisplayRotation()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setdisplayrotation).
## u8g2.disp:setDrawColor()
Defines the bit value (color index) for all drawing functions.
See [u8g2 setDrawColor()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setdrawcolor).
## u8g2.disp:setFlipMode()
Set flip (180 degree rotation) mode.
See [u8g2 setFlipMode()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setflipmode).
## u8g2.disp:setFont()
Define a u8g2 font for the glyph and string drawing functions. They can be supplied as strings or compiled into the firmware image. They are available as `u8g2.<font_name>` in Lua.
See [u8g2 setFont()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfont).
## u8g2.disp:setFontDirection()
Set the drawing direction of all strings or glyphs.
See [u8g2 setFontDirection()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontdirection).
## u8g2.disp:setFontMode()
Define font background color mode.
See [u8g2 setFontMode()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontmode).
## u8g2.disp:setFontPosBaseline()
Change the reference position for the glyph and string draw functions to "baseline".
See [u8g2 setFontPosBaseline()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontposbaseline).
## u8g2.disp:setFontPosBottom()
Change the reference position for the glyph and string draw functions to "bottom".
See [u8g2 setFontPosBottom()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontposbottom).
## u8g2.disp:setFontPosTop()
Change the reference position for the glyph and string draw functions to "top".
See [u8g2 setFontPosTop()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontpostop).
## u8g2.disp:setFontPosCenter()
Change the reference position for the glyph and string draw functions to "center".
See [u8g2 setFontPosCenter()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontposcenter).
## u8g2.disp:setFontRefHeightAll()
Set ascent and descent calculation mode to "highest and lowest glyph".
See [u8g2 setFontRefHeightAll()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontrefheightall).
## u8g2.disp:setFontRefHeightExtendedText()
Set ascent and descent calculation mode to "highest of [A1(], lowest of [g(]".
See [u8g2 setFontRefHeightExtendedText()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontrefheightextendedtext).
## u8g2.disp:setFontRefHeightText()
Set ascent and descent calculation mode to "highest of [A1], lowest of [g]".
See [u8g2 setFontRefHeightText()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setfontrefheighttext).
## u8g2.disp:setPowerSave()
Activate or disable power save mode of the display.
See [u8g2 setPowerSave()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setpowersave).
......@@ -12,7 +12,7 @@ This module is not for casual use -- it requires an understanding of IEEE802.11
This registers a callback function to be called whenever a management frame is received. Note that this can be at quite a high rate, so some limited
filtering is provided before the callback is invoked. Only the first 110 bytes or so of the frame are returned -- this is an SDK restriction.
Any connected ap/station will be disconnected.
Any connected AP/station will be disconnected. Calling this function sets the channel back to 1.
#### Syntax
`wifi.monitor.start([filter parameters,] mgmt_frame_callback)`
......@@ -29,10 +29,10 @@ nothing.
#### Example
```
wifi.monitor.channel(6)
wifi.monitor.start(13, 0x80, function(pkt)
print ('Beacon: ' .. pkt.bssid_hex .. " '" .. pkt[0] .. "' ch " .. pkt[3]:byte(1))
end)
wifi.monitor.channel(6)
```
## wifi.monitor.stop()
......@@ -46,6 +46,7 @@ This disables the monitor mode and returns to normal operation. There are no par
This sets the channel number to monitor. Note that in many applications you will want to step through the channel numbers at regular intervals. Beacon
frames (in particular) are typically sent every 102 milliseconds, so a switch time of (say) 150 milliseconds seems to work well.
Note that this function should be called after starting to monitor, since `wifi.monitor.start` resets the channel back to 1.
#### Syntax
`wifi.monitor.channel(channel)`
......
# Getting started
## Obtain the firmware
[Build the firmware](build.html) or download it from ?
## Flash the firmware
There are a number of tools for flashing the firmware.
......@@ -118,19 +118,9 @@ wifi.sta.config({ssid=SSID, pwd=PASSWORD})
## Compiling Lua on your PC for Uploading
If you install `lua` on your development PC or Laptop then you can use the standard Lua
compiler to syntax check any Lua source before downloading it to the ESP8266 module. However,
the NodeMCU compiler output uses different data types (e.g. it supports ROMtables) so the
compiled output cannot run on the ESP8266.
Compiling source on one platform for use on another (e.g. Intel x38 Window to ESP8266) is
known as _cross-compilation_ and the NodeMCU firmware supports the compilation of `luac.cross`
on \*nix patforms which have Lua 5.1, the Lua filesystem module (lfs), and the essential
GCC tools. Simply change directory to the firmware root directoy and run the command:
lua tools/cross-lua.lua
This will generate a `luac.cross` executable in your root directory which can be used to
compile and to syntax-check Lua source on the Development machine for execution under
NodeMCU Lua on the ESP8266.
If you install Lua on your development PC or Laptop, then you can use a standard `lua` environment to develop PC applications and also use the standard `luac` compiler to syntax check _any_ Lua source code. However because of architectural differences between the ESP8266 chipset with its SDK and a standard PC CPU, the system APIs are different and the binary output from the standard PC `luac` cannot be run on the ESP8266.
To address this issue, the standard NodeMCU make now generates a host executable `lua.cross` (or `lua.cross.int` for integer builds) as well as the firmware binary itself. Compiling source on one platform for use on another is known as _cross-compilation_ and this `luac.cross` compiler allows you to compile Lua source files on your PC for downloading onto ESP8266 in a binary format.
The firmware also includes API calls to allow Lua sources to be compiled on ESP, but this mode of compilation is limited by the RAM heap available. Host cross compilation bypasses this ESP compile limit entirely and allows you to use larger modules within your code. In the case of LFS compiles, this code is stored in flash memory on the ESP, and so has no RAM overhead; the only limit is the size of the allocated LFS region.
var nodemcu = nodemcu || {};
(function () {
'use strict';
//var languageCodeToNameMap = {en: 'English', de: 'Deutsch'};
......@@ -112,7 +113,7 @@ var nodemcu = nodemcu || {};
* replaces the relative path with an absolute path based on the selected branch.
*/
function replaceRelativeLinksWithStaticGitHubUrl() {
var relativePath = "../../../..";
var relativePath = isOnRtd() ? "../../../.." : "../../..";
var gitHubPath = "https://github.com/nodemcu/nodemcu-firmware/tree/" + determineSelectedBranch();
var gitHubLinks = $("a[href^='" + relativePath + "']").each(function (index) {
var url = $(this).attr('href');
......@@ -148,7 +149,7 @@ var nodemcu = nodemcu || {};
*/
function determineSelectedLanguageCode() {
var selectedLanguageCode, path = window.location.pathname;
if (window.location.origin.indexOf('readthedocs') > -1) {
if (isOnRtd()) {
// path is like /en/<branch>/<lang>/build/ -> extract 'lang'
// split[0] is an '' because the path starts with the separator
selectedLanguageCode = path.split('/')[3];
......@@ -171,7 +172,7 @@ var nodemcu = nodemcu || {};
*/
function determineSelectedBranch() {
var branch = 'dev', path = window.location.pathname;
if (window.location.origin.indexOf('readthedocs') > -1) {
if (isOnRtd()) {
// path is like /en/<branch>/<lang>/build/ -> extract 'lang'
// split[0] is an '' because the path starts with the separator
var thirdPathSegment = path.split('/')[2];
......@@ -192,4 +193,8 @@ var nodemcu = nodemcu || {};
}
return values;
}
function isOnRtd() {
return window.location.origin.indexOf('readthedocs') > -1;
}
}());
......@@ -233,22 +233,25 @@ SECTIONS
/* Link-time arrays containing the defs for the included modules */
. = ALIGN(4);
lua_libs = ABSOLUTE(.);
lua_libs_base = ABSOLUTE(.);
/* Allow either empty define or defined-to-1 to include the module */
KEEP(*(.lua_libs))
LONG(0) LONG(0) /* Null-terminate the array */
lua_rotable = ABSOLUTE(.);
lua_rotable_base = ABSOLUTE(.);
KEEP(*(.lua_rotable))
LONG(0) LONG(0) /* Null-terminate the array */
/* SDK doesn't use libc functions, and are therefore safe to put in flash */
/* SDK doesn't use libc functions, and are therefore safe to put in flash */
*/libc.a:*.o(.text* .literal*)
/* end libc functions */
/* Reserved areas, flash page aligned and last */
. = ALIGN(4096);
KEEP(*(.irom.reserved .irom.reserved.*))
_irom0_text_end = ABSOLUTE(.);
_flash_used_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr =0xffffffff
}
/* get ROM code address */
......
# Ignore everything
*
# But not this file itself.
!.gitignore
--
-- If you have the LFS _init loaded then you invoke the provision by
-- executing LFS.HTTP_OTA('your server','directory','image name'). Note
-- that is unencrypted and unsigned. But the loader does validate that
-- the image file is a valid and complete LFS image before loading.
--
local host, dir, image = ...
local doRequest, firstRec, subsRec, finalise
local n, total, size = 0, 0
doRequest = function(sk,hostIP)
if hostIP then
local con = net.createConnection(net.TCP,0)
con:connect(80,hostIP)
-- Note that the current dev version can only accept uncompressed LFS images
con:on("connection",function(sck)
local request = table.concat( {
"GET "..dir..image.." HTTP/1.1",
"User-Agent: ESP8266 app (linux-gnu)",
"Accept: application/octet-stream",
"Accept-Encoding: identity",
"Host: "..host,
"Connection: close",
"", "", }, "\r\n")
print(request)
sck:send(request)
sck:on("receive",firstRec)
end)
end
end
firstRec = function (sck,rec)
-- Process the headers; only interested in content length
local i = rec:find('\r\n\r\n',1,true) or 1
local header = rec:sub(1,i+1):lower()
size = tonumber(header:match('\ncontent%-length: *(%d+)\r') or 0)
print(rec:sub(1, i+1))
if size > 0 then
sck:on("receive",subsRec)
file.open(image, 'w')
subsRec(sck, rec:sub(i+4))
else
sck:on("receive", nil)
sck:close()
print("GET failed")
end
end
subsRec = function(sck,rec)
total, n = total + #rec, n + 1
if n % 4 == 1 then
sck:hold()
node.task.post(0, function() sck:unhold() end)
end
uart.write(0,('%u of %u, '):format(total, size))
file.write(rec)
if total == size then finalise(sck) end
end
finalise = function(sck)
file.close()
sck:on("receive", nil)
sck:close()
local s = file.stat(image)
if (s and size == s.size) then
wifi.setmode(wifi.NULLMODE)
collectgarbage();collectgarbage()
-- run as separate task to maximise RAM available
node.task.post(function() node.flashreload(image) end)
else
print"Invalid save of image file"
end
end
net.dns.resolve(host, doRequest)
--
-- File: _init.lua
--[[
This is a template for the LFS equivalent of the SPIFFS init.lua.
It is a good idea to such an _init.lua module to your LFS and do most of the LFS
module related initialisaion in this. This example uses standard Lua features to
simplify the LFS API.
The first section adds a 'LFS' table to _G and uses the __index metamethod to
resolve functions in the LFS, so you can execute the main function of module
'fred' by executing LFS.fred(params), etc. It also implements some standard
readonly properties:
LFS._time The Unix Timestamp when the luac.cross was executed. This can be
used as a version identifier.
LFS._config This returns a table of useful configuration parameters, hence
print (("0x%6x"):format(LFS._config.lfs_base))
gives you the parameter to use in the luac.cross -a option.
LFS._list This returns a table of the LFS modules, hence
print(table.concat(LFS._list,'\n'))
gives you a single column listing of all modules in the LFS.
---------------------------------------------------------------------------------]]
local index = node.flashindex
local lfs_t = {
__index = function(_, name)
local fn_ut, ba, ma, size, modules = index(name)
if not ba then
return fn_ut
elseif name == '_time' then
return fn_ut
elseif name == '_config' then
local fs_ma, fs_size = file.fscfg()
return {lfs_base = ba, lfs_mapped = ma, lfs_size = size,
fs_mapped = fs_ma, fs_size = fs_size}
elseif name == '_list' then
return modules
else
return nil
end
end,
__newindex = function(_, name, value)
error("LFS is readonly. Invalid write to LFS." .. name, 2)
end,
}
local G=getfenv()
G.LFS = setmetatable(lfs_t,lfs_t)
--[[-------------------------------------------------------------------------------
The second section adds the LFS to the require searchlist, so that you can
require a Lua module 'jean' in the LFS by simply doing require "jean". However
note that this is at the search entry following the FS searcher, so if you also
have jean.lc or jean.lua in SPIFFS, then this SPIFFS version will get loaded into
RAM instead of using. (Useful, for development).
See docs/en/lfs.md and the 'loaders' array in app/lua/loadlib.c for more details.
---------------------------------------------------------------------------------]]
package.loaders[3] = function(module) -- loader_flash
local fn, ba = index(module)
return ba and "Module not in LFS" or fn
end
--[[-------------------------------------------------------------------------------
You can add any other initialisation here, for example a couple of the globals
are never used, so setting them to nil saves a couple of global entries
---------------------------------------------------------------------------------]]
G.module = nil -- disable Lua 5.0 style modules to save RAM
package.seeall = nil
--
-- File: LFS_dummy_strings.lua
--[[
luac.cross -f generates a ROM string table which is part of the compiled LFS
image. This table includes all strings referenced in the loaded modules.
If you want to preload other string constants, then one way to achieve this is
to include a dummy module in the LFS that references the strings that you want
to load. You never need to call this module; it's inclusion in the LFS image is
enough to add the strings to the ROM table. Your application can use any strings
in the ROM table without incuring any RAM or Lua Garbage Collector (LGC)
overhead.
The local preload example is a useful starting point. However, if you call the
following code in your application during testing, then this will provide a
listing of the current RAM string table.
do
local a=debug.getstrings'RAM'
for i =1, #a do a[i] = ('%q'):format(a[i]) end
print ('local preload='..table.concat(a,','))
end
This will exclude any strings already in the ROM table, so the output is the list
of putative strings that you should consider adding to LFS ROM table.
---------------------------------------------------------------------------------]]
local preload = "?.lc;?.lua", "/\n;\n?\n!\n-", "@init.lua", "_G", "_LOADED",
"_LOADLIB", "__add", "__call", "__concat", "__div", "__eq", "__gc", "__index",
"__le", "__len", "__lt", "__mod", "__mode", "__mul", "__newindex", "__pow",
"__sub", "__tostring", "__unm", "collectgarbage", "cpath", "debug", "file",
"file.obj", "file.vol", "flash", "getstrings", "index", "ipairs", "list", "loaded",
"loader", "loaders", "loadlib", "module", "net.tcpserver", "net.tcpsocket",
"net.udpsocket", "newproxy", "package", "pairs", "path", "preload", "reload",
"require", "seeall", "wdclr", "not enough memory", "sjson.decoder","sjson.encoder",
"tmr.timer"
-- First time image boot to discover the confuration
--
-- If you want to use absolute address LFS load or SPIFFS imaging, then boot the
-- image for the first time bare, that is without either LFS or SPIFFS preloaded
-- then enter the following commands interactively through the UART:
--
do
local _,ma,fa=node.flashindex()
for n,v in pairs{LFS_MAPPED=ma, LFS_BASE=fa, SPIFFS_BASE=sa} do
print(('export %s=""0x%x"'):format(n, v))
end
end
--
-- This will print out 3 hex constants: the absolute address used in the
-- 'luac.cross -a' options and the flash adresses of the LFS and SPIFFS.
--
--[[ So you would need these commands to image your ESP module:
USB=/dev/ttyUSB0 # or whatever the device of your USB is
NODEMCU=~/nodemcu # The root of your NodeMCU file hierarchy
SRC=$NODEMCU/local/lua # your source directory for your LFS Lua files.
BIN=$NODEMCU/bin
ESPTOOL=$NODEMCU/tools/esptool.py
$ESPTOOL --port $USB erase_flash # Do this is you are having load funnies
$ESPTOOL --port $USB --baud 460800 write_flash -fm dio 0x00000 \
$BIN/0x00000.bin 0x10000 $BIN/0x10000.bin
#
# Now restart your module and use whatever your intective tool is to do the above
# cmds, so if this outputs 0x4027b000, -0x7b000, 0x100000 then you can do
#
$NODEMCU/luac.cross -a 0x4027b000 -o $BIN/0x7b000-flash.img $SRC/*.lua
$ESPTOOL --port $USB --baud 460800 write_flash -fm dio 0x7b000 \
$BIN/0x7b000-flash.img
# and if you've setup a SPIFFS then
$ESPTOOL --port $USB --baud 460800 write_flash -fm dio 0x100000 \
$BIN/0x100000-0x10000.img
# and now you are good to go
]]
-----------------------------------------------------------------------------------
--
-- File: init.lua
--
-- With the previous example you still need an init.lua to bootstrap the _init
-- module in LFS. Here is an example. It's a good idea either to use a timer
-- delay or a GPIO pin during development, so that you as developer can break into
-- the boot sequence if there is a problem with the _init bootstrap that is causing
-- a panic loop. Here is one example of how you might do this. You have a second
-- to inject tmr.stop(0) into UART0. Extend this delay if needed.
--
-- This example will also attempt to automatically load the LFS block from a SPIFFS
-- file named 'flash.img'.
--
if node.flashindex() == nil then
node.flashreload('flash.img')
end
tmr.alarm(0, 1000, tmr.ALARM_SINGLE,
function()
local fi=node.flashindex; return pcall(fi and fi'_init')
end)
......@@ -43,7 +43,7 @@ m:on("offline", function(conn)
end)
m:on("message",dispatch )
-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) )
m:connect(192.168.18.88,1883,0,1)
m:connect("192.168.18.88",1883,0,1)
-- usage:
-- another client(pc) subscribe to /topic2, will receive the test.lua content.
......
# Telnet Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2014-12-22 | [Zeroday](https://github.com/funshine) | [Terry Ellison](https://github.com/TerryE) | [simple_telnet.lua](./simple_telnet.lua) |
| 2018-05-24 | [Terry Ellison](https://github.com/TerryE) | [Terry Ellison](https://github.com/TerryE) | [telnet.lua](./telnet.lua) |
The Lua telnet example previously provided in our distro has been moved to this
file `simple_telnet.lua` in this folder. This README discusses the version complex
implementation at the Lua module `telnet.lua`. The main reason for this complex
alternative is that a single Lua command can produce a LOT of output, and the
telnet server has to work within four constraints:
- The SDK rules are that you can only issue one send per task invocation, so any
overflow must be buffered, and the buffer emptied using an on:sent callback (CB).
- Since the interpeter invokes a node.output CB per field, you have a double whammy
that these fields are typically small, so using a simple array FIFO would rapidly
exhaust RAM.
- For network efficiency, the module aggregates any FIFO buffered into sensible
sized packet, say 1024 bytes, but it must also need to handle the case when larger
string span multiple packets. However, you must flush the buffer if necessary.
- The overall buffering strategy needs to be reasonably memory efficient and avoid
hitting the GC too hard, so where practical avoid aggregating small strings to more
than 256 chars (as NodeMCU handles \<256 using stack buffers), and avoid serial
aggregation such as buf = buf .. str as this hammers the GC.
So this server adopts a simple buffering scheme using a two level FIFO. The
`node.output` CB adds records to the 1st level FIFO until the #recs is \> 32 or the
total size would exceed 256 bytes. Once over this threashold, the contents of the
FIFO are concatenated into a 2nd level FIFO entry of upto 256 bytes, and the 1st
level FIFO cleared down to any residue.
The sender dumps the 2nd level FIFO aggregating records up to 1024 bytes and once this
is empty dumps an aggrate of the 1st level.
Lastly remember that owing to architectural limitations of the firmware, this server
can only service stdin and stdout. Lua errors are still sent to stderr which is
the UART0 device. Hence errors will fail silently. If you want to capture
errors then you will need to wrap any commands in a `pcall()` and print any
error return.
## telnet:open()
Open a telnet server based on the provided parameters.
#### Syntax
`telnet:open(ssid, pwd, port)`
#### Parameters
`ssid` and `password`. Strings. SSID and Password for the Wifi network. If these are
`nil` then the wifi is assumed to be configured or autoconfigured.
`port`. Integer TCP listenting port for the Telnet service. The default is 2323
#### Returns
Nothing returned (this is evaluted as `nil` in a scalar context).
## telnet:close()
Close a telnet server and release all resources.
#### Syntax
`telnet:close()`
#### Parameters
None
#### Returns
Nothing returned (this is evaluted as `nil` in a scalar context).
--[[ A telnet server T. Ellison, May 2018
This version is more complex than the simple Lua example previously provided in our
distro. The main reason is that a single Lua command can produce a LOT of output,
and the server has to work within four constraints:
- The SDK rules are that you can only issue one send per task invocation, so any
overflow must be buffered, and the buffer emptied using an on:sent cb
- Since the interpeter invokes a node.output cb per field, you have a double
whammy that these fields are typically small, so using a simple array FIFO
would rapidly exhaust RAM.
- For network efficiency, you want to aggregate any FIFO buffered into sensible
sized packet, say 1024 bytes, but you also need to handle the case when larger
string span multiple packets. However, you must flush the buffer if necessary.
- The overall buffering strategy needs to be reasonably memory efficient and avoid
hitting the GC too hard, so where practical avoid aggregating small strings to
more than 256 chars (as NodeMCU handles <256 using stack buffers), and avoid
serial aggregation such as buf = buf .. str as this hammers the GC.
So this server adopts a simple buffering scheme using a two level FIFO. The node.output
cb adds cb records to the 1st level FIFO until the #recs is > 32 or the total size
would exceed 256 bytes. Once over this threashold, the contents of the FIFO are
concatenated into a 2nd level FIFO entry of upto 256 bytes, and the 1st level FIFO
cleared down to any residue.
The sender dumps the 2nd level FIFO aggregating records up to 1024 bytes and once this
is empty dumps an aggrate of the 1st level.
]]
local node, table, tmr, wifi, uwrite, tostring =
node, table, tmr, wifi, uart.write, tostring
local function telnet_listener(socket)
local insert, remove, concat, heap, gc =
table.insert, table.remove, table.concat, node.heap, collectgarbage
local fifo1, fifo1l, fifo2, fifo2l = {}, 0, {}, 0
local s -- s is a copy of the TCP socket if and only if sending is in progress
local wdclr, cnt = tmr.wdclr, 0
local function debug(fmt, ...)
if (...) then fmt = fmt:format(...) end
uwrite(0, "\r\nDBG: ",fmt,"\r\n" )
cnt = cnt + 1
if cnt % 10 then wdclr() end
end
local function flushGarbage()
if heap() < 13440 then gc() end
end
local function sendLine()
-- debug("entering sendLine")
if not s then return end
if fifo2l + fifo1l == 0 then -- both FIFOs empty, so clear down s
s = nil
-- debug("Q cleared")
return
end
flushGarbage()
if #fifo2 < 4 then -- Flush FIFO1 into FIFO2
insert(fifo2,concat(fifo1))
-- debug("flushing %u bytes / %u recs of FIFO1 into FIFO2[%u]", fifo1l, #fifo1, #fifo2)
fifo2l, fifo1, fifo1l = fifo2l + fifo1l, {}, 0
end
-- send out first 4 FIFO2 recs (or all if #fifo2<5)
local rec = remove(fifo2,1) .. (remove(fifo2,1) or '') ..
(remove(fifo2,1) or '') .. (remove(fifo2,1) or '')
fifo2l = fifo2l - #rec
flushGarbage()
s:send(rec)
-- debug( "sending %u bytes (%u buffers remain)\r\n%s ", #rec, #fifo2, rec)
end
local F1_SIZE = 256
local function queueLine(str)
-- Note that this algo does work for strings longer than 256 but it is sub-optimal
-- as it does string splitting, but this isn't really an issue IMO, as in practice
-- fields of this size are very infrequent.
-- debug("entering queueLine(l=%u)", #str)
while #str > 0 do -- this is because str might be longer than the packet size!
local k, l = F1_SIZE - fifo1l, #str
local chunk
-- Is it time to batch up and flush FIFO1 into a new FIFO2 entry? Note that it's
-- not worth splitting a string to squeeze the last ounce out of a buffer size.
-- debug("#fifo1 = %u, k = %u, l = %u", #fifo1, k, l)
if #fifo1 >= 32 or (k < l and k < 16) then
insert(fifo2, concat(fifo1))
-- debug("flushing %u bytes / %u recs of FIFO1 into FIFO2[%u]", fifo1l, #fifo1, #fifo2)
fifo2l, fifo1, fifo1l, k = fifo2l + fifo1l, {}, 0, F1_SIZE
end
if l > k+16 then -- also tolerate a size overrun of 16 bytes to avoid a split
chunk, str = str:sub(1,k), str:sub(k+1)
else
chunk, str = str, ''
end
-- debug("pushing %u bytes into FIFO1[l=%u], %u bytes remaining", #chunk, fifo1l, #str)
insert(fifo1, chunk)
fifo1l = fifo1l + #chunk
end
if not s and socket then
s = socket
sendLine()
else
flushGarbage()
end
end
local function receiveLine(s, line)
-- debug( "received: %s", line)
node.input(line)
end
local function disconnect(s)
fifo1, fifo1l, fifo2, fifo2l, s = {}, 0, {}, 0, nil
node.output(nil)
end
socket:on("receive", receiveLine)
socket:on("disconnection", disconnect)
socket:on("sent", sendLine)
node.output(queueLine, 0)
end
local listenerSocket
return {
open = function(this, ssid, pwd, port)
if ssid then
wifi.setmode(wifi.STATION, false)
wifi.sta.config { ssid = ssid, pwd = pwd, save = false }
end
tmr.alarm(0, 500, tmr.ALARM_AUTO, function()
if (wifi.sta.status() == wifi.STA_GOTIP) then
tmr.unregister(0)
print("Welcome to NodeMCU world", node.heap(), wifi.sta.getip())
net.createServer(net.TCP, 180):listen(port or 2323, telnet_listener)
else
uwrite(0,".")
end
end)
end,
close = function(this)
if listenerSocket then
listenerSocket:close()
package.loaded.telnet = nil
listenerSocket = nil
collectgarbage()
end
end,
}
-- ***************************************************************************
-- Graphics Test
--
-- This script executes several features of u8glib to test their Lua bindings.
--
-- Note: It is prepared for SSD1306-based displays. Select your connectivity
-- type by calling either init_i2c_display() or init_spi_display() at
-- the bottom of this file.
--
-- ***************************************************************************
-- setup I2c and connect display
function init_i2c_display()
-- SDA and SCL can be assigned freely to available GPIOs
local sda = 5 -- GPIO14
local scl = 6 -- GPIO12
local sla = 0x3c
i2c.setup(0, sda, scl, i2c.SLOW)
disp = u8g2.ssd1306_i2c_128x64_noname(0, sla)
end
-- setup SPI and connect display
function init_spi_display()
-- Hardware SPI CLK = GPIO14
-- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used)
-- Hardware SPI /CS = GPIO15 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs
local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2
local res = 0 -- GPIO16
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
-- we won't be using the HSPI /CS line, so disable it again
gpio.mode(8, gpio.INPUT, gpio.PULLUP)
disp = u8g2.ssd1306_128x64_noname(1, cs, dc, res)
end
function u8g2_prepare()
disp:setFont(u8g2.font_6x10_tf)
disp:setFontRefHeightExtendedText()
disp:setDrawColor(1)
disp:setFontPosTop()
disp:setFontDirection(0)
end
function u8g2_box_frame(a)
disp:drawStr( 0, 0, "drawBox")
disp:drawBox(5,10,20,10)
disp:drawBox(10+a,15,30,7)
disp:drawStr( 0, 30, "drawFrame")
disp:drawFrame(5,10+30,20,10)
disp:drawFrame(10+a,15+30,30,7)
end
function u8g2_disc_circle(a)
disp:drawStr( 0, 0, "drawDisc")
disp:drawDisc(10,18,9)
disp:drawDisc(24+a,16,7)
disp:drawStr( 0, 30, "drawCircle")
disp:drawCircle(10,18+30,9)
disp:drawCircle(24+a,16+30,7)
end
function u8g2_r_frame(a)
disp:drawStr( 0, 0, "drawRFrame/Box")
disp:drawRFrame(5, 10,40,30, a+1)
disp:drawRBox(50, 10,25,40, a+1)
end
function u8g2_string(a)
disp:setFontDirection(0)
disp:drawStr(30+a,31, " 0")
disp:setFontDirection(1)
disp:drawStr(30,31+a, " 90")
disp:setFontDirection(2)
disp:drawStr(30-a,31, " 180")
disp:setFontDirection(3)
disp:drawStr(30,31-a, " 270")
end
function u8g2_line(a)
disp:drawStr( 0, 0, "drawLine")
disp:drawLine(7+a, 10, 40, 55)
disp:drawLine(7+a*2, 10, 60, 55)
disp:drawLine(7+a*3, 10, 80, 55)
disp:drawLine(7+a*4, 10, 100, 55)
end
function u8g2_triangle(a)
local offset = a
disp:drawStr( 0, 0, "drawTriangle")
disp:drawTriangle(14,7, 45,30, 10,40)
disp:drawTriangle(14+offset,7-offset, 45+offset,30-offset, 57+offset,10-offset)
disp:drawTriangle(57+offset*2,10, 45+offset*2,30, 86+offset*2,53)
disp:drawTriangle(10+offset,40+offset, 45+offset,30+offset, 86+offset,53+offset)
end
function u8g2_ascii_1()
disp:drawStr( 0, 0, "ASCII page 1")
for y = 0, 5 do
for x = 0, 15 do
disp:drawStr(x*7, y*10+10, string.char(y*16 + x + 32))
end
end
end
function u8g2_ascii_2()
disp:drawStr( 0, 0, "ASCII page 2")
for y = 0, 5 do
for x = 0, 15 do
disp:drawStr(x*7, y*10+10, string.char(y*16 + x + 160))
end
end
end
function u8g2_extra_page(a)
disp:drawStr( 0, 0, "Unicode")
disp:setFont(u8g2.font_unifont_t_symbols)
disp:setFontPosTop()
disp:drawUTF8(0, 24, "☀ ☁")
if a <= 3 then
disp:drawUTF8(a*3, 36, "☂")
else
disp:drawUTF8(a*3, 36, "☔")
end
end
cross_width = 24
cross_height = 24
cross_bits = string.char(
0x00, 0x18, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x42, 0x00,
0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00,
0xC0, 0x00, 0x03, 0x38, 0x3C, 0x1C, 0x06, 0x42, 0x60, 0x01, 0x42, 0x80,
0x01, 0x42, 0x80, 0x06, 0x42, 0x60, 0x38, 0x3C, 0x1C, 0xC0, 0x00, 0x03,
0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00,
0x00, 0x42, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x18, 0x00)
cross_fill_width = 24
cross_fill_height = 24
cross_fill_bits = string.char(
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x64, 0x00, 0x26,
0x84, 0x00, 0x21, 0x08, 0x81, 0x10, 0x08, 0x42, 0x10, 0x10, 0x3C, 0x08,
0x20, 0x00, 0x04, 0x40, 0x00, 0x02, 0x80, 0x00, 0x01, 0x80, 0x18, 0x01,
0x80, 0x18, 0x01, 0x80, 0x00, 0x01, 0x40, 0x00, 0x02, 0x20, 0x00, 0x04,
0x10, 0x3C, 0x08, 0x08, 0x42, 0x10, 0x08, 0x81, 0x10, 0x84, 0x00, 0x21,
0x64, 0x00, 0x26, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
cross_block_width = 14
cross_block_height = 14
cross_block_bits = string.char(
0xFF, 0x3F, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20,
0xC1, 0x20, 0xC1, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20,
0x01, 0x20, 0xFF, 0x3F)
function u8g2_bitmap_overlay(a)
local frame_size = 28
disp:drawStr(0, 0, "Bitmap overlay")
disp:drawStr(0, frame_size + 12, "Solid / transparent")
disp:setBitmapMode(0) -- solid
disp:drawFrame(0, 10, frame_size, frame_size)
disp:drawXBM(2, 12, cross_width, cross_height, cross_bits)
if bit.band(a, 4) > 0 then
disp:drawXBM(7, 17, cross_block_width, cross_block_height, cross_block_bits)
end
disp:setBitmapMode(1) -- transparent
disp:drawFrame(frame_size + 5, 10, frame_size, frame_size)
disp:drawXBM(frame_size + 7, 12, cross_width, cross_height, cross_bits)
if bit.band(a, 4) then
disp:drawXBM(frame_size + 12, 17, cross_block_width, cross_block_height, cross_block_bits)
end
end
function u8g2_bitmap_modes(transparent)
local frame_size = 24
disp:drawBox(0, frame_size * 0.5, frame_size * 5, frame_size)
disp:drawStr(frame_size * 0.5, 50, "Black")
disp:drawStr(frame_size * 2, 50, "White")
disp:drawStr(frame_size * 3.5, 50, "XOR")
if transparent == 0 then
disp:setBitmapMode(0) -- solid
disp:drawStr(0, 0, "Solid bitmap")
else
disp:setBitmapMode(1) -- transparent
disp:drawStr(0, 0, "Transparent bitmap")
end
disp:setDrawColor(0) -- Black
disp:drawXBM(frame_size * 0.5, 24, cross_width, cross_height, cross_bits)
disp:setDrawColor(1) -- White
disp:drawXBM(frame_size * 2, 24, cross_width, cross_height, cross_bits)
disp:setDrawColor(2) -- XOR
disp:drawXBM(frame_size * 3.5, 24, cross_width, cross_height, cross_bits)
end
function draw()
u8g2_prepare()
local d3 = bit.rshift(draw_state, 3)
local d7 = bit.band(draw_state, 7)
if d3 == 0 then
u8g2_box_frame(d7)
elseif d3 == 1 then
u8g2_disc_circle(d7)
elseif d3 == 2 then
u8g2_r_frame(d7)
elseif d3 == 3 then
u8g2_string(d7)
elseif d3 == 4 then
u8g2_line(d7)
elseif d3 == 5 then
u8g2_triangle(d7)
elseif d3 == 6 then
u8g2_ascii_1()
elseif d3 == 7 then
u8g2_ascii_2()
elseif d3 == 8 then
u8g2_extra_page(d7)
elseif d3 == 9 then
u8g2_bitmap_modes(0)
elseif d3 == 10 then
u8g2_bitmap_modes(1)
elseif d3 == 11 then
u8g2_bitmap_overlay(d7)
end
end
function loop()
-- picture loop
disp:clearBuffer()
draw()
disp:sendBuffer()
-- increase the state
draw_state = draw_state + 1
if draw_state >= 12*8 then
draw_state = 0
end
-- delay between each frame
loop_tmr:start()
end
draw_state = 0
loop_tmr = tmr.create()
loop_tmr:register(100, tmr.ALARM_SEMI, loop)
init_i2c_display()
--init_spi_display()
print("--- Starting Graphics Test ---")
loop_tmr:start()
-- ***************************************************************************
-- Bitmaps Test
--
-- This script executes the bitmap features of u8glib to test their Lua
-- integration.
--
-- Note: It is prepared for SSD1306-based displays. Select your connectivity
-- type by calling either init_i2c_display() or init_spi_display() at
-- the bottom of this file.
--
-- ***************************************************************************
-- setup I2c and connect display
function init_i2c_display()
-- SDA and SCL can be assigned freely to available GPIOs
local sda = 5 -- GPIO14
local scl = 6 -- GPIO12
local sla = 0x3c
i2c.setup(0, sda, scl, i2c.SLOW)
disp = u8g.ssd1306_128x64_i2c(sla)
end
-- setup SPI and connect display
function init_spi_display()
-- Hardware SPI CLK = GPIO14
-- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used)
-- Hardware SPI /CS = GPIO15 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs
local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2
local res = 0 -- GPIO16
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
-- we won't be using the HSPI /CS line, so disable it again
gpio.mode(8, gpio.INPUT, gpio.PULLUP)
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
end
function xbm_picture()
disp:setFont(u8g.font_6x10)
disp:drawStr( 0, 10, "XBM picture")
disp:drawXBM( 0, 20, 38, 24, xbm_data )
end
function bitmap_picture(state)
disp:setFont(u8g.font_6x10)
disp:drawStr( 0, 10, "Bitmap picture")
disp:drawBitmap( 0 + (state * 10), 20 + (state * 4), 1, 8, bm_data )
end
-- the draw() routine
function draw(draw_state)
local component = bit.rshift(draw_state, 3)
if (component == 0) then
xbm_picture(bit.band(draw_state, 7))
elseif (component == 1) then
bitmap_picture(bit.band(draw_state, 7))
end
end
function draw_loop()
-- Draws one page and schedules the next page, if there is one
local function draw_pages()
draw(draw_state)
if disp:nextPage() then
node.task.post(draw_pages)
else
node.task.post(bitmap_test)
end
end
-- Restart the draw loop and start drawing pages
disp:firstPage()
node.task.post(draw_pages)
end
function bitmap_test()
if (draw_state <= 7 + 1*8) then
draw_state = draw_state + 1
else
print("--- Restarting Bitmap Test ---")
draw_state = 1
end
print("Heap: " .. node.heap())
-- retrigger draw_loop
node.task.post(draw_loop)
end
draw_state = 1
init_i2c_display()
--init_spi_display()
-- read XBM picture
file.open("u8glib_logo.xbm", "r")
xbm_data = file.read()
file.close()
-- read Bitmap picture
file.open("u8g_rook.bm", "r")
bm_data = file.read()
file.close()
print("--- Starting Bitmap Test ---")
node.task.post(draw_loop)
------------------------------------------------------------------------------
-- u8glib example which shows how to implement the draw loop without causing
-- timeout issues with the WiFi stack. This is done by drawing one page at
-- a time, allowing the ESP SDK to do its house keeping between the page
-- draws.
--
-- This example assumes you have an SSD1306 display connected to pins 4 and 5
-- using I2C and that the profont22r is compiled into the firmware.
-- Please edit the init_display function to match your setup.
--
-- Example:
-- dofile("u8g_drawloop.lua")
------------------------------------------------------------------------------
local disp
local font
function init_display()
local sda = 4
local sdl = 5
local sla = 0x3c
i2c.setup(0,sda,sdl, i2c.SLOW)
disp = u8g.ssd1306_128x64_i2c(sla)
font = u8g.font_profont22r
end
local function setLargeFont()
disp:setFont(font)
disp:setFontRefHeightExtendedText()
disp:setDefaultForegroundColor()
disp:setFontPosTop()
end
-- Start the draw loop with the draw implementation in the provided function callback
function updateDisplay(func)
-- Draws one page and schedules the next page, if there is one
local function drawPages()
func()
if (disp:nextPage() == true) then
node.task.post(drawPages)
end
end
-- Restart the draw loop and start drawing pages
disp:firstPage()
node.task.post(drawPages)
end
function drawHello()
setLargeFont()
disp:drawStr(30,22, "Hello")
end
function drawWorld()
setLargeFont()
disp:drawStr(30,22, "World")
end
local drawDemo = { drawHello, drawWorld }
function demoLoop()
-- Start the draw loop with one of the demo functions
local f = table.remove(drawDemo,1)
updateDisplay(f)
table.insert(drawDemo,f)
end
-- Initialise the display
init_display()
-- Draw demo page immediately and then schedule an update every 5 seconds.
-- To test your own drawXYZ function, disable the next two lines and call updateDisplay(drawXYZ) instead.
demoLoop()
tmr.alarm(4, 5000, 1, demoLoop)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment