Commit fa7cf878 authored by zeroday's avatar zeroday
Browse files

Merge pull request #287 from nodemcu/dev

Dev merge to master
parents 6c8cace9 1652df50
...@@ -39,7 +39,9 @@ endif ...@@ -39,7 +39,9 @@ endif
INCLUDES := $(INCLUDES) -I $(PDIR)include INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./ INCLUDES += -I ./
INCLUDES += -I ../libc INCLUDES += -I ../libc
INCLUDES += -I ../coap
INCLUDES += -I ../mqtt INCLUDES += -I ../mqtt
INCLUDES += -I ../u8glib
INCLUDES += -I ../lua INCLUDES += -I ../lua
INCLUDES += -I ../platform INCLUDES += -I ../platform
INCLUDES += -I ../wofs INCLUDES += -I ../wofs
......
...@@ -61,9 +61,15 @@ LUALIB_API int ( luaopen_i2c )( lua_State *L ); ...@@ -61,9 +61,15 @@ LUALIB_API int ( luaopen_i2c )( lua_State *L );
#define AUXLIB_WIFI "wifi" #define AUXLIB_WIFI "wifi"
LUALIB_API int ( luaopen_wifi )( lua_State *L ); LUALIB_API int ( luaopen_wifi )( lua_State *L );
#define AUXLIB_COAP "coap"
LUALIB_API int ( luaopen_coap )( lua_State *L );
#define AUXLIB_MQTT "mqtt" #define AUXLIB_MQTT "mqtt"
LUALIB_API int ( luaopen_mqtt )( lua_State *L ); LUALIB_API int ( luaopen_mqtt )( lua_State *L );
#define AUXLIB_U8G "u8g"
LUALIB_API int ( luaopen_u8g )( lua_State *L );
#define AUXLIB_NODE "node" #define AUXLIB_NODE "node"
LUALIB_API int ( luaopen_node )( lua_State *L ); LUALIB_API int ( luaopen_node )( lua_State *L );
...@@ -92,5 +98,9 @@ LUALIB_API int ( luaopen_ow )( lua_State *L ); ...@@ -92,5 +98,9 @@ LUALIB_API int ( luaopen_ow )( lua_State *L );
lua_pushnumber( L, val );\ lua_pushnumber( L, val );\
lua_setfield( L, -2, name ) lua_setfield( L, -2, name )
#define MOD_REG_LUDATA( L, name, val )\
lua_pushlightuserdata( L, val );\
lua_setfield( L, -2, name )
#endif #endif
// Module for coapwork
//#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
#include "c_string.h"
#include "c_stdlib.h"
#include "c_types.h"
#include "mem.h"
#include "espconn.h"
#include "driver/uart.h"
#include "coap.h"
#include "uri.h"
#include "node.h"
#include "coap_timer.h"
#include "coap_io.h"
#include "coap_server.h"
coap_queue_t *gQueue = NULL;
typedef struct lcoap_userdata
{
lua_State *L;
struct espconn *pesp_conn;
int self_ref;
}lcoap_userdata;
static void coap_received(void *arg, char *pdata, unsigned short len)
{
NODE_DBG("coap_received is called.\n");
struct espconn *pesp_conn = arg;
lcoap_userdata *cud = (lcoap_userdata *)pesp_conn->reverse;
// static uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0'
uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0'
c_memset(buf, 0, sizeof(buf)); // wipe prev data
if (len > MAX_MESSAGE_SIZE) {
NODE_DBG("Request Entity Too Large.\n"); // NOTE: should response 4.13 to client...
return;
}
// c_memcpy(buf, pdata, len);
size_t rsplen = coap_server_respond(pdata, len, buf, MAX_MESSAGE_SIZE+1);
espconn_sent(pesp_conn, (unsigned char *)buf, rsplen);
// c_memset(buf, 0, sizeof(buf));
}
static void coap_sent(void *arg)
{
NODE_DBG("coap_sent is called.\n");
}
// Lua: s = coap.create(function(conn))
static int coap_create( lua_State* L, const char* mt )
{
struct espconn *pesp_conn = NULL;
lcoap_userdata *cud;
unsigned type;
int stack = 1;
// create a object
cud = (lcoap_userdata *)lua_newuserdata(L, sizeof(lcoap_userdata));
// pre-initialize it, in case of errors
cud->self_ref = LUA_NOREF;
cud->pesp_conn = NULL;
// set its metatable
luaL_getmetatable(L, mt);
lua_setmetatable(L, -2);
// create the espconn struct
pesp_conn = (struct espconn *)c_zalloc(sizeof(struct espconn));
if(!pesp_conn)
return luaL_error(L, "not enough memory");
cud->pesp_conn = pesp_conn;
pesp_conn->type = ESPCONN_UDP;
pesp_conn->proto.tcp = NULL;
pesp_conn->proto.udp = NULL;
pesp_conn->proto.udp = (esp_udp *)c_zalloc(sizeof(esp_udp));
if(!pesp_conn->proto.udp){
c_free(pesp_conn);
cud->pesp_conn = pesp_conn = NULL;
return luaL_error(L, "not enough memory");
}
pesp_conn->state = ESPCONN_NONE;
NODE_DBG("UDP server/client is set.\n");
cud->L = L;
pesp_conn->reverse = cud;
NODE_DBG("coap_create is called.\n");
return 1;
}
// Lua: server:delete()
static int coap_delete( lua_State* L, const char* mt )
{
struct espconn *pesp_conn = NULL;
lcoap_userdata *cud;
cud = (lcoap_userdata *)luaL_checkudata(L, 1, mt);
luaL_argcheck(L, cud, 1, "Server/Client expected");
if(cud==NULL){
NODE_DBG("userdata is nil.\n");
return 0;
}
// free (unref) callback ref
if(LUA_NOREF!=cud->self_ref){
luaL_unref(L, LUA_REGISTRYINDEX, cud->self_ref);
cud->self_ref = LUA_NOREF;
}
cud->L = NULL;
if(cud->pesp_conn)
{
if(cud->pesp_conn->proto.udp->remote_port || cud->pesp_conn->proto.udp->local_port)
espconn_delete(cud->pesp_conn);
c_free(cud->pesp_conn->proto.udp);
cud->pesp_conn->proto.udp = NULL;
c_free(cud->pesp_conn);
cud->pesp_conn = NULL;
}
NODE_DBG("coap_delete is called.\n");
return 0;
}
// Lua: server:listen( port, ip )
static int coap_start( lua_State* L, const char* mt )
{
struct espconn *pesp_conn = NULL;
lcoap_userdata *cud;
unsigned port;
size_t il;
ip_addr_t ipaddr;
cud = (lcoap_userdata *)luaL_checkudata(L, 1, mt);
luaL_argcheck(L, cud, 1, "Server/Client expected");
if(cud==NULL){
NODE_DBG("userdata is nil.\n");
return 0;
}
pesp_conn = cud->pesp_conn;
port = luaL_checkinteger( L, 2 );
pesp_conn->proto.udp->local_port = port;
NODE_DBG("UDP port is set: %d.\n", port);
if( lua_isstring(L,3) ) // deal with the ip string
{
const char *ip = luaL_checklstring( L, 3, &il );
if (ip == NULL)
{
ip = "0.0.0.0";
}
ipaddr.addr = ipaddr_addr(ip);
c_memcpy(pesp_conn->proto.udp->local_ip, &ipaddr.addr, 4);
NODE_DBG("UDP ip is set: ");
NODE_DBG(IPSTR, IP2STR(&ipaddr.addr));
NODE_DBG("\n");
}
if(LUA_NOREF==cud->self_ref){
lua_pushvalue(L, 1); // copy to the top of stack
cud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
espconn_regist_recvcb(pesp_conn, coap_received);
espconn_regist_sentcb(pesp_conn, coap_sent);
espconn_create(pesp_conn);
NODE_DBG("Coap Server started on port: %d\n", port);
NODE_DBG("coap_start is called.\n");
return 0;
}
// Lua: server:close()
static int coap_close( lua_State* L, const char* mt )
{
struct espconn *pesp_conn = NULL;
lcoap_userdata *cud;
cud = (lcoap_userdata *)luaL_checkudata(L, 1, mt);
luaL_argcheck(L, cud, 1, "Server/Client expected");
if(cud==NULL){
NODE_DBG("userdata is nil.\n");
return 0;
}
if(cud->pesp_conn)
{
if(cud->pesp_conn->proto.udp->remote_port || cud->pesp_conn->proto.udp->local_port)
espconn_delete(cud->pesp_conn);
}
if(LUA_NOREF!=cud->self_ref){
luaL_unref(L, LUA_REGISTRYINDEX, cud->self_ref);
cud->self_ref = LUA_NOREF;
}
NODE_DBG("coap_close is called.\n");
return 0;
}
// Lua: server/client:on( "method", function(s) )
static int coap_on( lua_State* L, const char* mt )
{
NODE_DBG("coap_on is called.\n");
return 0;
}
static void coap_response_handler(void *arg, char *pdata, unsigned short len)
{
NODE_DBG("coap_response_handler is called.\n");
struct espconn *pesp_conn = arg;
coap_packet_t pkt;
pkt.content.p = NULL;
pkt.content.len = 0;
// static uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0'
uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0'
c_memset(buf, 0, sizeof(buf)); // wipe prev data
int rc;
if( len > MAX_MESSAGE_SIZE )
{
NODE_DBG("Request Entity Too Large.\n"); // NOTE: should response 4.13 to client...
return;
}
c_memcpy(buf, pdata, len);
if (0 != (rc = coap_parse(&pkt, buf, len))){
NODE_DBG("Bad packet rc=%d\n", rc);
}
else
{
#ifdef COAP_DEBUG
coap_dumpPacket(&pkt);
#endif
/* check if this is a response to our original request */
if (!check_token(&pkt)) {
/* drop if this was just some message, or send RST in case of notification */
if (pkt.hdr.t == COAP_TYPE_CON || pkt.hdr.t == COAP_TYPE_NONCON){
// coap_send_rst(pkt); // send RST response
// or, just ignore it.
}
goto end;
}
if (pkt.hdr.t == COAP_TYPE_RESET) {
NODE_DBG("got RST\n");
goto end;
}
uint32_t ip = 0, port = 0;
coap_tid_t id = COAP_INVALID_TID;
c_memcpy(&ip, pesp_conn->proto.udp->remote_ip, sizeof(ip));
port = pesp_conn->proto.udp->remote_port;
coap_transaction_id(ip, port, &pkt, &id);
/* transaction done, remove the node from queue */
// stop timer
coap_timer_stop();
// remove the node
coap_remove_node(&gQueue, id);
// calculate time elapsed
coap_timer_update(&gQueue);
coap_timer_start(&gQueue);
if (COAP_RESPONSE_CLASS(pkt.hdr.code) == 2)
{
/* There is no block option set, just read the data and we are done. */
NODE_DBG("%d.%02d\t", (pkt.hdr.code >> 5), pkt.hdr.code & 0x1F);
NODE_DBG((char *)pkt.payload.p);
}
else if (COAP_RESPONSE_CLASS(pkt.hdr.code) >= 4)
{
NODE_DBG("%d.%02d\t", (pkt.hdr.code >> 5), pkt.hdr.code & 0x1F);
NODE_DBG((char *)pkt.payload.p);
}
}
end:
if(!gQueue){ // if there is no node pending in the queue, disconnect from host.
if(pesp_conn->proto.udp->remote_port || pesp_conn->proto.udp->local_port)
espconn_delete(pesp_conn);
}
// c_memset(buf, 0, sizeof(buf));
}
// Lua: client:request( [CON], uri, [payload] )
static int coap_request( lua_State* L, coap_method_t m )
{
struct espconn *pesp_conn = NULL;
lcoap_userdata *cud;
int stack = 1;
cud = (lcoap_userdata *)luaL_checkudata(L, stack, "coap_client");
luaL_argcheck(L, cud, stack, "Server/Client expected");
if(cud==NULL){
NODE_DBG("userdata is nil.\n");
return 0;
}
stack++;
pesp_conn = cud->pesp_conn;
ip_addr_t ipaddr;
uint8_t host[32];
unsigned t;
if ( lua_isnumber(L, stack) )
{
t = lua_tointeger(L, stack);
stack++;
if ( t != COAP_TYPE_CON && t != COAP_TYPE_NONCON )
return luaL_error( L, "wrong arg type" );
} else {
t = COAP_TYPE_CON; // default to CON
}
size_t l;
const char *url = luaL_checklstring( L, stack, &l );
stack++;
if (url == NULL)
return luaL_error( L, "wrong arg type" );
coap_uri_t *uri = coap_new_uri(url, l); // should call free(uri) somewhere
if (uri == NULL)
return luaL_error( L, "uri wrong format." );
pesp_conn->proto.udp->remote_port = uri->port;
NODE_DBG("UDP port is set: %d.\n", uri->port);
pesp_conn->proto.udp->local_port = espconn_port();
if(uri->host.length){
c_memcpy(host, uri->host.s, uri->host.length);
host[uri->host.length] = '\0';
ipaddr.addr = ipaddr_addr(host);
NODE_DBG("Host len(%d):", uri->host.length);
NODE_DBG(host);
NODE_DBG("\n");
c_memcpy(pesp_conn->proto.udp->remote_ip, &ipaddr.addr, 4);
NODE_DBG("UDP ip is set: ");
NODE_DBG(IPSTR, IP2STR(&ipaddr.addr));
NODE_DBG("\n");
}
coap_pdu_t *pdu = coap_new_pdu(); // should call coap_delete_pdu() somewhere
if(!pdu){
if(uri)
c_free(uri);
return;
}
const char *payload = NULL;
l = 0;
if( lua_isstring(L, stack) ){
payload = luaL_checklstring( L, stack, &l );
if (payload == NULL)
l = 0;
}
coap_make_request(&(pdu->scratch), pdu->pkt, t, m, uri, payload, l);
#ifdef COAP_DEBUG
coap_dumpPacket(pdu->pkt);
#endif
int rc;
if (0 != (rc = coap_build(pdu->msg.p, &(pdu->msg.len), pdu->pkt))){
NODE_DBG("coap_build failed rc=%d\n", rc);
}
else
{
#ifdef COAP_DEBUG
NODE_DBG("Sending: ");
coap_dump(pdu->msg.p, pdu->msg.len, true);
NODE_DBG("\n");
#endif
espconn_regist_recvcb(pesp_conn, coap_response_handler);
sint8_t con = espconn_create(pesp_conn);
if( ESPCONN_OK != con){
NODE_DBG("Connect to host. code:%d\n", con);
// coap_delete_pdu(pdu);
}
// else
{
coap_tid_t tid = COAP_INVALID_TID;
if (pdu->pkt->hdr.t == COAP_TYPE_CON){
tid = coap_send_confirmed(pesp_conn, pdu);
}
else {
tid = coap_send(pesp_conn, pdu);
}
if (pdu->pkt->hdr.t != COAP_TYPE_CON || tid == COAP_INVALID_TID){
coap_delete_pdu(pdu);
}
}
}
if(uri)
c_free((void *)uri);
NODE_DBG("coap_request is called.\n");
return 0;
}
extern coap_luser_entry *variable_entry;
extern coap_luser_entry *function_entry;
// Lua: coap:var/func( string )
static int coap_regist( lua_State* L, const char* mt, int isvar )
{
size_t l;
const char *name = luaL_checklstring( L, 2, &l );
if (name == NULL)
return luaL_error( L, "name must be set." );
coap_luser_entry *h = NULL;
// if(lua_isstring(L, 3))
if(isvar)
h = variable_entry;
else
h = function_entry;
while(NULL!=h->next){ // goto the end of the list
if(h->name!= NULL && c_strcmp(h->name, name)==0) // key exist, override it
break;
h = h->next;
}
if(h->name==NULL || c_strcmp(h->name, name)!=0){ // not exists. make a new one.
h->next = (coap_luser_entry *)c_zalloc(sizeof(coap_luser_entry));
h = h->next;
if(h == NULL)
return luaL_error(L, "not enough memory");
h->next = NULL;
h->name = NULL;
h->L = NULL;
}
h->L = L;
h->name = name;
NODE_DBG("coap_regist is called.\n");
return 0;
}
// Lua: s = coap.createServer(function(conn))
static int coap_createServer( lua_State* L )
{
const char *mt = "coap_server";
return coap_create(L, mt);
}
// Lua: server:delete()
static int coap_server_delete( lua_State* L )
{
const char *mt = "coap_server";
return coap_delete(L, mt);
}
// Lua: server:listen( port, ip, function(err) )
static int coap_server_listen( lua_State* L )
{
const char *mt = "coap_server";
return coap_start(L, mt);
}
// Lua: server:close()
static int coap_server_close( lua_State* L )
{
const char *mt = "coap_server";
return coap_close(L, mt);
}
// Lua: server:on( "method", function(server) )
static int coap_server_on( lua_State* L )
{
const char *mt = "coap_server";
return coap_on(L, mt);
}
// Lua: server:var( "name" )
static int coap_server_var( lua_State* L )
{
const char *mt = "coap_server";
return coap_regist(L, mt, 1);
}
// Lua: server:func( "name" )
static int coap_server_func( lua_State* L )
{
const char *mt = "coap_server";
return coap_regist(L, mt, 0);
}
// Lua: s = coap.createClient(function(conn))
static int coap_createClient( lua_State* L )
{
const char *mt = "coap_client";
return coap_create(L, mt);
}
// Lua: client:gcdelete()
static int coap_client_gcdelete( lua_State* L )
{
const char *mt = "coap_client";
return coap_delete(L, mt);
}
// client:get( string, function(sent) )
static int coap_client_get( lua_State* L )
{
return coap_request(L, COAP_METHOD_GET);
}
// client:post( string, function(sent) )
static int coap_client_post( lua_State* L )
{
return coap_request(L, COAP_METHOD_POST);
}
// client:put( string, function(sent) )
static int coap_client_put( lua_State* L )
{
return coap_request(L, COAP_METHOD_PUT);
}
// client:delete( string, function(sent) )
static int coap_client_delete( lua_State* L )
{
return coap_request(L, COAP_METHOD_DELETE);
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
static const LUA_REG_TYPE coap_server_map[] =
{
{ LSTRKEY( "listen" ), LFUNCVAL ( coap_server_listen ) },
{ LSTRKEY( "close" ), LFUNCVAL ( coap_server_close ) },
{ LSTRKEY( "var" ), LFUNCVAL ( coap_server_var ) },
{ LSTRKEY( "func" ), LFUNCVAL ( coap_server_func ) },
{ LSTRKEY( "__gc" ), LFUNCVAL ( coap_server_delete ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "__index" ), LROVAL ( coap_server_map ) },
#endif
{ LNILKEY, LNILVAL }
};
static const LUA_REG_TYPE coap_client_map[] =
{
{ LSTRKEY( "get" ), LFUNCVAL ( coap_client_get ) },
{ LSTRKEY( "post" ), LFUNCVAL ( coap_client_post ) },
{ LSTRKEY( "put" ), LFUNCVAL ( coap_client_put ) },
{ LSTRKEY( "delete" ), LFUNCVAL ( coap_client_delete ) },
{ LSTRKEY( "__gc" ), LFUNCVAL ( coap_client_gcdelete ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "__index" ), LROVAL ( coap_client_map ) },
#endif
{ LNILKEY, LNILVAL }
};
const LUA_REG_TYPE coap_map[] =
{
{ LSTRKEY( "Server" ), LFUNCVAL ( coap_createServer ) },
{ LSTRKEY( "Client" ), LFUNCVAL ( coap_createClient ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "CON" ), LNUMVAL( COAP_TYPE_CON ) },
{ LSTRKEY( "NON" ), LNUMVAL( COAP_TYPE_NONCON ) },
{ LSTRKEY( "__metatable" ), LROVAL( coap_map ) },
#endif
{ LNILKEY, LNILVAL }
};
LUALIB_API int luaopen_coap( lua_State *L )
{
endpoint_setup();
#if LUA_OPTIMIZE_MEMORY > 0
luaL_rometatable(L, "coap_server", (void *)coap_server_map); // create metatable for coap_server
luaL_rometatable(L, "coap_client", (void *)coap_client_map); // create metatable for coap_client
return 0;
#else // #if LUA_OPTIMIZE_MEMORY > 0
int n;
luaL_register( L, AUXLIB_COAP, coap_map );
// Set it as its own metatable
lua_pushvalue( L, -1 );
lua_setmetatable( L, -2 );
// Module constants
MOD_REG_NUMBER( L, "CON", COAP_TYPE_CON );
MOD_REG_NUMBER( L, "NON", COAP_TYPE_NONCON );
n = lua_gettop(L);
// create metatable
luaL_newmetatable(L, "coap_server");
// metatable.__index = metatable
lua_pushliteral(L, "__index");
lua_pushvalue(L,-2);
lua_rawset(L,-3);
// Setup the methods inside metatable
luaL_register( L, NULL, coap_server_map );
lua_settop(L, n);
// create metatable
luaL_newmetatable(L, "coap_client");
// metatable.__index = metatable
lua_pushliteral(L, "__index");
lua_pushvalue(L,-2);
lua_rawset(L,-3);
// Setup the methods inside metatable
luaL_register( L, NULL, coap_client_map );
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
}
...@@ -111,7 +111,7 @@ static int file_seek (lua_State *L) ...@@ -111,7 +111,7 @@ static int file_seek (lua_State *L)
long offset = luaL_optlong(L, 2, 0); long offset = luaL_optlong(L, 2, 0);
op = fs_seek(file_fd, offset, mode[op]); op = fs_seek(file_fd, offset, mode[op]);
if (op) if (op)
lua_pushboolean(L, 1); /* error */ lua_pushnil(L); /* error */
else else
lua_pushinteger(L, fs_tell(file_fd)); lua_pushinteger(L, fs_tell(file_fd));
return 1; return 1;
...@@ -175,6 +175,22 @@ static int file_rename( lua_State* L ) ...@@ -175,6 +175,22 @@ static int file_rename( lua_State* L )
return 1; return 1;
} }
// Lua: fsinfo()
static int file_fsinfo( lua_State* L )
{
uint32_t total, used;
SPIFFS_info(&fs, &total, &used);
NODE_DBG("total: %d, used:%d\n", total, used);
if(total>0x7FFFFFFF || used>0x7FFFFFFF || used > total)
{
return luaL_error(L, "file system error");;
}
lua_pushinteger(L, total-used);
lua_pushinteger(L, used);
lua_pushinteger(L, total);
return 3;
}
#endif #endif
// g_read() // g_read()
...@@ -308,6 +324,7 @@ const LUA_REG_TYPE file_map[] = ...@@ -308,6 +324,7 @@ const LUA_REG_TYPE file_map[] =
{ LSTRKEY( "flush" ), LFUNCVAL( file_flush ) }, { LSTRKEY( "flush" ), LFUNCVAL( file_flush ) },
// { LSTRKEY( "check" ), LFUNCVAL( file_check ) }, // { LSTRKEY( "check" ), LFUNCVAL( file_check ) },
{ LSTRKEY( "rename" ), LFUNCVAL( file_rename ) }, { LSTRKEY( "rename" ), LFUNCVAL( file_rename ) },
{ LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) },
#endif #endif
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include "lrotable.h" #include "lrotable.h"
#include "luaconf.h" #include "luaconf.h"
#include "user_modules.h"
#if defined(LUA_USE_MODULES) #if defined(LUA_USE_MODULES)
#include "modules.h" #include "modules.h"
#endif #endif
...@@ -28,12 +30,26 @@ LUA_MODULES_ROM ...@@ -28,12 +30,26 @@ LUA_MODULES_ROM
static const luaL_Reg lualibs[] = { static const luaL_Reg lualibs[] = {
{"", luaopen_base}, {"", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package}, {LUA_LOADLIBNAME, luaopen_package},
// {LUA_IOLIBNAME, luaopen_io}, #if defined(LUA_USE_BUILTIN_IO)
{LUA_STRLIBNAME, luaopen_string}, {LUA_IOLIBNAME, luaopen_io},
#endif
#if defined(LUA_USE_BUILTIN_STRING)
{LUA_STRLIBNAME, luaopen_string},
#endif
#if LUA_OPTIMIZE_MEMORY == 0 #if LUA_OPTIMIZE_MEMORY == 0
// {LUA_MATHLIBNAME, luaopen_math}, #if defined(LUA_USE_BUILTIN_MATH)
{LUA_MATHLIBNAME, luaopen_math},
#endif
#if defined(LUA_USE_BUILTIN_TABLE)
{LUA_TABLIBNAME, luaopen_table}, {LUA_TABLIBNAME, luaopen_table},
// {LUA_DBLIBNAME, luaopen_debug}, #endif
#if defined(LUA_USE_BUILTIN_DEBUG)
{LUA_DBLIBNAME, luaopen_debug},
#endif
#endif #endif
#if defined(LUA_MODULES_ROM) #if defined(LUA_MODULES_ROM)
#undef _ROM #undef _ROM
...@@ -43,12 +59,30 @@ static const luaL_Reg lualibs[] = { ...@@ -43,12 +59,30 @@ static const luaL_Reg lualibs[] = {
{NULL, NULL} {NULL, NULL}
}; };
#if defined(LUA_USE_BUILTIN_STRING)
extern const luaR_entry strlib[]; extern const luaR_entry strlib[];
#endif
#if defined(LUA_USE_BUILTIN_OS)
extern const luaR_entry syslib[]; extern const luaR_entry syslib[];
#endif
#if defined(LUA_USE_BUILTIN_TABLE)
extern const luaR_entry tab_funcs[]; extern const luaR_entry tab_funcs[];
// extern const luaR_entry dblib[]; #endif
#if defined(LUA_USE_BUILTIN_DEBUG)
extern const luaR_entry dblib[];
#endif
#if defined(LUA_USE_BUILTIN_COROUTINE)
extern const luaR_entry co_funcs[]; extern const luaR_entry co_funcs[];
// extern const luaR_entry math_map[]; #endif
#if defined(LUA_USE_BUILTIN_MATH)
extern const luaR_entry math_map[];
#endif
#if defined(LUA_MODULES_ROM) && LUA_OPTIMIZE_MEMORY == 2 #if defined(LUA_MODULES_ROM) && LUA_OPTIMIZE_MEMORY == 2
#undef _ROM #undef _ROM
#define _ROM( name, openf, table ) extern const luaR_entry table[]; #define _ROM( name, openf, table ) extern const luaR_entry table[];
...@@ -57,11 +91,30 @@ LUA_MODULES_ROM ...@@ -57,11 +91,30 @@ LUA_MODULES_ROM
const luaR_table lua_rotable[] = const luaR_table lua_rotable[] =
{ {
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
#if defined(LUA_USE_BUILTIN_STRING)
{LUA_STRLIBNAME, strlib}, {LUA_STRLIBNAME, strlib},
#endif
#if defined(LUA_USE_BUILTIN_TABLE)
{LUA_TABLIBNAME, tab_funcs}, {LUA_TABLIBNAME, tab_funcs},
// {LUA_DBLIBNAME, dblib}, #endif
#if defined(LUA_USE_BUILTIN_DEBUG)
{LUA_DBLIBNAME, dblib},
#endif
#if defined(LUA_USE_BUILTIN_COROUTINE)
{LUA_COLIBNAME, co_funcs}, {LUA_COLIBNAME, co_funcs},
// {LUA_MATHLIBNAME, math_map}, #endif
#if defined(LUA_USE_BUILTIN_MATH)
{LUA_MATHLIBNAME, math_map},
#endif
#if defined(LUA_USE_BUILTIN_OS)
{LUA_OSLIBNAME, syslib},
#endif
#if defined(LUA_MODULES_ROM) && LUA_OPTIMIZE_MEMORY == 2 #if defined(LUA_MODULES_ROM) && LUA_OPTIMIZE_MEMORY == 2
#undef _ROM #undef _ROM
#define _ROM( name, openf, table ) { name, table }, #define _ROM( name, openf, table ) { name, table },
......
...@@ -37,6 +37,14 @@ ...@@ -37,6 +37,14 @@
#define ROM_MODULES_NET #define ROM_MODULES_NET
#endif #endif
#if defined(LUA_USE_MODULES_COAP)
#define MODULES_COAP "coap"
#define ROM_MODULES_COAP \
_ROM(MODULES_COAP, luaopen_coap, coap_map)
#else
#define ROM_MODULES_COAP
#endif
#if defined(LUA_USE_MODULES_MQTT) #if defined(LUA_USE_MODULES_MQTT)
#define MODULES_MQTT "mqtt" #define MODULES_MQTT "mqtt"
#define ROM_MODULES_MQTT \ #define ROM_MODULES_MQTT \
...@@ -45,6 +53,14 @@ ...@@ -45,6 +53,14 @@
#define ROM_MODULES_MQTT #define ROM_MODULES_MQTT
#endif #endif
#if defined(LUA_USE_MODULES_U8G)
#define MODULES_U8G "u8g"
#define ROM_MODULES_U8G \
_ROM(MODULES_U8G, luaopen_u8g, lu8g_map)
#else
#define ROM_MODULES_U8G
#endif
#if defined(LUA_USE_MODULES_I2C) #if defined(LUA_USE_MODULES_I2C)
#define MODULES_I2C "i2c" #define MODULES_I2C "i2c"
#define ROM_MODULES_I2C \ #define ROM_MODULES_I2C \
...@@ -120,17 +136,19 @@ ...@@ -120,17 +136,19 @@
#if defined(LUA_USE_MODULES_WS2812) #if defined(LUA_USE_MODULES_WS2812)
#define MODULES_WS2812 "ws2812" #define MODULES_WS2812 "ws2812"
#define ROM_MODULES_WS2812 \ #define ROM_MODULES_WS2812 \
_ROM(MODULES_WS2812, luaopen_ws2812, ws2812_map) _ROM(MODULES_WS2812, luaopen_ws2812, ws2812_map)
#else #else
#define ROM_MODULES_WS2812 #define ROM_MODULES_WS2812
#endif #endif
#define LUA_MODULES_ROM \ #define LUA_MODULES_ROM \
ROM_MODULES_GPIO \ ROM_MODULES_GPIO \
ROM_MODULES_PWM \ ROM_MODULES_PWM \
ROM_MODULES_WIFI \ ROM_MODULES_WIFI \
ROM_MODULES_MQTT \ ROM_MODULES_COAP \
ROM_MODULES_MQTT \
ROM_MODULES_U8G \
ROM_MODULES_I2C \ ROM_MODULES_I2C \
ROM_MODULES_SPI \ ROM_MODULES_SPI \
ROM_MODULES_TMR \ ROM_MODULES_TMR \
...@@ -140,8 +158,8 @@ ...@@ -140,8 +158,8 @@
ROM_MODULES_ADC \ ROM_MODULES_ADC \
ROM_MODULES_UART \ ROM_MODULES_UART \
ROM_MODULES_OW \ ROM_MODULES_OW \
ROM_MODULES_BIT \ ROM_MODULES_BIT \
ROM_MODULES_WS2812 ROM_MODULES_WS2812
#endif #endif
...@@ -1102,7 +1102,7 @@ const LUA_REG_TYPE mqtt_map[] = ...@@ -1102,7 +1102,7 @@ const LUA_REG_TYPE mqtt_map[] =
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
LUALIB_API int ICACHE_FLASH_ATTR luaopen_mqtt( lua_State *L ) LUALIB_API int luaopen_mqtt( lua_State *L )
{ {
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
luaL_rometatable(L, "mqtt.socket", (void *)mqtt_socket_map); // create metatable for mqtt.socket luaL_rometatable(L, "mqtt.socket", (void *)mqtt_socket_map); // create metatable for mqtt.socket
......
...@@ -200,10 +200,15 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -200,10 +200,15 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
return; return;
} }
if(nud->self_ref == LUA_NOREF){
NODE_DBG("self_ref null.\n");
return;
}
if(ipaddr == NULL) if(ipaddr == NULL)
{ {
NODE_ERR( "DNS Fail!\n" ); NODE_ERR( "DNS Fail!\n" );
return; goto end;
} }
// ipaddr->addr is a uint32_t ip // ipaddr->addr is a uint32_t ip
...@@ -214,16 +219,12 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -214,16 +219,12 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
c_sprintf(ip_str, IPSTR, IP2STR(&(ipaddr->addr))); c_sprintf(ip_str, IPSTR, IP2STR(&(ipaddr->addr)));
} }
if(nud->self_ref == LUA_NOREF){
NODE_DBG("self_ref null.\n");
return;
}
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua
lua_pushstring(gL, ip_str); // the ip para lua_pushstring(gL, ip_str); // the ip para
lua_call(gL, 2, 0); lua_call(gL, 2, 0);
end:
if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0) if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0)
|| (pesp_conn->type == ESPCONN_UDP && pesp_conn->proto.udp->remote_port == 0) ){ || (pesp_conn->type == ESPCONN_UDP && pesp_conn->proto.udp->remote_port == 0) ){
lua_gc(gL, LUA_GCSTOP, 0); lua_gc(gL, LUA_GCSTOP, 0);
...@@ -597,12 +598,22 @@ static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -597,12 +598,22 @@ static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
NODE_DBG("pesp_conn null.\n"); NODE_DBG("pesp_conn null.\n");
return; return;
} }
lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse;
if(nud == NULL)
return;
if(gL == NULL)
return;
if(ipaddr == NULL) if(ipaddr == NULL)
{ {
dns_reconn_count++; dns_reconn_count++;
if( dns_reconn_count >= 5 ){ if( dns_reconn_count >= 5 ){
NODE_ERR( "DNS Fail!\n" ); NODE_ERR( "DNS Fail!\n" );
lua_gc(gL, LUA_GCSTOP, 0);
if(nud->self_ref != LUA_NOREF){
luaL_unref(gL, LUA_REGISTRYINDEX, nud->self_ref);
nud->self_ref = LUA_NOREF; // unref this, and the net.socket userdata will delete it self
}
lua_gc(gL, LUA_GCRESTART, 0);
return; return;
} }
NODE_ERR( "DNS retry %d!\n", dns_reconn_count ); NODE_ERR( "DNS retry %d!\n", dns_reconn_count );
...@@ -1241,6 +1252,31 @@ static int net_socket_unhold( lua_State* L ) ...@@ -1241,6 +1252,31 @@ static int net_socket_unhold( lua_State* L )
return 0; return 0;
} }
// Lua: ip,port = sk:getpeer()
static int net_socket_getpeer( lua_State* L )
{
lnet_userdata *nud;
const char *mt = "net.socket";
nud = (lnet_userdata *)luaL_checkudata(L, 1, mt);
luaL_argcheck(L, nud, 1, "Server/Socket expected");
if(nud!=NULL && nud->pesp_conn!=NULL ){
char temp[20] = {0};
c_sprintf(temp, IPSTR, IP2STR( &(nud->pesp_conn->proto.tcp->remote_ip) ) );
if ( nud->pesp_conn->proto.tcp->remote_port != 0 ) {
lua_pushstring( L, temp );
lua_pushinteger( L, nud->pesp_conn->proto.tcp->remote_port );
} else {
lua_pushnil( L );
lua_pushnil( L );
}
} else {
lua_pushnil( L );
lua_pushnil( L );
}
return 2;
}
// Lua: socket:dns( string, function(ip) ) // Lua: socket:dns( string, function(ip) )
static int net_socket_dns( lua_State* L ) static int net_socket_dns( lua_State* L )
{ {
...@@ -1302,6 +1338,7 @@ static const LUA_REG_TYPE net_socket_map[] = ...@@ -1302,6 +1338,7 @@ static const LUA_REG_TYPE net_socket_map[] =
{ LSTRKEY( "hold" ), LFUNCVAL ( net_socket_hold ) }, { LSTRKEY( "hold" ), LFUNCVAL ( net_socket_hold ) },
{ LSTRKEY( "unhold" ), LFUNCVAL ( net_socket_unhold ) }, { LSTRKEY( "unhold" ), LFUNCVAL ( net_socket_unhold ) },
{ LSTRKEY( "dns" ), LFUNCVAL ( net_socket_dns ) }, { LSTRKEY( "dns" ), LFUNCVAL ( net_socket_dns ) },
{ LSTRKEY( "getpeer" ), LFUNCVAL ( net_socket_getpeer ) },
// { LSTRKEY( "delete" ), LFUNCVAL ( net_socket_delete ) }, // { LSTRKEY( "delete" ), LFUNCVAL ( net_socket_delete ) },
{ LSTRKEY( "__gc" ), LFUNCVAL ( net_socket_delete ) }, { LSTRKEY( "__gc" ), LFUNCVAL ( net_socket_delete ) },
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
......
...@@ -23,12 +23,16 @@ ...@@ -23,12 +23,16 @@
#include "user_interface.h" #include "user_interface.h"
#include "flash_api.h" #include "flash_api.h"
#include "flash_fs.h" #include "flash_fs.h"
#include "user_version.h"
#define CPU80MHZ 80
#define CPU160MHZ 160
// Lua: restart() // Lua: restart()
static int node_restart( lua_State* L ) static int node_restart( lua_State* L )
{ {
system_restart(); system_restart();
return 0; return 0;
} }
// Lua: dsleep( us, option ) // Lua: dsleep( us, option )
...@@ -55,7 +59,7 @@ static int node_deepsleep( lua_State* L ) ...@@ -55,7 +59,7 @@ static int node_deepsleep( lua_State* L )
else else
system_deep_sleep( us ); system_deep_sleep( us );
} }
return 0; return 0;
} }
// Lua: dsleep_set_options // Lua: dsleep_set_options
...@@ -79,10 +83,14 @@ static int node_info( lua_State* L ) ...@@ -79,10 +83,14 @@ static int node_info( lua_State* L )
lua_pushinteger(L, NODE_VERSION_REVISION); lua_pushinteger(L, NODE_VERSION_REVISION);
lua_pushinteger(L, system_get_chip_id()); // chip id lua_pushinteger(L, system_get_chip_id()); // chip id
lua_pushinteger(L, spi_flash_get_id()); // flash id lua_pushinteger(L, spi_flash_get_id()); // flash id
lua_pushinteger(L, flash_get_size_byte() / 1024); // flash size in KB #if defined(FLASH_SAFE_API)
lua_pushinteger(L, flash_get_mode()); lua_pushinteger(L, flash_safe_get_size_byte() / 1024); // flash size in KB
lua_pushinteger(L, flash_get_speed()); #else
return 8; lua_pushinteger(L, flash_rom_get_size_byte() / 1024); // flash size in KB
#endif // defined(FLASH_SAFE_API)
lua_pushinteger(L, flash_rom_get_mode());
lua_pushinteger(L, flash_rom_get_speed());
return 8;
} }
// Lua: chipid() // Lua: chipid()
...@@ -90,7 +98,7 @@ static int node_chipid( lua_State* L ) ...@@ -90,7 +98,7 @@ static int node_chipid( lua_State* L )
{ {
uint32_t id = system_get_chip_id(); uint32_t id = system_get_chip_id();
lua_pushinteger(L, id); lua_pushinteger(L, id);
return 1; return 1;
} }
// Lua: readvdd33() // Lua: readvdd33()
static int node_readvdd33( lua_State* L ) static int node_readvdd33( lua_State* L )
...@@ -105,24 +113,23 @@ static int node_flashid( lua_State* L ) ...@@ -105,24 +113,23 @@ static int node_flashid( lua_State* L )
{ {
uint32_t id = spi_flash_get_id(); uint32_t id = spi_flash_get_id();
lua_pushinteger( L, id ); lua_pushinteger( L, id );
return 1; return 1;
} }
// Lua: flashsize() // Lua: flashsize()
static int node_flashsize( lua_State* L ) static int node_flashsize( lua_State* L )
{ {
//uint32_t sz = 0; if (lua_type(L, 1) == LUA_TNUMBER)
//if(lua_type(L, 1) == LUA_TNUMBER) {
//{ flash_rom_set_size_byte(luaL_checkinteger(L, 1));
// sz = luaL_checkinteger(L, 1); }
// if(sz > 0) #if defined(FLASH_SAFE_API)
// { uint32_t sz = flash_safe_get_size_byte();
// flash_set_size_byte(sz); #else
// } uint32_t sz = flash_rom_get_size_byte();
//} #endif // defined(FLASH_SAFE_API)
uint32_t sz = flash_get_size_byte();
lua_pushinteger( L, sz ); lua_pushinteger( L, sz );
return 1; return 1;
} }
// Lua: heap() // Lua: heap()
...@@ -130,7 +137,7 @@ static int node_heap( lua_State* L ) ...@@ -130,7 +137,7 @@ static int node_heap( lua_State* L )
{ {
uint32_t sz = system_get_free_heap_size(); uint32_t sz = system_get_free_heap_size();
lua_pushinteger(L, sz); lua_pushinteger(L, sz);
return 1; return 1;
} }
static lua_State *gL = NULL; static lua_State *gL = NULL;
...@@ -145,7 +152,7 @@ static int node_led( lua_State* L ) ...@@ -145,7 +152,7 @@ static int node_led( lua_State* L )
if ( lua_isnumber(L, 1) ) if ( lua_isnumber(L, 1) )
{ {
low = lua_tointeger(L, 1); low = lua_tointeger(L, 1);
if ( low < 0 ){ if ( low < 0 ) {
return luaL_error( L, "wrong arg type" ); return luaL_error( L, "wrong arg type" );
} }
} else { } else {
...@@ -154,7 +161,7 @@ static int node_led( lua_State* L ) ...@@ -154,7 +161,7 @@ static int node_led( lua_State* L )
if ( lua_isnumber(L, 2) ) if ( lua_isnumber(L, 2) )
{ {
high = lua_tointeger(L, 2); high = lua_tointeger(L, 2);
if ( high < 0 ){ if ( high < 0 ) {
return luaL_error( L, "wrong arg type" ); return luaL_error( L, "wrong arg type" );
} }
} else { } else {
...@@ -162,14 +169,14 @@ static int node_led( lua_State* L ) ...@@ -162,14 +169,14 @@ static int node_led( lua_State* L )
} }
led_high_count = (uint32_t)high / READLINE_INTERVAL; led_high_count = (uint32_t)high / READLINE_INTERVAL;
led_low_count = (uint32_t)low / READLINE_INTERVAL; led_low_count = (uint32_t)low / READLINE_INTERVAL;
return 0; return 0;
} }
static int long_key_ref = LUA_NOREF; static int long_key_ref = LUA_NOREF;
static int short_key_ref = LUA_NOREF; static int short_key_ref = LUA_NOREF;
void default_long_press(void *arg){ void default_long_press(void *arg) {
if(led_high_count == 12 && led_low_count == 12){ if (led_high_count == 12 && led_low_count == 12) {
led_low_count = led_high_count = 6; led_low_count = led_high_count = 6;
} else { } else {
led_low_count = led_high_count = 12; led_low_count = led_high_count = 12;
...@@ -179,32 +186,32 @@ void default_long_press(void *arg){ ...@@ -179,32 +186,32 @@ void default_long_press(void *arg){
// NODE_DBG("default_long_press is called. hc: %d, lc: %d\n", led_high_count, led_low_count); // NODE_DBG("default_long_press is called. hc: %d, lc: %d\n", led_high_count, led_low_count);
} }
void default_short_press(void *arg){ void default_short_press(void *arg) {
system_restart(); system_restart();
} }
void key_long_press(void *arg){ void key_long_press(void *arg) {
NODE_DBG("key_long_press is called.\n"); NODE_DBG("key_long_press is called.\n");
if(long_key_ref == LUA_NOREF){ if (long_key_ref == LUA_NOREF) {
default_long_press(arg); default_long_press(arg);
return; return;
} }
if(!gL) if (!gL)
return; return;
lua_rawgeti(gL, LUA_REGISTRYINDEX, long_key_ref); lua_rawgeti(gL, LUA_REGISTRYINDEX, long_key_ref);
lua_call(gL, 0, 0); lua_call(gL, 0, 0);
} }
void key_short_press(void *arg){ void key_short_press(void *arg) {
NODE_DBG("key_short_press is called.\n"); NODE_DBG("key_short_press is called.\n");
if(short_key_ref == LUA_NOREF){ if (short_key_ref == LUA_NOREF) {
default_short_press(arg); default_short_press(arg);
return; return;
} }
if(!gL) if (!gL)
return; return;
lua_rawgeti(gL, LUA_REGISTRYINDEX, short_key_ref); lua_rawgeti(gL, LUA_REGISTRYINDEX, short_key_ref);
lua_call(gL, 0, 0); lua_call(gL, 0, 0);
} }
// Lua: key(type, function) // Lua: key(type, function)
...@@ -212,32 +219,32 @@ static int node_key( lua_State* L ) ...@@ -212,32 +219,32 @@ static int node_key( lua_State* L )
{ {
int *ref = NULL; int *ref = NULL;
size_t sl; size_t sl;
const char *str = luaL_checklstring( L, 1, &sl ); const char *str = luaL_checklstring( L, 1, &sl );
if (str == NULL) if (str == NULL)
return luaL_error( L, "wrong arg type" ); return luaL_error( L, "wrong arg type" );
if(sl == 5 && c_strcmp(str, "short") == 0){ if (sl == 5 && c_strcmp(str, "short") == 0) {
ref = &short_key_ref; ref = &short_key_ref;
}else if(sl == 4 && c_strcmp(str, "long") == 0){ } else if (sl == 4 && c_strcmp(str, "long") == 0) {
ref = &long_key_ref; ref = &long_key_ref;
}else{ } else {
ref = &short_key_ref; ref = &short_key_ref;
} }
gL = L; gL = L;
// luaL_checkanyfunction(L, 2); // luaL_checkanyfunction(L, 2);
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION){ if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION) {
lua_pushvalue(L, 2); // copy argument (func) to the top of stack lua_pushvalue(L, 2); // copy argument (func) to the top of stack
if(*ref != LUA_NOREF) if (*ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, *ref); luaL_unref(L, LUA_REGISTRYINDEX, *ref);
*ref = luaL_ref(L, LUA_REGISTRYINDEX); *ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else { // unref the key press function } else { // unref the key press function
if(*ref != LUA_NOREF) if (*ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, *ref); luaL_unref(L, LUA_REGISTRYINDEX, *ref);
*ref = LUA_NOREF; *ref = LUA_NOREF;
} }
return 0; return 0;
} }
#endif #endif
...@@ -247,15 +254,15 @@ extern void dojob(lua_Load *load); ...@@ -247,15 +254,15 @@ extern void dojob(lua_Load *load);
// Lua: input("string") // Lua: input("string")
static int node_input( lua_State* L ) static int node_input( lua_State* L )
{ {
size_t l=0; size_t l = 0;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
if (s != NULL && l > 0 && l < LUA_MAXINPUT - 1) if (s != NULL && l > 0 && l < LUA_MAXINPUT - 1)
{ {
lua_Load *load = &gLoad; lua_Load *load = &gLoad;
if(load->line_position == 0){ if (load->line_position == 0) {
c_memcpy(load->line, s, l); c_memcpy(load->line, s, l);
load->line[l+1] = '\0'; load->line[l + 1] = '\0';
load->line_position = c_strlen(load->line)+1; load->line_position = c_strlen(load->line) + 1;
load->done = 1; load->done = 1;
NODE_DBG("Get command:\n"); NODE_DBG("Get command:\n");
NODE_DBG(load->line); // buggy here NODE_DBG(load->line); // buggy here
...@@ -270,18 +277,18 @@ static int node_input( lua_State* L ) ...@@ -270,18 +277,18 @@ static int node_input( lua_State* L )
static int output_redir_ref = LUA_NOREF; static int output_redir_ref = LUA_NOREF;
static int serial_debug = 1; static int serial_debug = 1;
void output_redirect(const char *str){ void output_redirect(const char *str) {
// if(c_strlen(str)>=TX_BUFF_SIZE){ // if(c_strlen(str)>=TX_BUFF_SIZE){
// NODE_ERR("output too long.\n"); // NODE_ERR("output too long.\n");
// return; // return;
// } // }
if(output_redir_ref == LUA_NOREF || !gL){ if (output_redir_ref == LUA_NOREF || !gL) {
uart0_sendStr(str); uart0_sendStr(str);
return; return;
} }
if(serial_debug!=0){ if (serial_debug != 0) {
uart0_sendStr(str); uart0_sendStr(str);
} }
...@@ -295,15 +302,15 @@ static int node_output( lua_State* L ) ...@@ -295,15 +302,15 @@ static int node_output( lua_State* L )
{ {
gL = L; gL = L;
// luaL_checkanyfunction(L, 1); // luaL_checkanyfunction(L, 1);
if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION){ if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION) {
lua_pushvalue(L, 1); // copy argument (func) to the top of stack lua_pushvalue(L, 1); // copy argument (func) to the top of stack
if(output_redir_ref != LUA_NOREF) if (output_redir_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref); luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref);
output_redir_ref = luaL_ref(L, LUA_REGISTRYINDEX); output_redir_ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else { // unref the key press function } else { // unref the key press function
if(output_redir_ref != LUA_NOREF) if (output_redir_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref); luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref);
output_redir_ref = LUA_NOREF; output_redir_ref = LUA_NOREF;
serial_debug = 1; serial_debug = 1;
return 0; return 0;
} }
...@@ -311,26 +318,26 @@ static int node_output( lua_State* L ) ...@@ -311,26 +318,26 @@ static int node_output( lua_State* L )
if ( lua_isnumber(L, 2) ) if ( lua_isnumber(L, 2) )
{ {
serial_debug = lua_tointeger(L, 2); serial_debug = lua_tointeger(L, 2);
if(serial_debug!=0) if (serial_debug != 0)
serial_debug = 1; serial_debug = 1;
} else { } else {
serial_debug = 1; // default to 1 serial_debug = 1; // default to 1
} }
return 0; return 0;
} }
static int writer(lua_State* L, const void* p, size_t size, void* u) static int writer(lua_State* L, const void* p, size_t size, void* u)
{ {
UNUSED(L); UNUSED(L);
int file_fd = *( (int *)u ); int file_fd = *( (int *)u );
if((FS_OPEN_OK - 1)==file_fd) if ((FS_OPEN_OK - 1) == file_fd)
return 1; return 1;
NODE_DBG("get fd:%d,size:%d\n",file_fd,size); NODE_DBG("get fd:%d,size:%d\n", file_fd, size);
if(size!=0 && (size!=fs_write(file_fd, (const char *)p, size)) ) if (size != 0 && (size != fs_write(file_fd, (const char *)p, size)) )
return 1; return 1;
NODE_DBG("write fd:%d,size:%d\n",file_fd,size); NODE_DBG("write fd:%d,size:%d\n", file_fd, size);
return 0; return 0;
} }
...@@ -342,55 +349,73 @@ static int node_compile( lua_State* L ) ...@@ -342,55 +349,73 @@ static int node_compile( lua_State* L )
int file_fd = FS_OPEN_OK - 1; int file_fd = FS_OPEN_OK - 1;
size_t len; size_t len;
const char *fname = luaL_checklstring( L, 1, &len ); const char *fname = luaL_checklstring( L, 1, &len );
if( len > FS_NAME_MAX_LENGTH ) if ( len > FS_NAME_MAX_LENGTH )
return luaL_error(L, "filename too long"); return luaL_error(L, "filename too long");
char output[FS_NAME_MAX_LENGTH]; char output[FS_NAME_MAX_LENGTH];
c_strcpy(output, fname); c_strcpy(output, fname);
// check here that filename end with ".lua". // check here that filename end with ".lua".
if(len<4 || (c_strcmp( output+len-4,".lua")!=0) ) if (len < 4 || (c_strcmp( output + len - 4, ".lua") != 0) )
return luaL_error(L, "not a .lua file"); return luaL_error(L, "not a .lua file");
output[c_strlen(output)-2] = 'c'; output[c_strlen(output) - 2] = 'c';
output[c_strlen(output)-1] = '\0'; output[c_strlen(output) - 1] = '\0';
NODE_DBG(output); NODE_DBG(output);
NODE_DBG("\n"); NODE_DBG("\n");
if (luaL_loadfsfile(L,fname)!=0){ if (luaL_loadfsfile(L, fname) != 0) {
return luaL_error(L, lua_tostring(L,-1)); return luaL_error(L, lua_tostring(L, -1));
} }
f = toproto(L,-1); f = toproto(L, -1);
int stripping = 1; /* strip debug information? */ int stripping = 1; /* strip debug information? */
file_fd = fs_open(output, fs_mode2flag("w+")); file_fd = fs_open(output, fs_mode2flag("w+"));
if(file_fd < FS_OPEN_OK) if (file_fd < FS_OPEN_OK)
{ {
return luaL_error(L, "cannot open/write to file"); return luaL_error(L, "cannot open/write to file");
} }
lua_lock(L); lua_lock(L);
int result=luaU_dump(L,f,writer,&file_fd,stripping); int result = luaU_dump(L, f, writer, &file_fd, stripping);
lua_unlock(L); lua_unlock(L);
fs_flush(file_fd); fs_flush(file_fd);
fs_close(file_fd); fs_close(file_fd);
file_fd = FS_OPEN_OK - 1; file_fd = FS_OPEN_OK - 1;
if (result==LUA_ERR_CC_INTOVERFLOW){ if (result == LUA_ERR_CC_INTOVERFLOW) {
return luaL_error(L, "value too big or small for target integer type"); return luaL_error(L, "value too big or small for target integer type");
} }
if (result==LUA_ERR_CC_NOTINTEGER){ if (result == LUA_ERR_CC_NOTINTEGER) {
return luaL_error(L, "target lua_Number is integral but fractional value found"); return luaL_error(L, "target lua_Number is integral but fractional value found");
} }
return 0; return 0;
} }
// Lua: setcpufreq(mhz)
// mhz is either CPU80MHZ od CPU160MHZ
static int node_setcpufreq(lua_State* L)
{
// http://www.esp8266.com/viewtopic.php?f=21&t=1369
uint32_t new_freq = luaL_checkinteger(L, 1);
if (new_freq == CPU160MHZ){
REG_SET_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(CPU160MHZ);
} else {
REG_CLR_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(CPU80MHZ);
}
new_freq = ets_get_cpu_frequency();
lua_pushinteger(L, new_freq);
return 1;
}
// Module function map // Module function map
#define MIN_OPT_LEVEL 2 #define MIN_OPT_LEVEL 2
#include "lrodefs.h" #include "lrodefs.h"
const LUA_REG_TYPE node_map[] = const LUA_REG_TYPE node_map[] =
{ {
{ LSTRKEY( "restart" ), LFUNCVAL( node_restart ) }, { LSTRKEY( "restart" ), LFUNCVAL( node_restart ) },
{ LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) }, { LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) },
...@@ -407,7 +432,10 @@ const LUA_REG_TYPE node_map[] = ...@@ -407,7 +432,10 @@ const LUA_REG_TYPE node_map[] =
{ LSTRKEY( "output" ), LFUNCVAL( node_output ) }, { LSTRKEY( "output" ), LFUNCVAL( node_output ) },
{ LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) }, { LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) },
{ LSTRKEY( "compile" ), LFUNCVAL( node_compile) }, { LSTRKEY( "compile" ), LFUNCVAL( node_compile) },
// Combined to dsleep(us, option) { LSTRKEY( "CPU80MHZ" ), LNUMVAL( CPU80MHZ ) },
{ LSTRKEY( "CPU160MHZ" ), LNUMVAL( CPU160MHZ ) },
{ LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) },
// Combined to dsleep(us, option)
// { LSTRKEY( "dsleepsetoption" ), LFUNCVAL( node_deepsleep_setoption) }, // { LSTRKEY( "dsleepsetoption" ), LFUNCVAL( node_deepsleep_setoption) },
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
...@@ -424,5 +452,5 @@ LUALIB_API int luaopen_node( lua_State *L ) ...@@ -424,5 +452,5 @@ LUALIB_API int luaopen_node( lua_State *L )
// Add constants // Add constants
return 1; return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0 #endif // #if LUA_OPTIMIZE_MEMORY > 0
} }
...@@ -148,24 +148,30 @@ static int tmr_wdclr( lua_State* L ) ...@@ -148,24 +148,30 @@ static int tmr_wdclr( lua_State* L )
} }
static os_timer_t rtc_timer_updator; static os_timer_t rtc_timer_updator;
static uint64_t cur_count = 0; static uint32_t cur_count = 0;
static uint64_t rtc_us = 0; static uint32_t rtc_10ms = 0;
void rtc_timer_update_cb(void *arg){ void rtc_timer_update_cb(void *arg){
uint64_t t = (uint64_t)system_get_rtc_time(); uint32_t t = (uint32_t)system_get_rtc_time();
uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count); uint32_t delta = 0;
if(t>=cur_count){
delta = t-cur_count;
}else{
delta = 0xFFFFFFF - cur_count + t + 1;
}
// uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count);
// NODE_ERR("%x\n",t); // NODE_ERR("%x\n",t);
cur_count = t; cur_count = t;
unsigned c = system_rtc_clock_cali_proc(); uint32_t c = system_rtc_clock_cali_proc();
uint64_t itg = c >> 12; uint32_t itg = c >> 12; // ~=5
uint64_t dec = c & 0xFFF; uint32_t dec = c & 0xFFF; // ~=2ff
rtc_us += (delta*itg + ((delta*dec)>>12)); rtc_10ms += (delta*itg + ((delta*dec)>>12)) / 10000;
// TODO: store rtc_us to rtc memory. // TODO: store rtc_10ms to rtc memory.
} }
// Lua: time() , return rtc time in second // Lua: time() , return rtc time in second
static int tmr_time( lua_State* L ) static int tmr_time( lua_State* L )
{ {
uint64_t local = rtc_us; uint32_t local = rtc_10ms;
lua_pushinteger( L, ((uint32_t)(local/1000000)) & 0x7FFFFFFF ); lua_pushinteger( L, ((uint32_t)(local/100)) & 0x7FFFFFFF );
return 1; return 1;
} }
......
// Module for U8glib
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
//#include "c_string.h"
#include "c_stdlib.h"
#include "u8g.h"
#include "u8g_config.h"
struct _lu8g_userdata_t
{
u8g_t u8g;
u8g_pb_t pb;
u8g_dev_t dev;
};
typedef struct _lu8g_userdata_t lu8g_userdata_t;
// shorthand macro for the u8g structure inside the userdata
#define LU8G (&(lud->u8g))
// function to read 4-byte aligned from program memory AKA irom0
u8g_pgm_uint8_t ICACHE_FLASH_ATTR u8g_pgm_read(const u8g_pgm_uint8_t *adr)
{
uint32_t iadr = (uint32_t)adr;
// set up pointer to 4-byte aligned memory location
uint32_t *ptr = (uint32_t *)(iadr & ~0x3);
// read 4-byte aligned
uint32_t pgm_data = *ptr;
// return the correct byte within the retrieved 32bit word
return pgm_data >> ((iadr % 4) * 8);
}
// helper function: retrieve and check userdata argument
static lu8g_userdata_t *get_lud( lua_State *L )
{
lu8g_userdata_t *lud = (lu8g_userdata_t *)luaL_checkudata(L, 1, "u8g.display");
luaL_argcheck(L, lud, 1, "u8g.display expected");
return lud;
}
// helper function: retrieve given number of integer arguments
static void lu8g_get_int_args( lua_State *L, uint8_t stack, uint8_t num, u8g_uint_t *args)
{
while (num-- > 0)
{
*args++ = luaL_checkinteger( L, stack++ );
}
}
// Lua: u8g.begin( self )
static int lu8g_begin( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_Begin( LU8G );
return 0;
}
// Lua: u8g.setFont( self, font )
static int lu8g_setFont( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_fntpgm_uint8_t *font = (u8g_fntpgm_uint8_t *)lua_touserdata( L, 2 );
if (font != NULL)
u8g_SetFont( LU8G, font );
return 0;
}
// Lua: u8g.setFontRefHeightAll( self )
static int lu8g_setFontRefHeightAll( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetFontRefHeightAll( LU8G );
return 0;
}
// Lua: u8g.setFontRefHeightExtendedText( self )
static int lu8g_setFontRefHeightExtendedText( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetFontRefHeightExtendedText( LU8G );
return 0;
}
// Lua: u8g.setFontRefHeightText( self )
static int lu8g_setFontRefHeightText( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetFontRefHeightText( LU8G );
return 0;
}
// Lua: u8g.setDefaultBackgroundColor( self )
static int lu8g_setDefaultBackgroundColor( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetDefaultBackgroundColor( LU8G );
return 0;
}
// Lua: u8g.setDefaultForegroundColor( self )
static int lu8g_setDefaultForegroundColor( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetDefaultForegroundColor( LU8G );
return 0;
}
// Lua: u8g.setFontPosBaseline( self )
static int lu8g_setFontPosBaseline( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetFontPosBaseline( LU8G );
return 0;
}
// Lua: u8g.setFontPosBottom( self )
static int lu8g_setFontPosBottom( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetFontPosBottom( LU8G );
return 0;
}
// Lua: u8g.setFontPosCenter( self )
static int lu8g_setFontPosCenter( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetFontPosCenter( LU8G );
return 0;
}
// Lua: u8g.setFontPosTop( self )
static int lu8g_setFontPosTop( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetFontPosTop( LU8G );
return 0;
}
// Lua: int = u8g.getFontAscent( self )
static int lu8g_getFontAscent( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
lua_pushinteger( L, u8g_GetFontAscent( LU8G ) );
return 1;
}
// Lua: int = u8g.getFontDescent( self )
static int lu8g_getFontDescent( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
lua_pushinteger( L, u8g_GetFontDescent( LU8G ) );
return 1;
}
// Lua: int = u8g.getFontLineSpacing( self )
static int lu8g_getFontLineSpacing( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
lua_pushinteger( L, u8g_GetFontLineSpacing( LU8G ) );
return 1;
}
// Lua: int = u8g.getMode( self )
static int lu8g_getMode( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
lua_pushinteger( L, u8g_GetMode( LU8G ) );
return 1;
}
// Lua: u8g.setColorIndex( self, color )
static int lu8g_setColorIndex( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetColorIndex( LU8G, luaL_checkinteger( L, 2 ) );
return 0;
}
// Lua: int = u8g.getColorIndex( self )
static int lu8g_getColorIndex( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
lua_pushinteger( L, u8g_GetColorIndex( LU8G ) );
return 1;
}
static int lu8g_generic_drawStr( lua_State *L, uint8_t rot )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[2];
lu8g_get_int_args( L, 2, 2, args );
const char *s = luaL_checkstring( L, (1+2) + 1 );
if (s == NULL)
return 0;
switch (rot)
{
case 1:
lua_pushinteger( L, u8g_DrawStr90( LU8G, args[0], args[1], s ) );
break;
case 2:
lua_pushinteger( L, u8g_DrawStr180( LU8G, args[0], args[1], s ) );
break;
case 3:
lua_pushinteger( L, u8g_DrawStr270( LU8G, args[0], args[1], s ) );
break;
default:
lua_pushinteger( L, u8g_DrawStr( LU8G, args[0], args[1], s ) );
break;
}
return 1;
}
// Lua: pix_len = u8g.drawStr( self, x, y, string )
static int lu8g_drawStr( lua_State *L )
{
lu8g_userdata_t *lud;
return lu8g_generic_drawStr( L, 0 );
}
// Lua: pix_len = u8g.drawStr90( self, x, y, string )
static int lu8g_drawStr90( lua_State *L )
{
lu8g_userdata_t *lud;
return lu8g_generic_drawStr( L, 1 );
}
// Lua: pix_len = u8g.drawStr180( self, x, y, string )
static int lu8g_drawStr180( lua_State *L )
{
lu8g_userdata_t *lud;
return lu8g_generic_drawStr( L, 2 );
}
// Lua: pix_len = u8g.drawStr270( self, x, y, string )
static int lu8g_drawStr270( lua_State *L )
{
lu8g_userdata_t *lud;
return lu8g_generic_drawStr( L, 3 );
}
// Lua: u8g.drawLine( self, x1, y1, x2, y2 )
static int lu8g_drawLine( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[4];
lu8g_get_int_args( L, 2, 4, args );
u8g_DrawLine( LU8G, args[0], args[1], args[2], args[3] );
return 0;
}
// Lua: u8g.drawTriangle( self, x0, y0, x1, y1, x2, y2 )
static int lu8g_drawTriangle( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[6];
lu8g_get_int_args( L, 2, 6, args );
u8g_DrawTriangle( LU8G, args[0], args[1], args[2], args[3], args[4], args[5] );
return 0;
}
// Lua: u8g.drawBox( self, x, y, width, height )
static int lu8g_drawBox( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[4];
lu8g_get_int_args( L, 2, 4, args );
u8g_DrawBox( LU8G, args[0], args[1], args[2], args[3] );
return 0;
}
// Lua: u8g.drawRBox( self, x, y, width, height, radius )
static int lu8g_drawRBox( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[5];
lu8g_get_int_args( L, 2, 5, args );
u8g_DrawRBox( LU8G, args[0], args[1], args[2], args[3], args[4] );
return 0;
}
// Lua: u8g.drawFrame( self, x, y, width, height )
static int lu8g_drawFrame( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[4];
lu8g_get_int_args( L, 2, 4, args );
u8g_DrawFrame( LU8G, args[0], args[1], args[2], args[3] );
return 0;
}
// Lua: u8g.drawRFrame( self, x, y, width, height, radius )
static int lu8g_drawRFrame( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[5];
lu8g_get_int_args( L, 2, 5, args );
u8g_DrawRFrame( LU8G, args[0], args[1], args[2], args[3], args[4] );
return 0;
}
// Lua: u8g.drawDisc( self, x0, y0, rad, opt = U8G_DRAW_ALL )
static int lu8g_drawDisc( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[3];
lu8g_get_int_args( L, 2, 3, args );
u8g_uint_t opt = luaL_optinteger( L, (1+3) + 1, U8G_DRAW_ALL );
u8g_DrawDisc( LU8G, args[0], args[1], args[2], opt );
return 0;
}
// Lua: u8g.drawCircle( self, x0, y0, rad, opt = U8G_DRAW_ALL )
static int lu8g_drawCircle( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[3];
lu8g_get_int_args( L, 2, 3, args );
u8g_uint_t opt = luaL_optinteger( L, (1+3) + 1, U8G_DRAW_ALL );
u8g_DrawCircle( LU8G, args[0], args[1], args[2], opt );
return 0;
}
// Lua: u8g.drawEllipse( self, x0, y0, rx, ry, opt = U8G_DRAW_ALL )
static int lu8g_drawEllipse( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[4];
lu8g_get_int_args( L, 2, 4, args );
u8g_uint_t opt = luaL_optinteger( L, (1+4) + 1, U8G_DRAW_ALL );
u8g_DrawEllipse( LU8G, args[0], args[1], args[2], args[3], opt );
return 0;
}
// Lua: u8g.drawFilledEllipse( self, x0, y0, rx, ry, opt = U8G_DRAW_ALL )
static int lu8g_drawFilledEllipse( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[4];
lu8g_get_int_args( L, 2, 4, args );
u8g_uint_t opt = luaL_optinteger( L, (1+4) + 1, U8G_DRAW_ALL );
u8g_DrawFilledEllipse( LU8G, args[0], args[1], args[2], args[3], opt );
return 0;
}
// Lua: u8g.drawPixel( self, x, y )
static int lu8g_drawPixel( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[2];
lu8g_get_int_args( L, 2, 2, args );
u8g_DrawPixel( LU8G, args[0], args[1] );
return 0;
}
// Lua: u8g.drawHLine( self, x, y, width )
static int lu8g_drawHLine( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[3];
lu8g_get_int_args( L, 2, 3, args );
u8g_DrawHLine( LU8G, args[0], args[1], args[2] );
return 0;
}
// Lua: u8g.drawVLine( self, x, y, width )
static int lu8g_drawVLine( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[3];
lu8g_get_int_args( L, 2, 3, args );
u8g_DrawVLine( LU8G, args[0], args[1], args[2] );
return 0;
}
// Lua: u8g.drawXBM( self, x, y, width, height, data )
static int lu8g_drawXBM( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[4];
lu8g_get_int_args( L, 2, 4, args );
const char *xbm_data = luaL_checkstring( L, (1+4) + 1 );
if (xbm_data == NULL)
return 0;
u8g_DrawXBM( LU8G, args[0], args[1], args[2], args[3], (const uint8_t *)xbm_data );
return 0;
}
// Lua: u8g.drawBitmap( self, x, y, count, height, data )
static int lu8g_drawBitmap( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t args[4];
lu8g_get_int_args( L, 2, 4, args );
const char *bm_data = luaL_checkstring( L, (1+4) + 1 );
if (bm_data == NULL)
return 0;
u8g_DrawBitmap( LU8G, args[0], args[1], args[2], args[3], (const uint8_t *)bm_data );
return 0;
}
// Lua: u8g.setScale2x2( self )
static int lu8g_setScale2x2( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetScale2x2( LU8G );
return 0;
}
// Lua: u8g.undoScale( self )
static int lu8g_undoScale( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_UndoScale( LU8G );
return 0;
}
// Lua: u8g.firstPage( self )
static int lu8g_firstPage( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_FirstPage( LU8G );
return 0;
}
// Lua: bool = u8g.nextPage( self )
static int lu8g_nextPage( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
lua_pushboolean( L, u8g_NextPage( LU8G ) );
return 1;
}
// Lua: u8g.sleepOn( self )
static int lu8g_sleepOn( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SleepOn( LU8G );
return 0;
}
// Lua: u8g.sleepOff( self )
static int lu8g_sleepOff( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SleepOff( LU8G );
return 0;
}
// Lua: u8g.setRot90( self )
static int lu8g_setRot90( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetRot90( LU8G );
return 0;
}
// Lua: u8g.setRot180( self )
static int lu8g_setRot180( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetRot180( LU8G );
return 0;
}
// Lua: u8g.setRot270( self )
static int lu8g_setRot270( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_SetRot270( LU8G );
return 0;
}
// Lua: u8g.undoRotation( self )
static int lu8g_undoRotation( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_UndoRotation( LU8G );
return 0;
}
// Lua: width = u8g.getWidth( self )
static int lu8g_getWidth( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
lua_pushinteger( L, u8g_GetWidth( LU8G ) );
return 1;
}
// Lua: height = u8g.getHeight( self )
static int lu8g_getHeight( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
lua_pushinteger( L, u8g_GetHeight( LU8G ) );
return 1;
}
// ------------------------------------------------------------
// comm functions
//
#define I2C_CMD_MODE 0x000
#define I2C_DATA_MODE 0x040
#define ESP_I2C_ID 0
static uint8_t do_i2c_start(uint8_t id, uint8_t sla)
{
platform_i2c_send_start( id );
// ignore return value -> tolerate missing ACK
platform_i2c_send_address( id, sla, PLATFORM_I2C_DIRECTION_TRANSMITTER );
return 1;
}
static uint8_t u8g_com_esp8266_ssd_start_sequence(u8g_t *u8g)
{
/* are we requested to set the a0 state? */
if ( u8g->pin_list[U8G_PI_SET_A0] == 0 )
return 1;
/* setup bus, might be a repeated start */
if ( do_i2c_start( ESP_I2C_ID, u8g->i2c_addr ) == 0 )
return 0;
if ( u8g->pin_list[U8G_PI_A0_STATE] == 0 )
{
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, I2C_CMD_MODE ) == 0 )
; //return 0;
}
else
{
platform_i2c_send_byte( ESP_I2C_ID, I2C_DATA_MODE );
}
u8g->pin_list[U8G_PI_SET_A0] = 0;
return 1;
}
static void lu8g_digital_write( u8g_t *u8g, uint8_t pin_index, uint8_t value )
{
uint8_t pin;
pin = u8g->pin_list[pin_index];
if ( pin != U8G_PIN_NONE )
platform_gpio_write( pin, value );
}
uint8_t u8g_com_esp8266_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
{
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_INIT:
// we assume that the SPI interface was already initialized
// just care for the /CS and D/C pins
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
platform_gpio_mode( u8g->pin_list[U8G_PI_CS], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
platform_gpio_mode( u8g->pin_list[U8G_PI_A0], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
lu8g_digital_write( u8g, U8G_PI_A0, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
break;
case U8G_COM_MSG_CHIP_SELECT:
if (arg_val == 0)
{
/* disable */
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
}
else
{
/* enable */
//u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, LOW);
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_LOW );
}
break;
case U8G_COM_MSG_RESET:
if ( u8g->pin_list[U8G_PI_RESET] != U8G_PIN_NONE )
lu8g_digital_write( u8g, U8G_PI_RESET, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
break;
case U8G_COM_MSG_WRITE_BYTE:
platform_spi_send_recv( 1, arg_val );
break;
case U8G_COM_MSG_WRITE_SEQ:
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
platform_spi_send_recv( 1, *ptr++ );
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P:
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
platform_spi_send_recv( 1, u8g_pgm_read(ptr) );
ptr++;
arg_val--;
}
}
break;
}
return 1;
}
uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
{
case U8G_COM_MSG_INIT:
// we assume that the i2c bus was already initialized
//u8g_i2c_init(u8g->pin_list[U8G_PI_I2C_OPTION]);
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
/* Currently disabled, but it could be enable. Previous restrictions have been removed */
/* u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val); */
break;
case U8G_COM_MSG_CHIP_SELECT:
u8g->pin_list[U8G_PI_A0_STATE] = 0;
u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again, also forces start condition */
if ( arg_val == 0 )
{
/* disable chip, send stop condition */
platform_i2c_send_stop( ESP_I2C_ID );
}
else
{
/* enable, do nothing: any byte writing will trigger the i2c start */
}
break;
case U8G_COM_MSG_WRITE_BYTE:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
return platform_i2c_stop( ESP_I2C_ID ), 0;
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, arg_val) == 0 )
; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_WRITE_SEQ:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, *ptr++) == 0 )
; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
arg_val--;
}
}
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_WRITE_SEQ_P:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, u8g_pgm_read(ptr) ) == 0 )
; //return 0;
ptr++;
arg_val--;
}
}
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g->pin_list[U8G_PI_A0_STATE] = arg_val;
u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again */
break;
}
return 1;
}
// device destructor
static int lu8g_close_display( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
// free up allocated page buffer
if (lud->pb.buf != NULL)
{
c_free( lud->pb.buf );
lud->pb.buf = NULL;
}
return 0;
}
// device constructors
uint8_t u8g_dev_ssd1306_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg);
// Lua: object = u8g.ssd1306_128x64_i2c( i2c_addr )
static int lu8g_ssd1306_128x64_i2c( lua_State *L )
{
unsigned addr = luaL_checkinteger( L, 1 );
if (addr == 0)
return luaL_error( L, "i2c address required" );
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) );
lud->u8g.i2c_addr = (uint8_t)addr;
// Don't use the pre-defined device structure for u8g_dev_ssd1306_128x64_i2c here
// Reason: linking the pre-defined structures allocates RAM for the device/comm structure
// *before* the display is constructed (especially the page buffers)
// this consumes heap even when the device is not used at all
#if 1
// build device entry
lud->dev = (u8g_dev_t){ u8g_dev_ssd1306_128x64_fn, &(lud->pb), U8G_COM_SSD_I2C };
// populate and allocate page buffer
// constants taken from u8g_dev_ssd1306_128x64.c:
// PAGE_HEIGHT
// | Height
// | | WIDTH
// | | |
lud->pb = (u8g_pb_t){ { 8, 64, 0, 0, 0 }, 128, NULL };
//
if ((lud->pb.buf = (void *)c_zalloc(lud->pb.width)) == NULL)
return luaL_error( L, "out of memory" );
// and finally init device using specific interface init function
u8g_InitI2C( LU8G, &(lud->dev), U8G_I2C_OPT_NONE);
#else
u8g_InitI2C( LU8G, &u8g_dev_ssd1306_128x64_i2c, U8G_I2C_OPT_NONE);
#endif
// set its metatable
luaL_getmetatable(L, "u8g.display");
lua_setmetatable(L, -2);
return 1;
}
// Lua: object = u8g.ssd1306_128x64_spi( cs, dc, [res] )
static int lu8g_ssd1306_128x64_spi( lua_State *L )
{
unsigned cs = luaL_checkinteger( L, 1 );
if (cs == 0)
return luaL_error( L, "CS pin required" );
unsigned dc = luaL_checkinteger( L, 2 );
if (dc == 0)
return luaL_error( L, "D/C pin required" );
unsigned res = luaL_optinteger( L, 3, U8G_PIN_NONE );
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) );
// Don't use the pre-defined device structure for u8g_dev_ssd1306_128x64_spi here
// Reason: linking the pre-defined structures allocates RAM for the device/comm structure
// *before* the display is constructed (especially the page buffers)
// this consumes heap even when the device is not used at all
#if 1
// build device entry
lud->dev = (u8g_dev_t){ u8g_dev_ssd1306_128x64_fn, &(lud->pb), U8G_COM_HW_SPI };
// populate and allocate page buffer
// constants taken from u8g_dev_ssd1306_128x64.c:
// PAGE_HEIGHT
// | Height
// | | WIDTH
// | | |
lud->pb = (u8g_pb_t){ { 8, 64, 0, 0, 0 }, 128, NULL };
//
if ((lud->pb.buf = (void *)c_zalloc(lud->pb.width)) == NULL)
return luaL_error( L, "out of memory" );
// and finally init device using specific interface init function
u8g_InitHWSPI( LU8G, &(lud->dev), cs, dc, res );
#else
u8g_InitHWSPI( LU8G, &u8g_dev_ssd1306_128x64_spi, cs, dc, res );
#endif
// set its metatable
luaL_getmetatable(L, "u8g.display");
lua_setmetatable(L, -2);
return 1;
}
uint8_t u8g_dev_pcd8544_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg);
// Lua: object = u8g.pcd8544_84x48( sce, dc, res )
static int lu8g_pcd8544_84x48( lua_State *L )
{
unsigned sce = luaL_checkinteger( L, 1 );
if (sce == 0)
return luaL_error( L, "SCE pin required" );
unsigned dc = luaL_checkinteger( L, 2 );
if (dc == 0)
return luaL_error( L, "D/C pin required" );
unsigned res = luaL_checkinteger( L, 3 );
if (res == 0)
return luaL_error( L, "RES pin required" );
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) );
// Don't use the pre-defined device structure for u8g_dev_pcd8544_84x48_hw_spi here
// Reason: linking the pre-defined structures allocates RAM for the device/comm structure
// *before* the display is constructed (especially the page buffers)
// this consumes heap even when the device is not used at all
#if 1
// build device entry
lud->dev = (u8g_dev_t){ u8g_dev_pcd8544_fn, &(lud->pb), U8G_COM_HW_SPI };
// populate and allocate page buffer
// constants taken from u8g_dev_pcd8544_84x48.c:
// PAGE_HEIGHT
// | Height
// | | WIDTH
// | | |
lud->pb = (u8g_pb_t){ { 8, 48, 0, 0, 0 }, 84, NULL };
//
if ((lud->pb.buf = (void *)c_zalloc(lud->pb.width)) == NULL)
return luaL_error( L, "out of memory" );
// and finally init device using specific interface init function
u8g_InitHWSPI( LU8G, &(lud->dev), sce, dc, res );
#else
u8g_InitHWSPI( LU8G, &u8g_dev_pcd8544_84x48_hw_spi, sce, dc, res );
#endif
// set its metatable
luaL_getmetatable(L, "u8g.display");
lua_setmetatable(L, -2);
return 1;
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
static const LUA_REG_TYPE lu8g_display_map[] =
{
{ LSTRKEY( "begin" ), LFUNCVAL( lu8g_begin ) },
{ LSTRKEY( "setFont" ), LFUNCVAL( lu8g_setFont ) },
{ LSTRKEY( "setFontRefHeightAll" ), LFUNCVAL( lu8g_setFontRefHeightAll ) },
{ LSTRKEY( "setFontRefHeightExtendedText" ), LFUNCVAL( lu8g_setFontRefHeightExtendedText ) },
{ LSTRKEY( "setFontRefHeightText" ), LFUNCVAL( lu8g_setFontRefHeightText ) },
{ LSTRKEY( "setDefaultBackgroundColor" ), LFUNCVAL( lu8g_setDefaultBackgroundColor ) },
{ LSTRKEY( "setDefaultForegroundColor" ), LFUNCVAL( lu8g_setDefaultForegroundColor ) },
{ LSTRKEY( "setFontPosBaseline" ), LFUNCVAL( lu8g_setFontPosBaseline ) },
{ LSTRKEY( "setFontPosBottom" ), LFUNCVAL( lu8g_setFontPosBottom ) },
{ LSTRKEY( "setFontPosCenter" ), LFUNCVAL( lu8g_setFontPosCenter ) },
{ LSTRKEY( "setFontPosTop" ), LFUNCVAL( lu8g_setFontPosTop ) },
{ LSTRKEY( "getFontAscent" ), LFUNCVAL( lu8g_getFontAscent ) },
{ LSTRKEY( "getFontDescent" ), LFUNCVAL( lu8g_getFontDescent ) },
{ LSTRKEY( "getFontLineSpacing" ), LFUNCVAL( lu8g_getFontLineSpacing ) },
{ LSTRKEY( "getMode" ), LFUNCVAL( lu8g_getMode ) },
{ LSTRKEY( "setColorIndex" ), LFUNCVAL( lu8g_setColorIndex ) },
{ LSTRKEY( "getColorIndex" ), LFUNCVAL( lu8g_getColorIndex ) },
{ LSTRKEY( "drawStr" ), LFUNCVAL( lu8g_drawStr ) },
{ LSTRKEY( "drawStr90" ), LFUNCVAL( lu8g_drawStr90 ) },
{ LSTRKEY( "drawStr180" ), LFUNCVAL( lu8g_drawStr180 ) },
{ LSTRKEY( "drawStr270" ), LFUNCVAL( lu8g_drawStr270 ) },
{ LSTRKEY( "drawBox" ), LFUNCVAL( lu8g_drawBox ) },
{ LSTRKEY( "drawLine" ), LFUNCVAL( lu8g_drawLine ) },
{ LSTRKEY( "drawTriangle" ), LFUNCVAL( lu8g_drawTriangle ) },
{ LSTRKEY( "drawRBox" ), LFUNCVAL( lu8g_drawRBox ) },
{ LSTRKEY( "drawFrame" ), LFUNCVAL( lu8g_drawFrame ) },
{ LSTRKEY( "drawRFrame" ), LFUNCVAL( lu8g_drawRFrame ) },
{ LSTRKEY( "drawDisc" ), LFUNCVAL( lu8g_drawDisc ) },
{ LSTRKEY( "drawCircle" ), LFUNCVAL( lu8g_drawCircle ) },
{ LSTRKEY( "drawEllipse" ), LFUNCVAL( lu8g_drawEllipse ) },
{ LSTRKEY( "drawFilledEllipse" ), LFUNCVAL( lu8g_drawFilledEllipse ) },
{ LSTRKEY( "drawPixel" ), LFUNCVAL( lu8g_drawPixel ) },
{ LSTRKEY( "drawHLine" ), LFUNCVAL( lu8g_drawHLine ) },
{ LSTRKEY( "drawVLine" ), LFUNCVAL( lu8g_drawVLine ) },
{ LSTRKEY( "drawBitmap" ), LFUNCVAL( lu8g_drawBitmap ) },
{ LSTRKEY( "drawXBM" ), LFUNCVAL( lu8g_drawXBM ) },
{ LSTRKEY( "setScale2x2" ), LFUNCVAL( lu8g_setScale2x2 ) },
{ LSTRKEY( "undoScale" ), LFUNCVAL( lu8g_undoScale ) },
{ LSTRKEY( "firstPage" ), LFUNCVAL( lu8g_firstPage ) },
{ LSTRKEY( "nextPage" ), LFUNCVAL( lu8g_nextPage ) },
{ LSTRKEY( "sleepOn" ), LFUNCVAL( lu8g_sleepOn ) },
{ LSTRKEY( "sleepOff" ), LFUNCVAL( lu8g_sleepOff ) },
{ LSTRKEY( "setRot90" ), LFUNCVAL( lu8g_setRot90 ) },
{ LSTRKEY( "setRot180" ), LFUNCVAL( lu8g_setRot180 ) },
{ LSTRKEY( "setRot270" ), LFUNCVAL( lu8g_setRot270 ) },
{ LSTRKEY( "undoRotation" ), LFUNCVAL( lu8g_undoRotation ) },
{ LSTRKEY( "getWidth" ), LFUNCVAL( lu8g_getWidth ) },
{ LSTRKEY( "getHeight" ), LFUNCVAL( lu8g_getHeight ) },
{ LSTRKEY( "__gc" ), LFUNCVAL( lu8g_close_display ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "__index" ), LROVAL ( lu8g_display_map ) },
#endif
{ LNILKEY, LNILVAL }
};
const LUA_REG_TYPE lu8g_map[] =
{
#ifdef U8G_SSD1306_128x64_I2C
{ LSTRKEY( "ssd1306_128x64_i2c" ), LFUNCVAL ( lu8g_ssd1306_128x64_i2c ) },
#endif
#ifdef U8G_SSD1306_128x64_I2C
{ LSTRKEY( "ssd1306_128x64_spi" ), LFUNCVAL ( lu8g_ssd1306_128x64_spi ) },
#endif
#ifdef U8G_PCD8544_84x48
{ LSTRKEY( "pcd8544_84x48" ), LFUNCVAL ( lu8g_pcd8544_84x48 ) },
#endif
#if LUA_OPTIMIZE_MEMORY > 0
// Register fonts
#undef U8G_FONT_TABLE_ENTRY
#define U8G_FONT_TABLE_ENTRY(font) { LSTRKEY( #font ), LUDATA( (void *)(u8g_ ## font) ) },
U8G_FONT_TABLE
// Options for circle/ ellipse drwing
{ LSTRKEY( "DRAW_UPPER_RIGHT" ), LNUMVAL( U8G_DRAW_UPPER_RIGHT ) },
{ LSTRKEY( "DRAW_UPPER_LEFT" ), LNUMVAL( U8G_DRAW_UPPER_LEFT ) },
{ LSTRKEY( "DRAW_LOWER_RIGHT" ), LNUMVAL( U8G_DRAW_LOWER_RIGHT ) },
{ LSTRKEY( "DRAW_LOWER_LEFT" ), LNUMVAL( U8G_DRAW_LOWER_LEFT ) },
{ LSTRKEY( "DRAW_ALL" ), LNUMVAL( U8G_DRAW_ALL ) },
// Display modes
{ LSTRKEY( "MODE_BW" ), LNUMVAL( U8G_MODE_BW ) },
{ LSTRKEY( "MODE_GRAY2BIT" ), LNUMVAL( U8G_MODE_GRAY2BIT ) },
{ LSTRKEY( "__metatable" ), LROVAL( lu8g_map ) },
#endif
{ LNILKEY, LNILVAL }
};
LUALIB_API int luaopen_u8g( lua_State *L )
{
#if LUA_OPTIMIZE_MEMORY > 0
luaL_rometatable(L, "u8g.display", (void *)lu8g_display_map); // create metatable
return 0;
#else // #if LUA_OPTIMIZE_MEMORY > 0
int n;
luaL_register( L, AUXLIB_U8G, lu8g_map );
// Set it as its own metatable
lua_pushvalue( L, -1 );
lua_setmetatable( L, -2 );
// Module constants
// Register fonts
#undef U8G_FONT_TABLE_ENTRY
#define U8G_FONT_TABLE_ENTRY(font) MOD_REG_LUDATA( L, #font, (void *)(u8g_ ## font) );
U8G_FONT_TABLE
// Options for circle/ ellipse drawing
MOD_REG_NUMBER( L, "DRAW_UPPER_RIGHT", U8G_DRAW_UPPER_RIGHT );
MOD_REG_NUMBER( L, "DRAW_UPPER_LEFT", U8G_DRAW_UPPER_RIGHT );
MOD_REG_NUMBER( L, "DRAW_LOWER_RIGHT", U8G_DRAW_UPPER_RIGHT );
MOD_REG_NUMBER( L, "DRAW_LOWER_LEFT", U8G_DRAW_UPPER_RIGHT );
// Display modes
MOD_REG_NUMBER( L, "MODE_BW", U8G_MODE_BW );
MOD_REG_NUMBER( L, "MODE_GRAY2BIT", U8G_MODE_BW );
// create metatable
luaL_newmetatable(L, "u8g.display");
// metatable.__index = metatable
lua_pushliteral(L, "__index");
lua_pushvalue(L,-2);
lua_rawset(L,-3);
// Setup the methods inside metatable
luaL_register( L, NULL, u8g_display_map );
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
}
...@@ -8,47 +8,56 @@ ...@@ -8,47 +8,56 @@
* from user Markus Gritsch. * from user Markus Gritsch.
* I just put this code into its own module and pushed into a forked repo, * I just put this code into its own module and pushed into a forked repo,
* to easily create a pull request. Thanks to Markus Gritsch for the code. * to easily create a pull request. Thanks to Markus Gritsch for the code.
*
*/ */
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// -- This WS2812 code must be compiled with -O2 to get the timing right. // -- This WS2812 code must be compiled with -O2 to get the timing right. Read this:
// -- http://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/ // -- http://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
// The ICACHE_FLASH_ATTR is there to trick the compiler and get the very first pulse width correct. // -- The ICACHE_FLASH_ATTR is there to trick the compiler and get the very first pulse width correct.
static void ICACHE_FLASH_ATTR send_ws_0(uint8_t gpio) { static void ICACHE_FLASH_ATTR send_ws_0(uint8_t gpio) {
uint8_t i; uint8_t i;
i = 4; i = 4; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio);
while (i--) i = 9; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio);
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio);
i = 9;
while (i--)
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio);
} }
static void ICACHE_FLASH_ATTR send_ws_1(uint8_t gpio) { static void ICACHE_FLASH_ATTR send_ws_1(uint8_t gpio) {
uint8_t i; uint8_t i;
i = 8; i = 8; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio);
while (i--) i = 6; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio);
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio);
i = 6;
while (i--)
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio);
} }
// Lua: ws2812.write(pin, "string") // Lua: ws2812.write(pin, "string")
// Byte triples in the string are interpreted as G R B values. // Byte triples in the string are interpreted as R G B values and sent to the hardware as G R B.
// ws2812.write(4, string.char(0, 255, 0)) uses GPIO2 and sets the first LED red. // ws2812.write(4, string.char(255, 0, 0)) uses GPIO2 and sets the first LED red.
// ws2812.write(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue. // ws2812.write(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue.
// ws2812.write(4, string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white. // ws2812.write(4, string.char(0, 255, 0, 255, 255, 255)) first LED green, second LED white.
static int ICACHE_FLASH_ATTR ws2812_write(lua_State* L) { static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
{
const uint8_t pin = luaL_checkinteger(L, 1); const uint8_t pin = luaL_checkinteger(L, 1);
size_t length; size_t length;
const char *buffer = luaL_checklstring(L, 2, &length); char *buffer = (char *)luaL_checklstring(L, 2, &length); // Cast away the constness.
// Initialize the output pin:
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
platform_gpio_write(pin, 0); platform_gpio_write(pin, 0);
os_delay_us(10);
// Ignore incomplete Byte triples at the end of buffer:
length -= length % 3;
// Rearrange R G B values to G R B order needed by WS2812 LEDs:
size_t i;
for (i = 0; i < length; i += 3) {
const char r = buffer[i];
const char g = buffer[i + 1];
buffer[i] = g;
buffer[i + 1] = r;
}
// Do not remove these:
os_delay_us(1);
os_delay_us(1);
// Send the buffer:
os_intr_lock(); os_intr_lock();
const char * const end = buffer + length; const char * const end = buffer + length;
while (buffer != end) { while (buffer != end) {
...@@ -68,7 +77,7 @@ static int ICACHE_FLASH_ATTR ws2812_write(lua_State* L) { ...@@ -68,7 +77,7 @@ static int ICACHE_FLASH_ATTR ws2812_write(lua_State* L) {
#include "lrodefs.h" #include "lrodefs.h"
const LUA_REG_TYPE ws2812_map[] = const LUA_REG_TYPE ws2812_map[] =
{ {
{ LSTRKEY( "write" ), LFUNCVAL( ws2812_write )}, { LSTRKEY( "writergb" ), LFUNCVAL( ws2812_writergb )},
{ LNILKEY, LNILVAL} { LNILKEY, LNILVAL}
}; };
...@@ -77,6 +86,3 @@ LUALIB_API int luaopen_ws2812(lua_State *L) { ...@@ -77,6 +86,3 @@ LUALIB_API int luaopen_ws2812(lua_State *L) {
LREGISTER(L, "ws2812", ws2812_map); LREGISTER(L, "ws2812", ws2812_map);
return 1; return 1;
} }
// ----------------------------------------------------------------------------
...@@ -30,7 +30,11 @@ ...@@ -30,7 +30,11 @@
#elif defined(FLASH_16M) #elif defined(FLASH_16M)
#define FLASH_SEC_NUM 0x1000 #define FLASH_SEC_NUM 0x1000
#elif defined(FLASH_AUTOSIZE) #elif defined(FLASH_AUTOSIZE)
#define FLASH_SEC_NUM (flash_get_sec_num()) #if defined(FLASH_SAFE_API)
#define FLASH_SEC_NUM (flash_safe_get_sec_num())
#else
#define FLASH_SEC_NUM (flash_rom_get_sec_num())
#endif // defined(FLASH_SAFE_API)
#else #else
#define FLASH_SEC_NUM 0x80 #define FLASH_SEC_NUM 0x80
#endif #endif
...@@ -54,8 +58,14 @@ ...@@ -54,8 +58,14 @@
// SpiFlashOpResult spi_flash_erase_sector(uint16 sec); // SpiFlashOpResult spi_flash_erase_sector(uint16 sec);
// SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size); // SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size);
// SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size); // SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size);
#if defined(FLASH_SAFE_API)
#define flash_write flash_safe_write
#define flash_erase flash_safe_erase_sector
#define flash_read flash_safe_read
#else
#define flash_write spi_flash_write #define flash_write spi_flash_write
#define flash_erase spi_flash_erase_sector #define flash_erase spi_flash_erase_sector
#define flash_read spi_flash_read #define flash_read spi_flash_read
#endif // defined(FLASH_SAFE_API)
#endif // #ifndef __CPU_ESP8266_H__ #endif // #ifndef __CPU_ESP8266_H__
...@@ -20,74 +20,154 @@ static volatile const uint8_t flash_init_data[128] ICACHE_STORE_ATTR ICACHE_RODA ...@@ -20,74 +20,154 @@ static volatile const uint8_t flash_init_data[128] ICACHE_STORE_ATTR ICACHE_RODA
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
SPIFlashInfo flash_get_info(void) uint32_t flash_detect_size_byte(void)
{
#define FLASH_BUFFER_SIZE_DETECT 32
uint32_t dummy_size = FLASH_SIZE_256KBYTE;
uint8_t data_orig[FLASH_BUFFER_SIZE_DETECT] ICACHE_STORE_ATTR = {0};
uint8_t data_new[FLASH_BUFFER_SIZE_DETECT] ICACHE_STORE_ATTR = {0};
if (SPI_FLASH_RESULT_OK == flash_safe_read(0, (uint32 *)data_orig, FLASH_BUFFER_SIZE_DETECT))
{
dummy_size = FLASH_SIZE_256KBYTE;
while ((dummy_size < FLASH_SIZE_16MBYTE) &&
(SPI_FLASH_RESULT_OK == flash_safe_read(dummy_size, (uint32 *)data_new, FLASH_BUFFER_SIZE_DETECT)) &&
(0 != os_memcmp(data_orig, data_new, FLASH_BUFFER_SIZE_DETECT))
)
{
dummy_size *= 2;
}
};
return dummy_size;
#undef FLASH_BUFFER_SIZE_DETECT
}
uint32_t flash_safe_get_size_byte(void)
{
static uint32_t flash_size = 0;
if (flash_size == 0)
{
flash_size = flash_detect_size_byte();
}
return flash_size;
}
uint16_t flash_safe_get_sec_num(void)
{
return (flash_safe_get_size_byte() / (SPI_FLASH_SEC_SIZE));
}
SpiFlashOpResult flash_safe_read(uint32 src_addr, uint32 *des_addr, uint32 size)
{
SpiFlashOpResult result = SPI_FLASH_RESULT_ERR;
FLASH_SAFEMODE_ENTER();
result = spi_flash_read(src_addr, (uint32 *) des_addr, size);
FLASH_SAFEMODE_LEAVE();
return result;
}
SpiFlashOpResult flash_safe_write(uint32 des_addr, uint32 *src_addr, uint32 size)
{
SpiFlashOpResult result = SPI_FLASH_RESULT_ERR;
FLASH_SAFEMODE_ENTER();
result = spi_flash_write(des_addr, src_addr, size);
FLASH_SAFEMODE_LEAVE();
return result;
}
SpiFlashOpResult flash_safe_erase_sector(uint16 sec)
{
SpiFlashOpResult result = SPI_FLASH_RESULT_ERR;
FLASH_SAFEMODE_ENTER();
result = spi_flash_erase_sector(sec);
FLASH_SAFEMODE_LEAVE();
return result;
}
SPIFlashInfo flash_rom_getinfo(void)
{ {
volatile SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR; volatile SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR;
spi_flash_info = *((SPIFlashInfo *)(FLASH_MAP_START_ADDRESS)); // Don't use it before cache read disabled
// FLASH_DISABLE_CACHE();
// spi_flash_info = *((SPIFlashInfo *)(FLASH_ADDRESS_START_MAP));
// FLASH_ENABLE_CACHE();
// Needn't safe mode.
spi_flash_read(0, (uint32 *)(& spi_flash_info), sizeof(spi_flash_info));
return spi_flash_info; return spi_flash_info;
} }
uint8_t flash_get_size(void) uint8_t flash_rom_get_size_type(void)
{ {
return flash_get_info().size; return flash_rom_getinfo().size;
} }
uint32_t flash_get_size_byte(void) uint32_t flash_rom_get_size_byte(void)
{ {
uint32_t flash_size = 0; static uint32_t flash_size = 0;
switch (flash_get_info().size) if (flash_size == 0)
{ {
case SIZE_2MBIT: switch (flash_rom_getinfo().size)
// 2Mbit, 256kByte {
flash_size = 256 * 1024; case SIZE_2MBIT:
break; // 2Mbit, 256kByte
case SIZE_4MBIT: flash_size = 256 * 1024;
// 4Mbit, 512kByte break;
flash_size = 512 * 1024; case SIZE_4MBIT:
break; // 4Mbit, 512kByte
case SIZE_8MBIT: flash_size = 512 * 1024;
// 8Mbit, 1MByte break;
flash_size = 1 * 1024 * 1024; case SIZE_8MBIT:
break; // 8Mbit, 1MByte
case SIZE_16MBIT: flash_size = 1 * 1024 * 1024;
// 16Mbit, 2MByte break;
flash_size = 2 * 1024 * 1024; case SIZE_16MBIT:
break; // 16Mbit, 2MByte
case SIZE_32MBIT: flash_size = 2 * 1024 * 1024;
// 32Mbit, 4MByte break;
flash_size = 4 * 1024 * 1024; case SIZE_32MBIT:
case SIZE_64MBIT: // 32Mbit, 4MByte
// 64Mbit, 8MByte flash_size = 4 * 1024 * 1024;
flash_size = 8 * 1024 * 1024; break;
case SIZE_128MBIT: case SIZE_64MBIT:
// 128Mbit, 16MByte // 64Mbit, 8MByte
flash_size = 16 * 1024 * 1024; flash_size = 8 * 1024 * 1024;
break; break;
default: case SIZE_128MBIT:
// Unknown flash size, fall back mode. // 128Mbit, 16MByte
flash_size = 512 * 1024; flash_size = 16 * 1024 * 1024;
break; break;
default:
// Unknown flash size, fall back mode.
flash_size = 512 * 1024;
break;
}
} }
return flash_size; return flash_size;
} }
bool flash_set_size(uint8_t size) bool flash_rom_set_size_type(uint8_t size)
{ {
// Dangerous, here are dinosaur infested!!!!! // Dangerous, here are dinosaur infested!!!!!
// Reboot required!!! // Reboot required!!!
// If you don't know what you're doing, your nodemcu may turn into stone ... // If you don't know what you're doing, your nodemcu may turn into stone ...
NODE_DBG("\nBEGIN SET FLASH HEADER\n");
uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR; uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR;
spi_flash_read(0, (uint32 *)data, sizeof(data)); if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
SPIFlashInfo *p_spi_flash_info = (SPIFlashInfo *)(data); {
p_spi_flash_info->size = size; ((SPIFlashInfo *)(&data[0]))->size = size;
spi_flash_erase_sector(0); if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE))
spi_flash_write(0, (uint32 *)data, sizeof(data)); {
//p_spi_flash_info = flash_get_info(); NODE_DBG("\nERASE SUCCESS\n");
//p_spi_flash_info->size = size; }
if (SPI_FLASH_RESULT_OK == spi_flash_write(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nWRITE SUCCESS, %u\n", size);
}
}
NODE_DBG("\nEND SET FLASH HEADER\n");
return true; return true;
} }
bool flash_set_size_byte(uint32_t size) bool flash_rom_set_size_byte(uint32_t size)
{ {
// Dangerous, here are dinosaur infested!!!!! // Dangerous, here are dinosaur infested!!!!!
// Reboot required!!! // Reboot required!!!
...@@ -99,27 +179,37 @@ bool flash_set_size_byte(uint32_t size) ...@@ -99,27 +179,37 @@ bool flash_set_size_byte(uint32_t size)
case 256 * 1024: case 256 * 1024:
// 2Mbit, 256kByte // 2Mbit, 256kByte
flash_size = SIZE_2MBIT; flash_size = SIZE_2MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break; break;
case 512 * 1024: case 512 * 1024:
// 4Mbit, 512kByte // 4Mbit, 512kByte
flash_size = SIZE_4MBIT; flash_size = SIZE_4MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break; break;
case 1 * 1024 * 1024: case 1 * 1024 * 1024:
// 8Mbit, 1MByte // 8Mbit, 1MByte
flash_size = SIZE_8MBIT; flash_size = SIZE_8MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break; break;
case 2 * 1024 * 1024: case 2 * 1024 * 1024:
// 16Mbit, 2MByte // 16Mbit, 2MByte
flash_size = SIZE_16MBIT; flash_size = SIZE_16MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break; break;
case 4 * 1024 * 1024: case 4 * 1024 * 1024:
// 32Mbit, 4MByte // 32Mbit, 4MByte
flash_size = SIZE_32MBIT; flash_size = SIZE_32MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break;
case 8 * 1024 * 1024:
// 64Mbit, 8MByte
flash_size = SIZE_64MBIT;
flash_rom_set_size_type(flash_size);
break;
case 16 * 1024 * 1024:
// 128Mbit, 16MByte
flash_size = SIZE_128MBIT;
flash_rom_set_size_type(flash_size);
break; break;
default: default:
// Unknown flash size. // Unknown flash size.
...@@ -129,14 +219,22 @@ bool flash_set_size_byte(uint32_t size) ...@@ -129,14 +219,22 @@ bool flash_set_size_byte(uint32_t size)
return result; return result;
} }
uint16_t flash_get_sec_num(void) uint16_t flash_rom_get_sec_num(void)
{ {
return flash_get_size_byte() / SPI_FLASH_SEC_SIZE; //static uint16_t sec_num = 0;
// return flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE);
// c_printf("\nflash_rom_get_size_byte()=%d\n", ( flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE) ));
// if( sec_num == 0 )
//{
// sec_num = 4 * 1024 * 1024 / (SPI_FLASH_SEC_SIZE);
//}
//return sec_num;
return ( flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE) );
} }
uint8_t flash_get_mode(void) uint8_t flash_rom_get_mode(void)
{ {
SPIFlashInfo spi_flash_info = flash_get_info(); SPIFlashInfo spi_flash_info = flash_rom_getinfo();
switch (spi_flash_info.mode) switch (spi_flash_info.mode)
{ {
// Reserved for future use // Reserved for future use
...@@ -152,10 +250,10 @@ uint8_t flash_get_mode(void) ...@@ -152,10 +250,10 @@ uint8_t flash_get_mode(void)
return spi_flash_info.mode; return spi_flash_info.mode;
} }
uint32_t flash_get_speed(void) uint32_t flash_rom_get_speed(void)
{ {
uint32_t speed = 0; uint32_t speed = 0;
SPIFlashInfo spi_flash_info = flash_get_info(); SPIFlashInfo spi_flash_info = flash_rom_getinfo();
switch (spi_flash_info.speed) switch (spi_flash_info.speed)
{ {
case SPEED_40MHZ: case SPEED_40MHZ:
...@@ -178,11 +276,55 @@ uint32_t flash_get_speed(void) ...@@ -178,11 +276,55 @@ uint32_t flash_get_speed(void)
return speed; return speed;
} }
bool flash_rom_set_speed(uint32_t speed)
{
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// If you don't know what you're doing, your nodemcu may turn into stone ...
NODE_DBG("\nBEGIN SET FLASH HEADER\n");
uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR;
uint8_t speed_type = SPEED_40MHZ;
if (speed < 26700000)
{
speed_type = SPEED_20MHZ;
}
else if (speed < 40000000)
{
speed_type = SPEED_26MHZ;
}
else if (speed < 80000000)
{
speed_type = SPEED_40MHZ;
}
else if (speed >= 80000000)
{
speed_type = SPEED_80MHZ;
}
if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
((SPIFlashInfo *)(&data[0]))->speed = speed_type;
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nERASE SUCCESS\n");
}
if (SPI_FLASH_RESULT_OK == spi_flash_write(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nWRITE SUCCESS, %u\n", speed_type);
}
}
NODE_DBG("\nEND SET FLASH HEADER\n");
return true;
}
bool flash_init_data_written(void) bool flash_init_data_written(void)
{ {
// FLASH SEC - 4 // FLASH SEC - 4
uint32_t data[2] ICACHE_STORE_ATTR; uint32_t data[2] ICACHE_STORE_ATTR;
if (SPI_FLASH_RESULT_OK == spi_flash_read((flash_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data))) #if defined(FLASH_SAFE_API)
if (SPI_FLASH_RESULT_OK == flash_safe_read((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data)))
#else
if (SPI_FLASH_RESULT_OK == spi_flash_read((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data)))
#endif // defined(FLASH_SAFE_API)
{ {
if (data[0] == 0xFFFFFFFF && data[1] == 0xFFFFFFFF) if (data[0] == 0xFFFFFFFF && data[1] == 0xFFFFFFFF)
{ {
...@@ -199,13 +341,23 @@ bool flash_init_data_default(void) ...@@ -199,13 +341,23 @@ bool flash_init_data_default(void)
// Reboot required!!! // Reboot required!!!
// It will init system data to default! // It will init system data to default!
bool result = false; bool result = false;
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 4))) #if defined(FLASH_SAFE_API)
if (SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 4)))
{
if (SPI_FLASH_RESULT_OK == flash_safe_write((flash_safe_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)flash_init_data, 128))
{
result = true;
}
}
#else
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 4)))
{ {
if (SPI_FLASH_RESULT_OK == spi_flash_write((flash_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)flash_init_data, 128)) if (SPI_FLASH_RESULT_OK == spi_flash_write((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)flash_init_data, 128))
{ {
result = true; result = true;
} }
} }
#endif // defined(FLASH_SAFE_API)
return result; return result;
} }
...@@ -216,8 +368,13 @@ bool flash_init_data_blank(void) ...@@ -216,8 +368,13 @@ bool flash_init_data_blank(void)
// Reboot required!!! // Reboot required!!!
// It will init system config to blank! // It will init system config to blank!
bool result = false; bool result = false;
if ((SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 2))) && #if defined(FLASH_SAFE_API)
(SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 1)))) if ((SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_rom_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_rom_get_sec_num() - 1))))
#else
if ((SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 1))))
#endif // defined(FLASH_SAFE_API)
{ {
result = true; result = true;
} }
...@@ -232,13 +389,39 @@ bool flash_self_destruct(void) ...@@ -232,13 +389,39 @@ bool flash_self_destruct(void)
return true; return true;
} }
uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index) uint8_t byte_of_aligned_array(const uint8_t *aligned_array, uint32_t index)
{ {
if( (((uint32_t)aligned_array)%4) != 0 ){ if ( (((uint32_t)aligned_array) % 4) != 0 )
{
NODE_DBG("aligned_array is not 4-byte aligned.\n"); NODE_DBG("aligned_array is not 4-byte aligned.\n");
return 0; return 0;
} }
uint32_t v = ((uint32_t *)aligned_array)[ index/4 ]; uint32_t v = ((uint32_t *)aligned_array)[ index / 4 ];
uint8_t *p = (uint8_t *) (&v); uint8_t *p = (uint8_t *) (&v);
return p[ (index%4) ]; return p[ (index % 4) ];
} }
// uint8_t flash_rom_get_checksum(void)
// {
// // SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR = flash_rom_getinfo();
// // uint32_t address = sizeof(spi_flash_info) + spi_flash_info.segment_size;
// // uint32_t address_aligned_4bytes = (address + 3) & 0xFFFFFFFC;
// // uint8_t buffer[64] = {0};
// // spi_flash_read(address, (uint32 *) buffer, 64);
// // uint8_t i = 0;
// // c_printf("\nBEGIN DUMP\n");
// // for (i = 0; i < 64; i++)
// // {
// // c_printf("%02x," , buffer[i]);
// // }
// // i = (address + 0x10) & 0x10 - 1;
// // c_printf("\nSIZE:%d CHECK SUM:%02x\n", spi_flash_info.segment_size, buffer[i]);
// // c_printf("\nEND DUMP\n");
// // return buffer[0];
// return 0;
// }
// uint8_t flash_rom_calc_checksum(void)
// {
// return 0;
// }
\ No newline at end of file
...@@ -3,34 +3,62 @@ ...@@ -3,34 +3,62 @@
#include "ets_sys.h" #include "ets_sys.h"
#include "user_config.h" #include "user_config.h"
#include "cpu_esp8266.h" #include "cpu_esp8266.h"
#define FLASH_MAP_START_ADDRESS (INTERNAL_FLASH_START_ADDRESS)
#define FLASH_ADDRESS_START_MAP (INTERNAL_FLASH_START_ADDRESS)
#define FLASH_SIZE_2MBIT (2 * 1024 * 1024)
#define FLASH_SIZE_4MBIT (4 * 1024 * 1024)
#define FLASH_SIZE_8MBIT (8 * 1024 * 1024)
#define FLASH_SIZE_16MBIT (16 * 1024 * 1024)
#define FLASH_SIZE_32MBIT (32 * 1024 * 1024)
#define FLASH_SIZE_64MBIT (64 * 1024 * 1024)
#define FLASH_SIZE_128MBIT (128 * 1024 * 1024)
#define FLASH_SIZE_256KBYTE (FLASH_SIZE_2MBIT / 8)
#define FLASH_SIZE_512KBYTE (FLASH_SIZE_4MBIT / 8)
#define FLASH_SIZE_1MBYTE (FLASH_SIZE_8MBIT / 8)
#define FLASH_SIZE_2MBYTE (FLASH_SIZE_16MBIT / 8)
#define FLASH_SIZE_4MBYTE (FLASH_SIZE_32MBIT / 8)
#define FLASH_SIZE_8MBYTE (FLASH_SIZE_64MBIT / 8)
#define FLASH_SIZE_16MBYTE (FLASH_SIZE_128MBIT/ 8)
#define FLASH_SAFEMODE_ENTER() \
do { \
extern SpiFlashChip * flashchip; \
flashchip->chip_size = FLASH_SIZE_16MBYTE
#define FLASH_SAFEMODE_LEAVE() \
flashchip->chip_size = flash_rom_get_size_byte(); \
} while(0)
/****************************************************************************** /******************************************************************************
* ROM Function definition * ROM Function definition
* Note: It is unsafe to use ROM function, but it may efficient. * Note: It is unsafe to use ROM function, but it may efficient.
* SPIEraseSector * SPIEraseSector
* unknown SPIEraseSector(uint16 sec); * SpiFlashOpResult SPIEraseSector(uint16 sec);
* The 1st parameter is flash sector number. * The 1st parameter is flash sector number.
* Note: Must disable cache read before using it.
* SPIRead (Unsafe) * SPIRead
* unknown SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size); * SpiFlashOpResult SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size);
* The 1st parameter is source addresses. * The 1st parameter is source addresses.
* The 2nd parameter is destination addresses. * The 2nd parameter is destination addresses.
* The 3rd parameter is size. * The 3rd parameter is size.
* Note: Sometimes it have no effect, may be need a delay or other option(lock or unlock, etc.) with known reason. * Note: Must disable cache read before using it.
* SPIWrite (Unsafe) * SPIWrite
* unknown SPIWrite(uint32_t des_addr, uint32_t *src_addr, uint32_t size); * SpiFlashOpResult SPIWrite(uint32_t des_addr, uint32_t *src_addr, uint32_t size);
* The 1st parameter is destination addresses. * The 1st parameter is destination addresses.
* The 2nd parameter is source addresses. * The 2nd parameter is source addresses.
* The 3rd parameter is size. * The 3rd parameter is size.
* Note: Sometimes it have no effect, may be need a delay or other option(lock or unlock, etc.) with known reason. * Note: Must disable cache read before using it.
*******************************************************************************/ *******************************************************************************/
typedef struct typedef struct
{ {
uint8_t unknown0; uint8_t header_magic;
uint8_t unknown1; uint8_t segment_count;
enum enum
{ {
MODE_QIO = 0, MODE_QIO = 0,
...@@ -55,20 +83,31 @@ typedef struct ...@@ -55,20 +83,31 @@ typedef struct
SIZE_64MBIT = 5, SIZE_64MBIT = 5,
SIZE_128MBIT = 6, SIZE_128MBIT = 6,
} size : 4; } size : 4;
uint32_t entry_point;
uint32_t memory_offset;
uint32_t segment_size;
} ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo; } ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo;
SPIFlashInfo flash_get_info(void); uint32_t flash_detect_size_byte(void);
uint8_t flash_get_size(void); uint32_t flash_safe_get_size_byte(void);
uint32_t flash_get_size_byte(void); uint16_t flash_safe_get_sec_num(void);
bool flash_set_size(uint8_t); SpiFlashOpResult flash_safe_read(uint32 src_addr, uint32 *des_addr, uint32 size);
bool flash_set_size_byte(uint32_t); SpiFlashOpResult flash_safe_write(uint32 des_addr, uint32 *src_addr, uint32 size);
uint16_t flash_get_sec_num(void); SpiFlashOpResult flash_safe_erase_sector(uint16 sec);
uint8_t flash_get_mode(void); SPIFlashInfo flash_rom_getinfo(void);
uint32_t flash_get_speed(void); uint8_t flash_rom_get_size_type(void);
uint32_t flash_rom_get_size_byte(void);
bool flash_rom_set_size_type(uint8_t);
bool flash_rom_set_size_byte(uint32_t);
uint16_t flash_rom_get_sec_num(void);
uint8_t flash_rom_get_mode(void);
uint32_t flash_rom_get_speed(void);
bool flash_init_data_written(void); bool flash_init_data_written(void);
bool flash_init_data_default(void); bool flash_init_data_default(void);
bool flash_init_data_blank(void); bool flash_init_data_blank(void);
bool flash_self_destruct(void); bool flash_self_destruct(void);
uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index); uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index);
// uint8_t flash_rom_get_checksum(void);
// uint8_t flash_rom_calc_checksum(void);
#endif // __FLASH_API_H__ #endif // __FLASH_API_H__
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#define fs_format myspiffs_format #define fs_format myspiffs_format
#define fs_check myspiffs_check #define fs_check myspiffs_check
#define fs_rename myspiffs_rename #define fs_rename myspiffs_rename
#define fs_size myspiffs_size
#define FS_NAME_MAX_LENGTH SPIFFS_OBJ_NAME_LEN #define FS_NAME_MAX_LENGTH SPIFFS_OBJ_NAME_LEN
......
...@@ -160,11 +160,14 @@ int myspiffs_error( int fd ){ ...@@ -160,11 +160,14 @@ int myspiffs_error( int fd ){
return SPIFFS_errno(&fs); return SPIFFS_errno(&fs);
} }
void myspiffs_clearerr( int fd ){ void myspiffs_clearerr( int fd ){
fs.errno = SPIFFS_OK; SPIFFS_clearerr(&fs);
} }
int myspiffs_rename( const char *old, const char *newname ){ int myspiffs_rename( const char *old, const char *newname ){
return SPIFFS_rename(&fs, (char *)old, (char *)newname); return SPIFFS_rename(&fs, (char *)old, (char *)newname);
} }
size_t myspiffs_size( int fd ){
return SPIFFS_size(&fs, (spiffs_file)fd);
}
#if 0 #if 0
void test_spiffs() { void test_spiffs() {
char buf[12]; char buf[12];
......
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
#ifndef SPIFFS_H_ #ifndef SPIFFS_H_
#define SPIFFS_H_ #define SPIFFS_H_
#if defined(__cplusplus)
extern "C" {
#endif
#include "c_stdio.h" #include "c_stdio.h"
#include "spiffs_config.h" #include "spiffs_config.h"
...@@ -181,7 +185,7 @@ typedef struct { ...@@ -181,7 +185,7 @@ typedef struct {
u32_t fd_count; u32_t fd_count;
// last error // last error
s32_t errno; s32_t err_code;
// current number of free blocks // current number of free blocks
u32_t free_blocks; u32_t free_blocks;
...@@ -375,9 +379,9 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh); ...@@ -375,9 +379,9 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh);
* Renames a file * Renames a file
* @param fs the file system struct * @param fs the file system struct
* @param old path of file to rename * @param old path of file to rename
* @param new new path of file * @param newPath new path of file
*/ */
s32_t SPIFFS_rename(spiffs *fs, char *old, char *new); s32_t SPIFFS_rename(spiffs *fs, char *old, char *newPath);
/** /**
* Returns last error of last file operation. * Returns last error of last file operation.
...@@ -385,6 +389,12 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new); ...@@ -385,6 +389,12 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new);
*/ */
s32_t SPIFFS_errno(spiffs *fs); s32_t SPIFFS_errno(spiffs *fs);
/**
* Clears last error.
* @param fs the file system struct
*/
void SPIFFS_clearerr(spiffs *fs);
/** /**
* Opens a directory stream corresponding to the given name. * Opens a directory stream corresponding to the given name.
* The stream is positioned at the first entry in the directory. * The stream is positioned at the first entry in the directory.
...@@ -416,6 +426,21 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e); ...@@ -416,6 +426,21 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
*/ */
s32_t SPIFFS_check(spiffs *fs); s32_t SPIFFS_check(spiffs *fs);
/**
* Returns number of total bytes available and number of used bytes.
* This is an estimation, and depends on if there a many files with little
* data or few files with much data.
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
* run. This indicates a power loss in midst of things. In worst case
* (repeated powerlosses in mending or gc) you might have to delete some files.
*
* @param fs the file system struct
* @param total total number of bytes in filesystem
* @param used used number of bytes in filesystem
*/
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
/** /**
* Check if EOF reached. * Check if EOF reached.
* @param fs the file system struct * @param fs the file system struct
...@@ -423,6 +448,7 @@ s32_t SPIFFS_check(spiffs *fs); ...@@ -423,6 +448,7 @@ s32_t SPIFFS_check(spiffs *fs);
*/ */
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh); s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh); s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_size(spiffs *fs, spiffs_file fh);
#if SPIFFS_TEST_VISUALISATION #if SPIFFS_TEST_VISUALISATION
/** /**
...@@ -465,5 +491,10 @@ int myspiffs_error( int fd ); ...@@ -465,5 +491,10 @@ int myspiffs_error( int fd );
void myspiffs_clearerr( int fd ); void myspiffs_clearerr( int fd );
int myspiffs_check( void ); int myspiffs_check( void );
int myspiffs_rename( const char *old, const char *newname ); int myspiffs_rename( const char *old, const char *newname );
size_t myspiffs_size( int fd );
#if defined(__cplusplus)
}
#endif
#endif /* SPIFFS_H_ */ #endif /* SPIFFS_H_ */
...@@ -30,19 +30,19 @@ typedef uint8_t u8_t; ...@@ -30,19 +30,19 @@ typedef uint8_t u8_t;
// Set generic spiffs debug output call. // Set generic spiffs debug output call.
#ifndef SPIFFS_DGB #ifndef SPIFFS_DGB
#define SPIFFS_DBG(...) #define SPIFFS_DBG(...) //printf(__VA_ARGS__)
#endif #endif
// Set spiffs debug output call for garbage collecting. // Set spiffs debug output call for garbage collecting.
#ifndef SPIFFS_GC_DGB #ifndef SPIFFS_GC_DGB
#define SPIFFS_GC_DBG(...) #define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
#endif #endif
// Set spiffs debug output call for caching. // Set spiffs debug output call for caching.
#ifndef SPIFFS_CACHE_DGB #ifndef SPIFFS_CACHE_DGB
#define SPIFFS_CACHE_DBG(...) #define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
#endif #endif
// Set spiffs debug output call for system consistency checks. // Set spiffs debug output call for system consistency checks.
#ifndef SPIFFS_CHECK_DGB #ifndef SPIFFS_CHECK_DGB
#define SPIFFS_CHECK_DBG(...) #define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
#endif #endif
// Enable/disable API functions to determine exact number of bytes // Enable/disable API functions to determine exact number of bytes
...@@ -77,7 +77,7 @@ typedef uint8_t u8_t; ...@@ -77,7 +77,7 @@ typedef uint8_t u8_t;
// Define maximum number of gc runs to perform to reach desired free pages. // Define maximum number of gc runs to perform to reach desired free pages.
#ifndef SPIFFS_GC_MAX_RUNS #ifndef SPIFFS_GC_MAX_RUNS
#define SPIFFS_GC_MAX_RUNS 3 #define SPIFFS_GC_MAX_RUNS 5
#endif #endif
// Enable/disable statistics on gc. Debug/test purpose only. // Enable/disable statistics on gc. Debug/test purpose only.
......
...@@ -119,16 +119,21 @@ s32_t spiffs_gc_check( ...@@ -119,16 +119,21 @@ s32_t spiffs_gc_check(
spiffs *fs, spiffs *fs,
u32_t len) { u32_t len) {
s32_t res; s32_t res;
u32_t free_pages = s32_t free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
- fs->stats_p_allocated - fs->stats_p_deleted; - fs->stats_p_allocated - fs->stats_p_deleted;
int tries = 0; int tries = 0;
if (fs->free_blocks > 3 && if (fs->free_blocks > 3 &&
len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) { (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
return SPIFFS_OK; return SPIFFS_OK;
} }
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
return SPIFFS_ERR_FULL;
}
//printf("gcing started %i dirty, blocks %i free, want %i bytes\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len); //printf("gcing started %i dirty, blocks %i free, want %i bytes\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len);
do { do {
...@@ -168,16 +173,22 @@ s32_t spiffs_gc_check( ...@@ -168,16 +173,22 @@ s32_t spiffs_gc_check(
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
free_pages = free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
- fs->stats_p_allocated - fs->stats_p_deleted; - fs->stats_p_allocated - fs->stats_p_deleted;
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs))); (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
SPIFFS_GC_DBG("gc_check: finished\n");
free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
- fs->stats_p_allocated - fs->stats_p_deleted;
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
res = SPIFFS_ERR_FULL;
}
//printf("gcing finished %i dirty, blocks %i free, %i pages free, %i tries, res %i\n", SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n",
// fs->stats_p_allocated + fs->stats_p_deleted, fs->stats_p_allocated + fs->stats_p_deleted,
// fs->free_blocks, free_pages, tries, res); fs->free_blocks, free_pages, tries, res);
return res; return res;
} }
......
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