Commit abfdb58d authored by markusgritsch's avatar markusgritsch
Browse files

Merge pull request #4 from nodemcu/dev

Dev
parents dadd2ae9 d8c8d257
...@@ -8,13 +8,21 @@ install: ...@@ -8,13 +8,21 @@ install:
script: script:
- make all - make all
- cd bin/ - cd bin/
- file_name="nodemcu-firmware_v${TRAVIS_TAG}.${TRAVIS_BUILD_NUMBER}.bin" - file_name_float="nodemcu_float_${TRAVIS_TAG}.bin"
- srec_cat -output ${file_name} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000 - srec_cat -output ${file_name_float} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000
- cd ../
- make clean
- make EXTRA_CCFLAGS="-DLUA_NUMBER_INTEGRAL"
- cd bin/
- file_name_integer="nodemcu_integer_${TRAVIS_TAG}.bin"
- srec_cat -output ${file_name_integer} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000
deploy: deploy:
provider: releases provider: releases
api_key: api_key:
secure: Swecz5lWvsuSbchSbVQ1rmCPN9nQIN5p/HlZNIEdEgAgnoLcJxRV4P8poVTB37jiA8Pck+8x2nWXpg74Rqik0i3KlPNvDfg5o4rIazWLNs4bc1Tbcpt44XAzFKKLYnDnWQUGcqjk7BcAXuNAF2X/fPBCVhFbHVg3Z7cDb32RsNw= secure: Swecz5lWvsuSbchSbVQ1rmCPN9nQIN5p/HlZNIEdEgAgnoLcJxRV4P8poVTB37jiA8Pck+8x2nWXpg74Rqik0i3KlPNvDfg5o4rIazWLNs4bc1Tbcpt44XAzFKKLYnDnWQUGcqjk7BcAXuNAF2X/fPBCVhFbHVg3Z7cDb32RsNw=
file: "$TRAVIS_BUILD_DIR/bin/${file_name}" file:
- "$TRAVIS_BUILD_DIR/bin/${file_name_float}"
- "$TRAVIS_BUILD_DIR/bin/${file_name_integer}"
skip_cleanup: true skip_cleanup: true
on: on:
tags: true tags: true
......
# **NodeMCU** # # **NodeMCU** #
version 0.9.5 version 0.9.5
[![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware) [![Join the chat at https://gitter.im/nodemcu/nodemcu-firmware](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nodemcu/nodemcu-firmware?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware) [![Download](https://img.shields.io/badge/download-~400k-orange.svg)](https://github.com/nodemcu/nodemcu-firmware/releases/latest)
###A lua based firmware for wifi-soc esp8266 ###A lua based firmware for wifi-soc esp8266
Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)<br /> Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)<br />
...@@ -33,6 +34,23 @@ Tencent QQ group: 309957875<br /> ...@@ -33,6 +34,23 @@ Tencent QQ group: 309957875<br />
- cross compiler (done) - cross compiler (done)
# Change log # Change log
2015-03-15<br />
bugs fixed: #239, #273.<br />
reduce coap module memory usage, add coap module to default built.
2015-03-11<br />
fix bugs of spiffs.<br />
build both float and integer version [latest releases](https://github.com/nodemcu/nodemcu-firmware/releases/latest).<br />
fix tmr.time().<br />
fix memory leak when DNS fail.
2015-03-10<br />
update to the recent spiffs.<br />
add file.fsinfo() api, usage: remain, used, total = file.fsinfo().<br />
add Travis CI. please download the latest firmware from [releases](https://github.com/nodemcu/nodemcu-firmware/releases).<br />
add math lib, partial api work.<br />
u8g module, ws2812 module default enabled in dev-branch build.
2015-02-13<br /> 2015-02-13<br />
add node.compile() api to compile lua text file into lua bytecode file.<br /> add node.compile() api to compile lua text file into lua bytecode file.<br />
this will reduce memory usage noticeably when require modules into NodeMCU.<br /> this will reduce memory usage noticeably when require modules into NodeMCU.<br />
...@@ -400,3 +418,25 @@ They'll be available as `u8g.<font_name>` in Lua. ...@@ -400,3 +418,25 @@ They'll be available as `u8g.<font_name>` in Lua.
-- first LED green, second LED white -- first LED green, second LED white
ws2812.writergb(4, string.char(0, 255, 0, 255, 255, 255)) ws2812.writergb(4, string.char(0, 255, 0, 255, 255, 255))
``` ```
####coap client and server
```lua
-- use copper addon for firefox
cs=coap.Server()
cs:listen(5683)
myvar=1
cs:var("myvar") -- get coap://192.168.18.103:5683/v1/v/myvar will return the value of myvar: 1
-- function should tack one string, return one string.
function myfun(payload)
print("myfun called")
respond = "hello"
return respond
end
cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun
cc = coap.Client()
cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core")
cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello")
```
\ No newline at end of file
...@@ -76,7 +76,7 @@ int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8 ...@@ -76,7 +76,7 @@ int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8
else else
if (hdr->tkl <= 8) if (hdr->tkl <= 8)
{ {
if (4 + hdr->tkl > buflen) if (4U + hdr->tkl > buflen)
return COAP_ERR_TOKEN_TOO_SHORT; // tok bigger than packet return COAP_ERR_TOKEN_TOO_SHORT; // tok bigger than packet
tokbuf->p = buf+4; // past header tokbuf->p = buf+4; // past header
tokbuf->len = hdr->tkl; tokbuf->len = hdr->tkl;
...@@ -93,7 +93,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8 ...@@ -93,7 +93,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8
{ {
// inject token // inject token
uint8_t *p; uint8_t *p;
if (buflen < 4 + hdr->tkl) if (buflen < (4U + hdr->tkl))
return COAP_ERR_BUFFER_TOO_SMALL; return COAP_ERR_BUFFER_TOO_SMALL;
p = buf + 4; p = buf + 4;
if ((hdr->tkl > 0) && (hdr->tkl != tokbuf->len)) if ((hdr->tkl > 0) && (hdr->tkl != tokbuf->len))
...@@ -102,7 +102,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8 ...@@ -102,7 +102,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8
if (hdr->tkl > 0) if (hdr->tkl > 0)
c_memcpy(p, tokbuf->p, hdr->tkl); c_memcpy(p, tokbuf->p, hdr->tkl);
// http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3.1 // http://tools.ietf.org/html/rfc7252#section-3.1
// inject options // inject options
return hdr->tkl; return hdr->tkl;
} }
...@@ -111,8 +111,8 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8 ...@@ -111,8 +111,8 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8
int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen) int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen)
{ {
const uint8_t *p = *buf; const uint8_t *p = *buf;
uint16_t len, delta;
uint8_t headlen = 1; uint8_t headlen = 1;
uint16_t len, delta;
if (buflen < headlen) // too small if (buflen < headlen) // too small
return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER; return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
...@@ -179,14 +179,14 @@ int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8 ...@@ -179,14 +179,14 @@ int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8
return 0; return 0;
} }
// http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3.1 // http://tools.ietf.org/html/rfc7252#section-3.1
int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coap_buffer_t *payload, const coap_header_t *hdr, const uint8_t *buf, size_t buflen) int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coap_buffer_t *payload, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)
{ {
size_t optionIndex = 0; size_t optionIndex = 0;
uint16_t delta = 0;
const uint8_t *p = buf + 4 + hdr->tkl; const uint8_t *p = buf + 4 + hdr->tkl;
const uint8_t *end = buf + buflen; const uint8_t *end = buf + buflen;
int rc; int rc;
uint16_t delta = 0;
if (p > end) if (p > end)
return COAP_ERR_OPTION_OVERRUNS_PACKET; // out of bounds return COAP_ERR_OPTION_OVERRUNS_PACKET; // out of bounds
...@@ -215,7 +215,7 @@ int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coa ...@@ -215,7 +215,7 @@ int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coa
return 0; return 0;
} }
int coap_buildOptionHeader(unsigned short optDelta, size_t length, uint8_t *buf, size_t buflen) int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen)
{ {
int n = 0; int n = 0;
uint8_t *p = buf; uint8_t *p = buf;
...@@ -298,7 +298,7 @@ int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen) ...@@ -298,7 +298,7 @@ int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen)
} }
// options are always stored consecutively, so can return a block with same option num // options are always stored consecutively, so can return a block with same option num
const coap_option_t * coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count) const coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count)
{ {
// FIXME, options is always sorted, can find faster than this // FIXME, options is always sorted, can find faster than this
size_t i; size_t i;
...@@ -352,7 +352,7 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt) ...@@ -352,7 +352,7 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)
uint16_t optDelta = 0; uint16_t optDelta = 0;
int rc = 0; int rc = 0;
if (p-buf > *buflen) if (((size_t)(p-buf)) > *buflen)
return COAP_ERR_BUFFER_TOO_SMALL; return COAP_ERR_BUFFER_TOO_SMALL;
optDelta = pkt->opts[i].num - running_delta; optDelta = pkt->opts[i].num - running_delta;
...@@ -381,17 +381,17 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt) ...@@ -381,17 +381,17 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)
return 0; return 0;
} }
void coap_option_nibble(uint16_t value, uint8_t *nibble) void coap_option_nibble(uint32_t value, uint8_t *nibble)
{ {
if (value<13) if (value<13)
{ {
*nibble = (0xFF & value); *nibble = (0xFF & value);
} }
else else
if (((uint32_t)value)<=0xFF+13) if (value<=0xFF+13)
{ {
*nibble = 13; *nibble = 13;
} else if (((uint32_t)value) -269 <=0xFFFF) } else if (value<=0xFFFF+269)
{ {
*nibble = 14; *nibble = 14;
} }
...@@ -405,7 +405,7 @@ int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint ...@@ -405,7 +405,7 @@ int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint
pkt->hdr.code = rspcode; pkt->hdr.code = rspcode;
pkt->hdr.id[0] = msgid_hi; pkt->hdr.id[0] = msgid_hi;
pkt->hdr.id[1] = msgid_lo; pkt->hdr.id[1] = msgid_lo;
pkt->numopts = 0; pkt->numopts = 1;
// need token in response // need token in response
if (tok) { if (tok) {
...@@ -442,7 +442,7 @@ unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val) { ...@@ -442,7 +442,7 @@ unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val) {
return n; return n;
} }
static uint8_t _token_data[4]={'n','o','d','e'}; static uint8_t _token_data[4] = {'n','o','d','e'};
coap_buffer_t the_token = { _token_data, 4 }; coap_buffer_t the_token = { _token_data, 4 };
static unsigned short message_id; static unsigned short message_id;
......
...@@ -18,13 +18,15 @@ extern "C" { ...@@ -18,13 +18,15 @@ extern "C" {
#define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF) #define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF)
// http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3 //http://tools.ietf.org/html/rfc7252#section-3
typedef struct typedef struct
{ {
uint8_t ver; uint8_t ver; /* CoAP version number */
uint8_t t; uint8_t t; /* CoAP Message Type */
uint8_t tkl; uint8_t tkl; /* Token length: indicates length of the Token field */
uint8_t code; uint8_t code; /* CoAP status code. Can be request (0.xx), success reponse (2.xx),
* client error response (4.xx), or rever error response (5.xx)
* For possible values, see http://tools.ietf.org/html/rfc7252#section-12.1 */
uint8_t id[2]; uint8_t id[2];
} coap_header_t; } coap_header_t;
...@@ -42,23 +44,24 @@ typedef struct ...@@ -42,23 +44,24 @@ typedef struct
typedef struct typedef struct
{ {
uint8_t num; uint8_t num; /* Option number. See http://tools.ietf.org/html/rfc7252#section-5.10 */
coap_buffer_t buf; coap_buffer_t buf; /* Option value */
} coap_option_t; } coap_option_t;
typedef struct typedef struct
{ {
coap_header_t hdr; coap_header_t hdr; /* Header of the packet */
coap_buffer_t tok; coap_buffer_t tok; /* Token value, size as specified by hdr.tkl */
uint8_t numopts; uint8_t numopts; /* Number of options */
coap_option_t opts[MAXOPT]; coap_option_t opts[MAXOPT]; /* Options of the packet. For possible entries see
coap_buffer_t payload; * http://tools.ietf.org/html/rfc7252#section-5.10 */
coap_rw_buffer_t scratch; // scratch->p = malloc(...) , and free it when done. coap_buffer_t payload; /* Payload carried by the packet */
coap_rw_buffer_t content; // content->p = malloc(...) , and free it when done.
} coap_packet_t; } coap_packet_t;
///////////////////////////////////////// /////////////////////////////////////////
//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.2 //http://tools.ietf.org/html/rfc7252#section-12.2
typedef enum typedef enum
{ {
COAP_OPTION_IF_MATCH = 1, COAP_OPTION_IF_MATCH = 1,
...@@ -78,7 +81,7 @@ typedef enum ...@@ -78,7 +81,7 @@ typedef enum
COAP_OPTION_PROXY_SCHEME = 39 COAP_OPTION_PROXY_SCHEME = 39
} coap_option_num_t; } coap_option_num_t;
//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.1 //http://tools.ietf.org/html/rfc7252#section-12.1.1
typedef enum typedef enum
{ {
COAP_METHOD_GET = 1, COAP_METHOD_GET = 1,
...@@ -87,7 +90,7 @@ typedef enum ...@@ -87,7 +90,7 @@ typedef enum
COAP_METHOD_DELETE = 4 COAP_METHOD_DELETE = 4
} coap_method_t; } coap_method_t;
//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.1 //http://tools.ietf.org/html/rfc7252#section-12.1.1
typedef enum typedef enum
{ {
COAP_TYPE_CON = 0, COAP_TYPE_CON = 0,
...@@ -96,8 +99,8 @@ typedef enum ...@@ -96,8 +99,8 @@ typedef enum
COAP_TYPE_RESET = 3 COAP_TYPE_RESET = 3
} coap_msgtype_t; } coap_msgtype_t;
//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-5.2 //http://tools.ietf.org/html/rfc7252#section-5.2
//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.2 //http://tools.ietf.org/html/rfc7252#section-12.1.2
#define MAKE_RSPCODE(clas, det) ((clas << 5) | (det)) #define MAKE_RSPCODE(clas, det) ((clas << 5) | (det))
typedef enum typedef enum
{ {
...@@ -107,7 +110,7 @@ typedef enum ...@@ -107,7 +110,7 @@ typedef enum
COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4) COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4)
} coap_responsecode_t; } coap_responsecode_t;
//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.3 //http://tools.ietf.org/html/rfc7252#section-12.3
typedef enum typedef enum
{ {
COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block
...@@ -155,15 +158,21 @@ struct coap_luser_entry{ ...@@ -155,15 +158,21 @@ struct coap_luser_entry{
coap_luser_entry *next; coap_luser_entry *next;
}; };
struct coap_endpoint_t struct coap_endpoint_t{
{ coap_method_t method; /* (i.e. POST, PUT or GET) */
coap_method_t method; coap_endpoint_func handler; /* callback function which handles this
coap_endpoint_func handler; * type of endpoint (and calls
const coap_endpoint_path_t *path; * coap_make_response() at some point) */
const char *core_attr; const coap_endpoint_path_t *path; /* path towards a resource (i.e. foo/bar/) */
coap_luser_entry *user_entry; const char *core_attr; /* the 'ct' attribute, as defined in RFC7252, section 7.2.1.:
* "The Content-Format code "ct" attribute
* provides a hint about the
* Content-Formats this resource returns."
* (Section 12.3. lists possible ct values.) */
coap_luser_entry *user_entry;
}; };
/////////////////////// ///////////////////////
void coap_dumpPacket(coap_packet_t *pkt); void coap_dumpPacket(coap_packet_t *pkt);
int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen); int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen);
...@@ -173,11 +182,11 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt); ...@@ -173,11 +182,11 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt);
void coap_dump(const uint8_t *buf, size_t buflen, bool bare); void coap_dump(const uint8_t *buf, size_t buflen, bool bare);
int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, uint8_t msgid_hi, uint8_t msgid_lo, const coap_buffer_t* tok, coap_responsecode_t rspcode, coap_content_type_t content_type); int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, uint8_t msgid_hi, uint8_t msgid_lo, const coap_buffer_t* tok, coap_responsecode_t rspcode, coap_content_type_t content_type);
int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt); int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt);
void coap_option_nibble(uint16_t value, uint8_t *nibble); void coap_option_nibble(uint32_t value, uint8_t *nibble);
void coap_setup(void); void coap_setup(void);
void endpoint_setup(void); void endpoint_setup(void);
int coap_buildOptionHeader(unsigned short optDelta, size_t length, uint8_t *buf, size_t buflen); int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -11,6 +11,8 @@ void coap_client_response_handler(char *data, unsigned short len, unsigned short ...@@ -11,6 +11,8 @@ void coap_client_response_handler(char *data, unsigned short len, unsigned short
{ {
NODE_DBG("coap_client_response_handler is called.\n"); NODE_DBG("coap_client_response_handler is called.\n");
coap_packet_t pkt; coap_packet_t pkt;
pkt.content.p = NULL;
pkt.content.len = 0;
int rc; int rc;
if (0 != (rc = coap_parse(&pkt, data, len))){ if (0 != (rc = coap_parse(&pkt, data, len))){
......
#ifndef _COAP_SERVER_H #ifndef _COAP_CLIENT_H
#define _COAP_SERVER_H 1 #define _COAP_CLIENT_H 1
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
size_t coap_server_respond(char *data, unsigned short len, unsigned short size); void coap_client_response_handler(char *data, unsigned short len, unsigned short size, const uint32_t ip, const uint32_t port);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
#include "user_config.h" #include "user_config.h"
#include "c_types.h" #include "c_types.h"
#include "c_stdlib.h"
#include "coap.h" #include "coap.h"
size_t coap_server_respond(char *data, unsigned short len, unsigned short size) size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned short rsplen)
{ {
NODE_DBG("coap_server_respond is called.\n"); NODE_DBG("coap_server_respond is called.\n");
if(len>size){ size_t rlen = rsplen;
NODE_DBG("len:%d, size:%d\n",len,size);
return 0;
}
size_t rsplen = size;
coap_packet_t pkt; coap_packet_t pkt;
pkt.content.p = NULL;
pkt.content.len = 0;
uint8_t scratch_raw[4]; uint8_t scratch_raw[4];
coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)}; coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};
int rc; int rc;
#ifdef COAP_DEBUG #ifdef COAP_DEBUG
NODE_DBG("Received: "); NODE_DBG("Received: ");
coap_dump(data, len, true); coap_dump(req, reqlen, true);
NODE_DBG("\n"); NODE_DBG("\n");
#endif #endif
if (0 != (rc = coap_parse(&pkt, data, len))){ if (0 != (rc = coap_parse(&pkt, req, reqlen))){
NODE_DBG("Bad packet rc=%d\n", rc); NODE_DBG("Bad packet rc=%d\n", rc);
return 0; return 0;
} }
else else
{ {
coap_packet_t rsppkt; coap_packet_t rsppkt;
rsppkt.content.p = NULL;
rsppkt.content.len = 0;
#ifdef COAP_DEBUG #ifdef COAP_DEBUG
coap_dumpPacket(&pkt); coap_dumpPacket(&pkt);
#endif #endif
coap_handle_req(&scratch_buf, &pkt, &rsppkt); coap_handle_req(&scratch_buf, &pkt, &rsppkt);
if (0 != (rc = coap_build(data, &rsplen, &rsppkt))){ if (0 != (rc = coap_build(rsp, &rlen, &rsppkt))){
NODE_DBG("coap_build failed rc=%d\n", rc); NODE_DBG("coap_build failed rc=%d\n", rc);
return 0; // return 0;
rlen = 0;
} }
else else
{ {
#ifdef COAP_DEBUG #ifdef COAP_DEBUG
NODE_DBG("Responding: "); NODE_DBG("Responding: ");
coap_dump(data, rsplen, true); coap_dump(rsp, rlen, true);
NODE_DBG("\n"); NODE_DBG("\n");
#endif #endif
#ifdef COAP_DEBUG #ifdef COAP_DEBUG
coap_dumpPacket(&rsppkt); coap_dumpPacket(&rsppkt);
#endif #endif
} }
return rsplen; if(rsppkt.content.p){
c_free(rsppkt.content.p);
rsppkt.content.p = NULL;
rsppkt.content.len = 0;
}
return rlen;
} }
} }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
extern "C" { extern "C" {
#endif #endif
size_t coap_server_respond(char *data, unsigned short len, unsigned short size); size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned short rsplen);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
#include "c_stdio.h" #include "c_stdio.h"
#include "c_string.h" #include "c_string.h"
#include "c_stdlib.h"
#include "coap.h" #include "coap.h"
#include "lua.h" #include "lua.h"
...@@ -8,20 +9,24 @@ ...@@ -8,20 +9,24 @@
#include "os_type.h" #include "os_type.h"
static char rsp[MAX_PAYLOAD_SIZE] = ""; void build_well_known_rsp(char *rsp, uint16_t rsplen);
const uint16_t rsplen = MAX_PAYLOAD_SIZE;
void build_well_known_rsp(void);
void endpoint_setup(void) void endpoint_setup(void)
{ {
coap_setup(); coap_setup();
build_well_known_rsp();
} }
static const coap_endpoint_path_t path_well_known_core = {2, {".well-known", "core"}}; static const coap_endpoint_path_t path_well_known_core = {2, {".well-known", "core"}};
static int handle_get_well_known_core(const coap_endpoint_t *ep, coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo) static int handle_get_well_known_core(const coap_endpoint_t *ep, coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
{ {
return coap_make_response(scratch, outpkt, (const uint8_t *)rsp, c_strlen(rsp), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT); outpkt->content.p = (uint8_t *)c_zalloc(MAX_PAYLOAD_SIZE); // this should be free-ed when outpkt is built in coap_server_respond()
if(outpkt->content.p == NULL){
NODE_DBG("not enough memory\n");
return COAP_ERR_BUFFER_TOO_SMALL;
}
outpkt->content.len = MAX_PAYLOAD_SIZE;
build_well_known_rsp(outpkt->content.p, outpkt->content.len);
return coap_make_response(scratch, outpkt, (const uint8_t *)outpkt->content.p, c_strlen(outpkt->content.p), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT);
} }
static const coap_endpoint_path_t path_variable = {2, {"v1", "v"}}; static const coap_endpoint_path_t path_variable = {2, {"v1", "v"}};
...@@ -29,6 +34,7 @@ static int handle_get_variable(const coap_endpoint_t *ep, coap_rw_buffer_t *scra ...@@ -29,6 +34,7 @@ static int handle_get_variable(const coap_endpoint_t *ep, coap_rw_buffer_t *scra
{ {
const coap_option_t *opt; const coap_option_t *opt;
uint8_t count; uint8_t count;
int n;
if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count))) if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))
{ {
if ((count != ep->path->count ) && (count != ep->path->count + 1)) // +1 for /f/[function], /v/[variable] if ((count != ep->path->count ) && (count != ep->path->count + 1)) // +1 for /f/[function], /v/[variable]
...@@ -54,14 +60,15 @@ static int handle_get_variable(const coap_endpoint_t *ep, coap_rw_buffer_t *scra ...@@ -54,14 +60,15 @@ static int handle_get_variable(const coap_endpoint_t *ep, coap_rw_buffer_t *scra
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE); return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
if(c_strlen(h->name)) if(c_strlen(h->name))
{ {
n = lua_gettop(h->L);
lua_getglobal(h->L, h->name); lua_getglobal(h->L, h->name);
if (!lua_isnumber(h->L, -1)) { if (!lua_isnumber(h->L, -1)) {
NODE_DBG ("should be a number.\n"); NODE_DBG ("should be a number.\n");
lua_pop(h->L, 1); lua_settop(h->L, n);
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE); return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
} else { } else {
const char *res = lua_tostring(h->L,-1); const char *res = lua_tostring(h->L,-1);
lua_pop(h->L, 1); lua_settop(h->L, n);
return coap_make_response(scratch, outpkt, (const uint8_t *)res, c_strlen(res), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN); return coap_make_response(scratch, outpkt, (const uint8_t *)res, c_strlen(res), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
} }
} }
...@@ -84,6 +91,7 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr ...@@ -84,6 +91,7 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr
{ {
const coap_option_t *opt; const coap_option_t *opt;
uint8_t count; uint8_t count;
int n;
if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count))) if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))
{ {
if ((count != ep->path->count ) && (count != ep->path->count + 1)) // +1 for /f/[function], /v/[variable] if ((count != ep->path->count ) && (count != ep->path->count + 1)) // +1 for /f/[function], /v/[variable]
...@@ -111,10 +119,11 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr ...@@ -111,10 +119,11 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr
if(c_strlen(h->name)) if(c_strlen(h->name))
{ {
n = lua_gettop(h->L);
lua_getglobal(h->L, h->name); lua_getglobal(h->L, h->name);
if (lua_type(h->L, -1) != LUA_TFUNCTION) { if (lua_type(h->L, -1) != LUA_TFUNCTION) {
NODE_DBG ("should be a function\n"); NODE_DBG ("should be a function\n");
lua_pop(h->L, 1); lua_settop(h->L, n);
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE); return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
} else { } else {
lua_pushlstring(h->L, inpkt->payload.p, inpkt->payload.len); // make sure payload.p is filled with '\0' after payload.len, or use lua_pushlstring lua_pushlstring(h->L, inpkt->payload.p, inpkt->payload.len); // make sure payload.p is filled with '\0' after payload.len, or use lua_pushlstring
...@@ -125,14 +134,17 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr ...@@ -125,14 +134,17 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr
size_t len = 0; size_t len = 0;
const char *ret = luaL_checklstring( h->L, -1, &len ); const char *ret = luaL_checklstring( h->L, -1, &len );
if(len > MAX_PAYLOAD_SIZE){ if(len > MAX_PAYLOAD_SIZE){
lua_settop(h->L, n);
luaL_error( h->L, "return string:<MAX_PAYLOAD_SIZE" ); luaL_error( h->L, "return string:<MAX_PAYLOAD_SIZE" );
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE); return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
} }
NODE_DBG((char *)ret); NODE_DBG((char *)ret);
NODE_DBG("\n"); NODE_DBG("\n");
lua_settop(h->L, n);
return coap_make_response(scratch, outpkt, ret, len, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN); return coap_make_response(scratch, outpkt, ret, len, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
} }
} else { } else {
lua_settop(h->L, n);
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN); return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
} }
} }
...@@ -204,13 +216,13 @@ const coap_endpoint_t endpoints[] = ...@@ -204,13 +216,13 @@ const coap_endpoint_t endpoints[] =
{(coap_method_t)0, NULL, NULL, NULL, NULL} {(coap_method_t)0, NULL, NULL, NULL, NULL}
}; };
void build_well_known_rsp(void) void build_well_known_rsp(char *rsp, uint16_t rsplen)
{ {
const coap_endpoint_t *ep = endpoints; const coap_endpoint_t *ep = endpoints;
int i; int i;
uint16_t len = rsplen; uint16_t len = rsplen;
c_memset(rsp, 0, sizeof(rsp)); c_memset(rsp, 0, len);
len--; // Null-terminated string len--; // Null-terminated string
......
...@@ -24,6 +24,8 @@ coap_pdu_t * coap_new_pdu(void) { ...@@ -24,6 +24,8 @@ coap_pdu_t * coap_new_pdu(void) {
c_free(pdu); c_free(pdu);
return NULL; return NULL;
} }
pdu->pkt->content.p = NULL;
pdu->pkt->content.len = 0;
pdu->msg.p = (uint8_t *)c_zalloc(MAX_REQUEST_SIZE+1); // +1 for string '\0' pdu->msg.p = (uint8_t *)c_zalloc(MAX_REQUEST_SIZE+1); // +1 for string '\0'
if(!pdu->msg.p){ if(!pdu->msg.p){
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// #define FLASH_8M // #define FLASH_8M
// #define FLASH_16M // #define FLASH_16M
#define FLASH_AUTOSIZE #define FLASH_AUTOSIZE
#define FLASH_SAFE_API
// #define DEVELOP_VERSION // #define DEVELOP_VERSION
#define FULL_VERSION_FOR_USER #define FULL_VERSION_FOR_USER
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#define LUA_USE_MODULES_OW #define LUA_USE_MODULES_OW
#define LUA_USE_MODULES_BIT #define LUA_USE_MODULES_BIT
#define LUA_USE_MODULES_MQTT #define LUA_USE_MODULES_MQTT
// #define LUA_USE_MODULES_COAP // need about 4k more ram for now #define LUA_USE_MODULES_COAP
#define LUA_USE_MODULES_U8G #define LUA_USE_MODULES_U8G
#define LUA_USE_MODULES_WS2812 #define LUA_USE_MODULES_WS2812
#endif /* LUA_USE_MODULES */ #endif /* LUA_USE_MODULES */
......
...@@ -7,6 +7,6 @@ ...@@ -7,6 +7,6 @@
#define NODE_VERSION_INTERNAL 0U #define NODE_VERSION_INTERNAL 0U
#define NODE_VERSION "NodeMCU 0.9.5" #define NODE_VERSION "NodeMCU 0.9.5"
#define BUILD_DATE "build 20150306" #define BUILD_DATE "build 20150315"
#endif /* __USER_VERSION_H__ */ #endif /* __USER_VERSION_H__ */
...@@ -63,7 +63,7 @@ int c_stderr = 1001; ...@@ -63,7 +63,7 @@ int c_stderr = 1001;
#define ENDIAN_LITTLE 1234 #define ENDIAN_LITTLE 1234
#define ENDIAN_BIG 4321 #define ENDIAN_BIG 4321
#define ENDIAN_PDP 3412 #define ENDIAN_PDP 3412
#define ENDIAN ENDIAN_BIG #define ENDIAN ENDIAN_LITTLE
/* $Id: strichr.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */ /* $Id: strichr.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
......
...@@ -659,13 +659,19 @@ typedef struct LoadFSF { ...@@ -659,13 +659,19 @@ typedef struct LoadFSF {
static const char *getFSF (lua_State *L, void *ud, size_t *size) { static const char *getFSF (lua_State *L, void *ud, size_t *size) {
LoadFSF *lf = (LoadFSF *)ud; LoadFSF *lf = (LoadFSF *)ud;
(void)L; (void)L;
if (L == NULL && size == NULL) // Direct mode check
return NULL;
if (lf->extraline) { if (lf->extraline) {
lf->extraline = 0; lf->extraline = 0;
*size = 1; *size = 1;
return "\n"; return "\n";
} }
if (fs_eof(lf->f)) return NULL; if (fs_eof(lf->f)) return NULL;
*size = fs_read(lf->f, lf->buff, sizeof(lf->buff)); *size = fs_read(lf->f, lf->buff, sizeof(lf->buff));
return (*size > 0) ? lf->buff : NULL; return (*size > 0) ? lf->buff : NULL;
} }
......
...@@ -37,20 +37,20 @@ static void coap_received(void *arg, char *pdata, unsigned short len) ...@@ -37,20 +37,20 @@ static void coap_received(void *arg, char *pdata, unsigned short len)
struct espconn *pesp_conn = arg; struct espconn *pesp_conn = arg;
lcoap_userdata *cud = (lcoap_userdata *)pesp_conn->reverse; lcoap_userdata *cud = (lcoap_userdata *)pesp_conn->reverse;
static uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\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 c_memset(buf, 0, sizeof(buf)); // wipe prev data
if (len > MAX_MESSAGE_SIZE) { if (len > MAX_MESSAGE_SIZE) {
NODE_DBG("Request Entity Too Large.\n"); // NOTE: should response 4.13 to client... NODE_DBG("Request Entity Too Large.\n"); // NOTE: should response 4.13 to client...
return; return;
} else {
c_memcpy(buf, pdata, len);
} }
// c_memcpy(buf, pdata, len);
size_t rsplen = coap_server_respond(buf, len, MAX_MESSAGE_SIZE+1); size_t rsplen = coap_server_respond(pdata, len, buf, MAX_MESSAGE_SIZE+1);
espconn_sent(pesp_conn, (unsigned char *)buf, rsplen); espconn_sent(pesp_conn, (unsigned char *)buf, rsplen);
c_memset(buf, 0, sizeof(buf)); // c_memset(buf, 0, sizeof(buf));
} }
static void coap_sent(void *arg) static void coap_sent(void *arg)
...@@ -227,26 +227,19 @@ static void coap_response_handler(void *arg, char *pdata, unsigned short len) ...@@ -227,26 +227,19 @@ static void coap_response_handler(void *arg, char *pdata, unsigned short len)
struct espconn *pesp_conn = arg; struct espconn *pesp_conn = arg;
coap_packet_t pkt; coap_packet_t pkt;
static uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0' 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 c_memset(buf, 0, sizeof(buf)); // wipe prev data
static int n = 0;
int rc; int rc;
if ((len == 1460) && (1460 <= MAX_MESSAGE_SIZE)){ if( len > MAX_MESSAGE_SIZE )
c_memcpy(buf, pdata, len); // max length is 1460, another part of data is coming in next callback {
n = len; NODE_DBG("Request Entity Too Large.\n"); // NOTE: should response 4.13 to client...
return; return;
} else {
if( len > MAX_MESSAGE_SIZE )
{
NODE_DBG("Request Entity Too Large.\n"); // NOTE: should response 4.13 to client...
c_memset(buf, 0, sizeof(buf)); // wipe prev data
n = 0;
return;
}
c_memcpy(buf + n, pdata, len);
len += n; // more than 1460
} }
c_memcpy(buf, pdata, len);
if (0 != (rc = coap_parse(&pkt, buf, len))){ if (0 != (rc = coap_parse(&pkt, buf, len))){
NODE_DBG("Bad packet rc=%d\n", rc); NODE_DBG("Bad packet rc=%d\n", rc);
...@@ -306,8 +299,7 @@ end: ...@@ -306,8 +299,7 @@ end:
if(pesp_conn->proto.udp->remote_port || pesp_conn->proto.udp->local_port) if(pesp_conn->proto.udp->remote_port || pesp_conn->proto.udp->local_port)
espconn_delete(pesp_conn); espconn_delete(pesp_conn);
} }
c_memset(buf, 0, sizeof(buf)); // c_memset(buf, 0, sizeof(buf));
n = 0;
} }
// Lua: client:request( [CON], uri, [payload] ) // Lua: client:request( [CON], uri, [payload] )
...@@ -431,7 +423,6 @@ static int coap_request( lua_State* L, coap_method_t m ) ...@@ -431,7 +423,6 @@ static int coap_request( lua_State* L, coap_method_t m )
extern coap_luser_entry *variable_entry; extern coap_luser_entry *variable_entry;
extern coap_luser_entry *function_entry; extern coap_luser_entry *function_entry;
extern void build_well_known_rsp(void);
// Lua: coap:var/func( string ) // Lua: coap:var/func( string )
static int coap_regist( lua_State* L, const char* mt, int isvar ) static int coap_regist( lua_State* L, const char* mt, int isvar )
{ {
...@@ -466,8 +457,6 @@ static int coap_regist( lua_State* L, const char* mt, int isvar ) ...@@ -466,8 +457,6 @@ static int coap_regist( lua_State* L, const char* mt, int isvar )
h->L = L; h->L = L;
h->name = name; h->name = name;
build_well_known_rsp(); // rebuild .well-known
NODE_DBG("coap_regist is called.\n"); NODE_DBG("coap_regist is called.\n");
return 0; return 0;
} }
......
...@@ -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
......
...@@ -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 );
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
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 )
...@@ -56,7 +56,7 @@ static int node_deepsleep( lua_State* L ) ...@@ -56,7 +56,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
...@@ -80,10 +80,14 @@ static int node_info( lua_State* L ) ...@@ -80,10 +80,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()
...@@ -91,7 +95,7 @@ static int node_chipid( lua_State* L ) ...@@ -91,7 +95,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 )
...@@ -106,24 +110,23 @@ static int node_flashid( lua_State* L ) ...@@ -106,24 +110,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()
...@@ -131,7 +134,7 @@ static int node_heap( lua_State* L ) ...@@ -131,7 +134,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;
...@@ -146,7 +149,7 @@ static int node_led( lua_State* L ) ...@@ -146,7 +149,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 {
...@@ -155,7 +158,7 @@ static int node_led( lua_State* L ) ...@@ -155,7 +158,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 {
...@@ -163,14 +166,14 @@ static int node_led( lua_State* L ) ...@@ -163,14 +166,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;
...@@ -180,32 +183,32 @@ void default_long_press(void *arg){ ...@@ -180,32 +183,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)
...@@ -213,32 +216,32 @@ static int node_key( lua_State* L ) ...@@ -213,32 +216,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
...@@ -248,15 +251,15 @@ extern void dojob(lua_Load *load); ...@@ -248,15 +251,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
...@@ -271,18 +274,18 @@ static int node_input( lua_State* L ) ...@@ -271,18 +274,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);
} }
...@@ -296,15 +299,15 @@ static int node_output( lua_State* L ) ...@@ -296,15 +299,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;
} }
...@@ -312,26 +315,26 @@ static int node_output( lua_State* L ) ...@@ -312,26 +315,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;
} }
...@@ -343,45 +346,45 @@ static int node_compile( lua_State* L ) ...@@ -343,45 +346,45 @@ 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");
} }
...@@ -391,7 +394,7 @@ static int node_compile( lua_State* L ) ...@@ -391,7 +394,7 @@ static int node_compile( lua_State* L )
// 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 ) },
...@@ -408,7 +411,7 @@ const LUA_REG_TYPE node_map[] = ...@@ -408,7 +411,7 @@ 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) // 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
......
...@@ -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;
} }
......
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