Commit 4911d2db authored by Arnim Läuger's avatar Arnim Läuger
Browse files

Merge pull request #1336 from nodemcu/dev

1.5.1 master drop
parents c8037568 2e109686
The [issues list on GitHub](https://github.com/nodemcu/nodemcu-firmware/issues) is **not** the right place to ask for help. Use it to report bugs and to place feature requests. Questions like "how do I ..." or "I can't get this to work ..." should be directed to StackOverflow or esp8266.com.
Which ever site you use you need to make sure the description of the problem is to the point. It should be accompanied by a stripped down version of your Lua source code i.e. create a Minimal, Complete, and Verifiable Example (MCVE). A good resource is [http://stackoverflow.com/help/how-to-ask](http://stackoverflow.com/help/how-to-ask)
## StackOverflow
StackOverflow is the perfect place to ask coding questions. Use one or several of the following tags: [esp8266](http://stackoverflow.com/tags/esp8266), [nodemcu](http://stackoverflow.com/tags/nodemcu) or [Lua](http://stackoverflow.com/tags/lua).
## esp8266.com Forums
esp8266.com has a few [NodeMCU specific forums](http://www.esp8266.com/viewforum.php?f=17) where a number of our active community members tend to hang out.
\ No newline at end of file
As with [flashing](flash.md) there are several ways to upload code from your computer to the device.
Note that the NodeMCU serial interface uses 115200bps at boot time. To change the speed after booting, issue `uart.setup(0,9600,8,0,1,1)`. ESPlorer will do this automatically when changing the speed in the dropdown list. If the device panics and resets at any time, errors will be written to the serial interface at 115200 bps.
# ESPlorer
> The essential multiplatforms tools for any ESP8266 developer from luatool author’s, including Lua for NodeMCU and MicroPython. Also, all AT commands are supported. Requires Java (Standard Edition - SE ver 7 and above) installed.
![ESPlorer](../img/ESPlorer.jpg "ESPlorer")
Source: [https://github.com/4refr0nt/ESPlorer](https://github.com/4refr0nt/ESPlorer)
Supported platforms: OS X, Linux, Windows, anything that runs Java
# nodemcu-uploader.py
> A simple tool for uploading files to the filesystem of an ESP8266 running NodeMCU as well as some other useful commands.
Source: [https://github.com/kmpm/nodemcu-uploader](https://github.com/kmpm/nodemcu-uploader)
Supported platforms: OS X, Linux, Windows, anything that runs Python
# NodeMCU Studio
> THIS TOOL IS IN REALLY REALLY REALLY REALLY EARLY STAGE!!!!!!!!!!!!!!!!!!!!!!!!!!!
Source: [https://github.com/nodemcu/nodemcu-studio-csharp](https://github.com/nodemcu/nodemcu-studio-csharp)
Supported platforms: Windows
# luatool
> Allow easy uploading of any Lua-based script into the ESP8266 flash memory with NodeMcu firmware
Source: [https://github.com/4refr0nt/luatool](https://github.com/4refr0nt/luatool)
Supported platforms: OS X, Linux, Windows, anything that runs Python
# 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.
# NodeMCU Documentation
NodeMCU is an [eLua](http://www.eluaproject.net/) based firmware for the [ESP8266 WiFi SOC from Espressif](http://espressif.com/en/products/esp8266/). The NodeMCU *firmware* is a companion project to the popular [NodeMCU dev kits](https://github.com/nodemcu/nodemcu-devkit-v1.0), ready-made open source development boards with ESP8266-12E chips.
## Up-To-Date Documentation
At the moment the only up-to-date documentation maintained by the current NodeMCU team is in [English](en/index.md). It is part of the source code repository (`/docs` subfolder) and kept in sync with the code.
We encourage you to help transferring the outdated translations (see below) into the repository.
## Outdated And Sparse Documentation
The following translations are based on outdated documentation, use them with caution. The links point to the [NodeMCU wiki on GitHub](https://github.com/nodemcu/nodemcu-firmware/wiki).
- Chinese, [中文](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_cn)
- Russian, [русский](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_ru)
- Spanish, [español](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_es)
\ No newline at end of file
var nodemcu = nodemcu || {};
(function () {
'use strict';
//var languageCodeToNameMap = {en: 'English', de: 'Deutsch'};
var languageCodeToNameMap = {en: 'English'};
var languageNames = values(languageCodeToNameMap);
var defaultLanguageCode = 'en';
$(document).ready(function () {
addToc();
hideNavigationForAllButSelectedLanguage();
addLanguageSelectorToRtdFlyOutMenu();
replaceRelativeLinksWithStaticGitHubUrl();
});
/**
* Adds a TOC-style table to each page in the 'Modules' section.
*/
function addToc() {
var func, intro, tocHtmlTable;
if (isModulePage()) {
tocHtmlTable = '<table class="docutils">';
$('h2').each(function (index) {
// 'slice' cuts off the single permalink character at the end of the text (e.g. '¶')
func = $(this).text().slice(0, -1);
// get the first sentence of the paragraph directly below h2
intro = $(this).next().text();
intro = intro.substring(0, intro.indexOf('.') + 1);
tocHtmlTable += createTocTableRow(func, intro);
});
tocHtmlTable += '</table>';
$(tocHtmlTable).insertBefore($('h2').first())
}
function isModulePage() {
// if the breadcrumb contains 'Modules »' it must be an API page
return $("ul.wy-breadcrumbs li:contains('Modules »')").size() > 0;
}
function createTocTableRow(func, intro) {
// fragile attempt to auto-create the in-page anchor
var href = func.replace(/\.|:/g, '').replace('()', '').replace(' --', '-').replace(/ /g, '-');
var link = '<a href="#' + href.toLowerCase() + '">' + func + '</a>';
return '<tr><td>' + link + '</td><td>' + intro + '</td></tr>';
}
}
function hideNavigationForAllButSelectedLanguage() {
var selectedLanguageCode = determineSelectedLanguageCode();
var selectedLanguageName = languageCodeToNameMap[selectedLanguageCode];
// Finds all subnav elements and hides them if they're /language/ subnavs. Hence, all 'Modules' subnav elements
// won't be hidden.
// <ul class="subnav">
// <li><span>Modules</span></li>
// <li class="toctree-l1 ">
// <a class="" href="EN/modules/node/">node</a>
// </li>
$('.subnav li span').not(':contains(' + selectedLanguageName + ')').each(function (index) {
var spanElement = $(this);
if ($.inArray(spanElement.text(), languageNames) > -1) {
spanElement.parent().parent().hide();
}
});
}
/**
* Adds a language selector to the RTD fly-out menu found bottom left. Example:
*
* <dl>
* <dt>Languages</dt>
* <dd><a href="http://nodemcu.readthedocs.io/en/<branch>/de/">de</a></dd>
* <strong>
* <dd><a href="http://nodemcu.readthedocs.io/en/<branch>/en/">en</a></dd>
* </strong>
* </dl>
*
* UGLY! That fly-out menu is added by RTD with an AJAX call after page load. Hence, we need to
* react to the subsequent DOM manipulation using a DOM4 MutationObserver. The provided structure
* is as follows:
*
* <div class="rst-other-versions">
* <!-- Inserted RTD Footer -->
* <div class="injected">
*/
function addLanguageSelectorToRtdFlyOutMenu() {
var flyOutWrapper = $('.rst-other-versions');
// only relevant on RTD
if (flyOutWrapper.size() > 0) {
var observer = new MutationObserver(function (mutations) {
// since mutation on the target node was triggered we can safely assume the injected RTD div has now been added
var injectedDiv = $('.rst-other-versions .injected');
var selectedLanguageCode = determineSelectedLanguageCode();
var dl = document.createElement('dl');
var dt = document.createElement('dt');
dl.appendChild(dt);
dt.appendChild(document.createTextNode('Languages'));
for (var languageCode in languageCodeToNameMap) {
dl.appendChild(createLanguageLinkFor(languageCode, selectedLanguageCode === languageCode));
}
injectedDiv.prepend(dl);
// no need for that observer anymore
observer.disconnect();
});
// observed target node is the fly-out wrapper, the only event we care about is when children are modified
observer.observe(flyOutWrapper[0], {childList: true});
}
}
/**
* The module doc pages contain relative links to artifacts in the GitHub repository. For those links to work both
* on GitHub (i.e. when the page is viewed on GitHub) and on RTD they are defined with a relative URL. This function
* replaces the relative path with an absolute path based on the selected branch.
*/
function replaceRelativeLinksWithStaticGitHubUrl() {
var relativePath = "../../../..";
var gitHubPath = "https://github.com/nodemcu/nodemcu-firmware/tree/" + determineSelectedBranch();
var gitHubLinks = $("a[href^='" + relativePath + "']").each(function (index) {
var url = $(this).attr('href');
$(this).attr('href', url.replace(relativePath, gitHubPath));
});
}
function createLanguageLinkFor(languageCode, isCurrentlySelected) {
var strong;
// split[0] is an '' because the path starts with the separator
var pathSegments = window.location.pathname.split('/');
var dd = document.createElement("dd");
var href = document.createElement("a");
href.setAttribute('href', '/' + pathSegments[1] + '/' + pathSegments[2] + '/' + languageCode);
href.appendChild(document.createTextNode(languageCode));
dd.appendChild(href);
if (isCurrentlySelected) {
strong = document.createElement("strong");
strong.appendChild(dd);
return strong;
} else {
return dd;
}
}
/**
* Analyzes the URL of the current page to find out what the selected language is. It's usually
* part of the location path. The code needs to distinguish between running MkDocs standalone
* and docs served from RTD. If no valid language could be determined the default language is
* returned.
*
* @returns 2-char language code
*/
function determineSelectedLanguageCode() {
var selectedLanguageCode, path = window.location.pathname;
if (window.location.origin.indexOf('readthedocs') > -1) {
// path is like /en/<branch>/<lang>/build/ -> extract 'lang'
// split[0] is an '' because the path starts with the separator
selectedLanguageCode = path.split('/')[3];
} else {
// path is like /<lang>/build/ -> extract 'lang'
selectedLanguageCode = path.substr(1, 2);
}
if (!selectedLanguageCode || selectedLanguageCode.length > 2) {
selectedLanguageCode = defaultLanguageCode;
}
return selectedLanguageCode;
}
/**
* Analyzes the URL of the current page to find out what the selected GitHub branch is. It's usually
* part of the location path. The code needs to distinguish between running MkDocs standalone
* and docs served from RTD. If no valid branch could be determined 'dev' returned.
*
* @returns GitHub branch name
*/
function determineSelectedBranch() {
var branch = 'dev', path = window.location.pathname;
if (window.location.origin.indexOf('readthedocs') > -1) {
// path is like /en/<branch>/<lang>/build/ -> extract 'lang'
// split[0] is an '' because the path starts with the separator
branch = path.split('/')[2];
}
return branch;
}
function values(associativeArray) {
var values = [];
for (var key in associativeArray) {
if (associativeArray.hasOwnProperty(key)) {
values.push(associativeArray[key]);
}
}
return values;
}
}());
\ No newline at end of file
-- a simple telnet server
s=net.createServer(net.TCP,180)
s:listen(2323,function(c)
function s_output(str)
if(c~=nil)
then c:send(str)
end
end
node.output(s_output, 0) -- re-direct output to function s_ouput.
c:on("receive",function(c,l)
node.input(l) -- works like pcall(loadstring(l)) but support multiple separate line
end)
c:on("disconnection",function(c)
node.output(nil) -- un-regist the redirect output function, output goes to serial
end)
print("Welcome to NodeMcu world.")
end)
\ No newline at end of file
print("====Wicon, a LUA console over wifi.==========")
print("Author: openthings@163.com. copyright&GPL V2.")
print("Last modified 2014-11-19. V0.2")
print("Wicon Server starting ......")
function startServer()
print("Wifi AP connected. Wicon IP:")
print(wifi.sta.getip())
sv=net.createServer(net.TCP, 180)
sv:listen(8080, function(conn)
print("Wifi console connected.")
function s_output(str)
if (conn~=nil) then
conn:send(str)
end
end
node.output(s_output,0)
conn:on("receive", function(conn, pl)
node.input(pl)
if (conn==nil) then
print("conn is nil.")
end
end)
conn:on("disconnection",function(conn)
node.output(nil)
end)
end)
print("Wicon Server running at :8080")
print("===Now,Using xcon_tcp logon and input LUA.====")
end
tmr.alarm(0, 1000, 1, function()
if wifi.sta.getip()=="0.0.0.0" then
print("Connect AP, Waiting...")
else
startServer()
tmr.stop()
end
end)
...@@ -71,9 +71,11 @@ SECTIONS ...@@ -71,9 +71,11 @@ SECTIONS
_dport0_data_end = ABSOLUTE(.); _dport0_data_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr } >dport0_0_seg :dport0_0_phdr
.irom0.text : ALIGN(4) .irom0.text : ALIGN(0x1000)
{ {
_irom0_text_start = ABSOLUTE(.); _irom0_text_start = ABSOLUTE(.);
*(.servercert.flash)
*(.clientcert.flash)
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
*(.literal.* .text.*) *(.literal.* .text.*)
*(.rodata*) *(.rodata*)
...@@ -89,50 +91,18 @@ SECTIONS ...@@ -89,50 +91,18 @@ SECTIONS
KEEP(*(.lua_rotable)) KEEP(*(.lua_rotable))
LONG(0) LONG(0) /* Null-terminate the array */ LONG(0) LONG(0) /* Null-terminate the array */
/* These are *only* pulled in by Lua, and therefore safe to put in flash */ /* SDK doesn't use libc functions, and are therefore safe to put in flash */
*/libc.a:lib_a-isalnum.o(.text* .literal*) */libc.a:*.o(.text* .literal*)
*/libc.a:lib_a-isalpha.o(.text* .literal*) /* end libc functions */
*/libc.a:lib_a-iscntrl.o(.text* .literal*)
*/libc.a:lib_a-isspace.o(.text* .literal*)
*/libc.a:lib_a-islower.o(.text* .literal*)
*/libc.a:lib_a-isupper.o(.text* .literal*)
*/libc.a:lib_a-ispunct.o(.text* .literal*)
*/libc.a:lib_a-isxdigit.o(.text* .literal*)
*/libc.a:lib_a-locale.o(.text* .literal*)
*/libc.a:lib_a-tolower.o(.text* .literal*)
*/libc.a:lib_a-toupper.o(.text* .literal*)
*/libc.a:lib_a-strcasecmp.o(.text* .literal*)
*/libc.a:lib_a-strcoll.o(.text* .literal*)
*/libc.a:lib_a-strchr.o(.text* .literal*)
*/libc.a:lib_a-strrchr.o(.text* .literal*)
*/libc.a:lib_a-strcat.o(.text* .literal*)
*/libc.a:lib_a-strncat.o(.text* .literal*)
*/libc.a:lib_a-strcspn.o(.text* .literal*)
*/libc.a:lib_a-strtol.o(.text* .literal*)
*/libc.a:lib_a-strtoul.o(.text* .literal*)
*/libc.a:lib_a-strpbrk.o(.text* .literal*)
*/libc.a:lib_a-memchr.o(.text* .literal*)
*/libc.a:lib_a-setjmp.o(.text* .literal*)
/* end Lua C lib functions */
_irom0_text_end = ABSOLUTE(.); _irom0_text_end = ABSOLUTE(.);
_flash_used_end = ABSOLUTE(.); _flash_used_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr } >irom0_0_seg :irom0_0_phdr =0xffffffff
.data : ALIGN(4) .data : ALIGN(4)
{ {
_data_start = ABSOLUTE(.); _data_start = ABSOLUTE(.);
*(.data) *(.data)
/* Hook for randomizing TCP start numbers */
. = ALIGN(2);
_tcp_new_port_port = ABSOLUTE(.);
*/liblwip.a:tcp.o(.port)
/* Verify that the LWIP source has been patched as needed, or fail with
* a divide by zero error (../ld/nodemcu.ld:xxx / by zero) */
_tcp_new_port_port_size = ABSOLUTE(.) - _tcp_new_port_port;
_ensure_tcp_port_randomization_fix_presence = 1 / _tcp_new_port_port_size;
*(.data.*) *(.data.*)
*(.gnu.linkonce.d.*) *(.gnu.linkonce.d.*)
*(.data1) *(.data1)
......
-- Support HTTP and HTTPS, For example
-- HTTP POST Example with JSON header and body
http.post("http://somewhere.acceptjson.com/",
"Content-Type: application/json\r\n",
"{\"hello\":\"world\"}",
function(code, data)
print(code)
print(data)
end)
-- HTTPS GET Example with NULL header
http.get("https://www.vowstar.com/nodemcu/","",
function(code, data)
print(code)
print(data)
end)
-- You will get
-- > 200
-- hello nodemcu
-- HTTPS DELETE Example with NULL header and body
http.delete("https://10.0.0.2:443","","",
function(code, data)
print(code)
print(data)
end)
-- HTTPS PUT Example with NULL header and body
http.put("https://testput.somewhere/somewhereyouput.php","","",
function(code, data)
print(code)
print(data)
end)
-- HTTP RAW Request Example, use more HTTP/HTTPS request method
http.request("http://www.apple.com:80/library/test/success.html","GET","","",
function(code, data)
print(code)
print(data)
end)
--
-- Simple NodeMCU web server (done is a not so nodeie fashion :-)
--
-- Highly modified by Bruce Meacham, based on work by Scott Beasley 2015
-- Open and free to change and use. Enjoy. [Beasley/Meacham 2015]
--
-- Meacham Update: I streamlined/improved the parsing to focus on simple HTTP GET request and their simple parameters
-- Also added the code to drive a servo/light. Comment out as you see fit.
--
-- Usage:
-- Change SSID and SSID_PASSPHRASE for your wifi network
-- Download to NodeMCU
-- node.compile("http_server.lua")
-- dofile("http_server.lc")
-- When the server is esablished it will output the IP address.
-- http://{ip address}/?s0=1200&light=1
-- s0 is the servo position (actually the PWM hertz), 500 - 2000 are all good values
-- light chanel high(1)/low(0), some evaluation boards have LEDs pre-wired in a "pulled high" confguration, so '0' ground the emitter and turns it on backwards.
--
-- Add to init.lua if you want it to autoboot.
--
-- Your Wifi connection data
local SSID = "YOUR WIFI SSID"
local SSID_PASSWORD = "YOUR SSID PASSPHRASE"
-- General setup
local pinLight = 2 -- this is GPIO4
gpio.mode(pinLight,gpio.OUTPUT)
gpio.write(pinLight,gpio.HIGH)
servo = {}
servo.pin = 4 --this is GPIO2
servo.value = 1500
servo.id = "servo"
gpio.mode(servo.pin, gpio.OUTPUT)
gpio.write(servo.pin, gpio.LOW)
-- This alarm drives the servo
tmr.alarm(0,10,1,function() -- 50Hz
if servo.value then -- generate pulse
gpio.write(servo.pin, gpio.HIGH)
tmr.delay(servo.value)
gpio.write(servo.pin, gpio.LOW)
end
end)
local function connect (conn, data)
local query_data
conn:on ("receive",
function (cn, req_data)
params = get_http_req (req_data)
cn:send("HTTP/1.1 200/OK\r\nServer: NodeLuau\r\nContent-Type: text/html\r\n\r\n")
cn:send ("<h1>ESP8266 Servo &amp; Light Server</h1>\r\n")
if (params["light"] ~= nil) then
if ("0" == params["light"]) then
gpio.write(pinLight, gpio.LOW)
else
gpio.write(pinLight, gpio.HIGH)
end
end
if (params["s0"] ~= nil) then
servo.value = tonumber(params["s0"]);
end
-- Close the connection for the request
cn:close ( )
end)
end
-- Build and return a table of the http request data
function get_http_req (instr)
local t = {}
local str = string.sub(instr, 0, 200)
local v = string.gsub(split(str, ' ')[2], '+', ' ')
parts = split(v, '?')
local params = {}
if (table.maxn(parts) > 1) then
for idx,part in ipairs(split(parts[2], '&')) do
parmPart = split(part, '=')
params[parmPart[1]] = parmPart[2]
end
end
return params
end
-- Source: http://lua-users.org/wiki/MakingLuaLikePhp
-- Credit: http://richard.warburton.it/
function split(str, splitOn)
if (splitOn=='') then return false end
local pos,arr = 0,{}
for st,sp in function() return string.find(str,splitOn,pos,true) end do
table.insert(arr,string.sub(str,pos,st-1))
pos = sp + 1
end
table.insert(arr,string.sub(str,pos))
return arr
end
-- Configure the ESP as a station (client)
wifi.setmode (wifi.STATION)
wifi.sta.config (SSID, SSID_PASSWORD)
wifi.sta.autoconnect (1)
-- Hang out until we get a wifi connection before the httpd server is started.
tmr.alarm (1, 800, 1, function ( )
if wifi.sta.getip ( ) == nil then
print ("Waiting for Wifi connection")
else
tmr.stop (1)
print ("Config done, IP is " .. wifi.sta.getip ( ))
end
end)
-- Create the httpd server
svr = net.createServer (net.TCP, 30)
-- Server listening on port 80, call connect function if a request is received
svr:listen (80, connect)
print("====Wicon, a LUA console over wifi.==========") -- a simple telnet server
print("Author: openthings@163.com. copyright&GPL V2.")
print("Last modified 2014-11-19. V0.2")
print("Wicon Server starting ......")
function connected(conn) telnet_srv = net.createServer(net.TCP, 180)
print("Wifi console connected.") telnet_srv:listen(2323, function(socket)
function s_output(str) local fifo = {}
if (conn~=nil) then local fifo_drained = true
conn:send(str)
end
end
node.output(s_output,0)
conn:on("receive", function(conn, pl)
node.input(pl)
end)
conn:on("disconnection",function(conn)
node.output(nil)
end)
print("Welcome to NodeMcu world.")
end
function startServer() local function sender(c)
print("Wifi AP connected. Wicon IP:") if #fifo > 0 then
print(wifi.sta.getip()) c:send(table.remove(fifo, 1))
sv=net.createServer(net.TCP, 180) else
sv:listen(2323, connected) fifo_drained = true
print("Telnet Server running at :2323") end
print("===Now, logon and input LUA.====") end
end
tmr.alarm(1, 1000, 1, function() local function s_output(str)
if wifi.sta.getip()=="0.0.0.0" then table.insert(fifo, str)
print("Connect AP, Waiting...") if socket ~= nil and fifo_drained then
else fifo_drained = false
startServer() sender(socket)
tmr.stop(1) end
end end
node.output(s_output, 0) -- re-direct output to function s_ouput.
socket:on("receive", function(c, l)
node.input(l) -- works like pcall(loadstring(l)) but support multiple separate line
end)
socket:on("disconnection", function(c)
node.output(nil) -- un-regist the redirect output function, output goes to serial
end)
socket:on("sent", sender)
print("Welcome to NodeMCU world.")
end) end)
-- a simple telnet server
s=net.createServer(net.TCP,180)
s:listen(2323,function(c)
function s_output(str)
if(c~=nil)
then c:send(str)
end
end
node.output(s_output, 0) -- re-direct output to function s_ouput.
c:on("receive",function(c,l)
node.input(l) -- works like pcall(loadstring(l)) but support multiple separate line
end)
c:on("disconnection",function(c)
node.output(nil) -- un-regist the redirect output function, output goes to serial
end)
print("Welcome to NodeMcu world.")
end)
\ No newline at end of file
...@@ -25,12 +25,16 @@ function init_spi_display() ...@@ -25,12 +25,16 @@ function init_spi_display()
-- Hardware SPI CLK = GPIO14 -- Hardware SPI CLK = GPIO14
-- Hardware SPI MOSI = GPIO13 -- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used) -- Hardware SPI MISO = GPIO12 (not used)
-- Hardware SPI /CS = GPIO15 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs -- CS, D/C, and RES can be assigned freely to available GPIOs
local cs = 8 -- GPIO15, pull-down 10k to GND local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2 local dc = 4 -- GPIO2
local res = 0 -- GPIO16 local res = 0 -- GPIO16
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8) 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) disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
end end
...@@ -61,14 +65,22 @@ function draw(draw_state) ...@@ -61,14 +65,22 @@ function draw(draw_state)
end end
function bitmap_test() function draw_loop()
dir = 0 -- Draws one page and schedules the next page, if there is one
next_rotation = 0 local function draw_pages()
disp:firstPage()
repeat
draw(draw_state) draw(draw_state)
until disp:nextPage() == false 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 if (draw_state <= 7 + 1*8) then
draw_state = draw_state + 1 draw_state = draw_state + 1
...@@ -78,8 +90,8 @@ function bitmap_test() ...@@ -78,8 +90,8 @@ function bitmap_test()
end end
print("Heap: " .. node.heap()) print("Heap: " .. node.heap())
-- retrigger timer to give room for system housekeeping -- retrigger draw_loop
tmr.start(0) node.task.post(draw_loop)
end end
...@@ -99,8 +111,5 @@ bm_data = file.read() ...@@ -99,8 +111,5 @@ bm_data = file.read()
file.close() file.close()
-- set up timer 0 with short interval, will be retriggered in graphics_test()
tmr.register(0, 100, tmr.ALARM_SEMI, function() bitmap_test() end)
print("--- Starting Bitmap Test ---") print("--- Starting Bitmap Test ---")
tmr.start(0) 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)
...@@ -24,12 +24,16 @@ function init_spi_display() ...@@ -24,12 +24,16 @@ function init_spi_display()
-- Hardware SPI CLK = GPIO14 -- Hardware SPI CLK = GPIO14
-- Hardware SPI MOSI = GPIO13 -- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used) -- Hardware SPI MISO = GPIO12 (not used)
-- Hardware SPI /CS = GPIO15 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs -- CS, D/C, and RES can be assigned freely to available GPIOs
local cs = 8 -- GPIO15, pull-down 10k to GND local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2 local dc = 4 -- GPIO2
local res = 0 -- GPIO16 local res = 0 -- GPIO16
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8) 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) disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
end end
...@@ -134,12 +138,22 @@ function draw(draw_state) ...@@ -134,12 +138,22 @@ function draw(draw_state)
end end
end end
function graphics_test() function draw_loop()
-- Draws one page and schedules the next page, if there is one
disp:firstPage() local function draw_pages()
repeat
draw(draw_state) draw(draw_state)
until disp:nextPage() == false if disp:nextPage() then
node.task.post(draw_pages)
else
node.task.post(graphics_test)
end
end
-- Restart the draw loop and start drawing pages
disp:firstPage()
node.task.post(draw_pages)
end
function graphics_test()
if (draw_state <= 7 + 8*8) then if (draw_state <= 7 + 8*8) then
draw_state = draw_state + 1 draw_state = draw_state + 1
...@@ -149,8 +163,9 @@ function graphics_test() ...@@ -149,8 +163,9 @@ function graphics_test()
end end
print("Heap: " .. node.heap()) print("Heap: " .. node.heap())
-- retrigger timer to give room for system housekeeping -- retrigger draw_loop
tmr.start(0) node.task.post(draw_loop)
end end
draw_state = 0 draw_state = 0
...@@ -158,8 +173,5 @@ draw_state = 0 ...@@ -158,8 +173,5 @@ draw_state = 0
init_i2c_display() init_i2c_display()
--init_spi_display() --init_spi_display()
-- set up timer 0 with short interval, will be retriggered in graphics_test()
tmr.register(0, 100, tmr.ALARM_SEMI, function() graphics_test() end)
print("--- Starting Graphics Test ---") print("--- Starting Graphics Test ---")
tmr.start(0) node.task.post(draw_loop)
...@@ -25,12 +25,16 @@ function init_spi_display() ...@@ -25,12 +25,16 @@ function init_spi_display()
-- Hardware SPI CLK = GPIO14 -- Hardware SPI CLK = GPIO14
-- Hardware SPI MOSI = GPIO13 -- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used) -- Hardware SPI MISO = GPIO12 (not used)
-- Hardware SPI /CS = GPIO15 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs -- CS, D/C, and RES can be assigned freely to available GPIOs
local cs = 8 -- GPIO15, pull-down 10k to GND local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2 local dc = 4 -- GPIO2
local res = 0 -- GPIO16 local res = 0 -- GPIO16
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8) 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) disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
end end
......
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