Commit 18886ea6 authored by zeroday's avatar zeroday
Browse files

Merge pull request #203 from nodemcu/dev

Fixed floating point bug.
add file.rename
parents 370bc88b 22d096ce
...@@ -125,6 +125,7 @@ pre_build/latest/nodemcu_512k_latest.bin is removed. use pre_build/latest/nodemc ...@@ -125,6 +125,7 @@ pre_build/latest/nodemcu_512k_latest.bin is removed. use pre_build/latest/nodemc
#define LUA_USE_MODULES_UART #define LUA_USE_MODULES_UART
#define LUA_USE_MODULES_OW #define LUA_USE_MODULES_OW
#define LUA_USE_MODULES_BIT #define LUA_USE_MODULES_BIT
#define LUA_USE_MODULES_WS2812
#endif /* LUA_USE_MODULES */ #endif /* LUA_USE_MODULES */
... ...
// LUA_NUMBER_INTEGRAL // LUA_NUMBER_INTEGRAL
...@@ -330,3 +331,13 @@ cu:send("hello") ...@@ -330,3 +331,13 @@ cu:send("hello")
ds18b20 = nil ds18b20 = nil
package.loaded["ds18b20"]=nil package.loaded["ds18b20"]=nil
``` ```
####Control a WS2812 based light strip
```lua
-- set the color of one LED on GPIO 2 to red
ws2812.write(4, string.char(0, 255, 0))
-- set the color of 10 LEDs on GPIO 0 to blue
ws2812.write(3, string.char(0, 0, 255):rep(10))
-- first LED green, second LED white
ws2812.write(4, string.char(255, 0, 0, 255, 255, 255))
```
...@@ -33,18 +33,23 @@ typedef enum { ...@@ -33,18 +33,23 @@ typedef enum {
} UartExistParity; } UartExistParity;
typedef enum { typedef enum {
BIT_RATE_1200 = 1200, BIT_RATE_300 = 300,
BIT_RATE_2400 = 2400, BIT_RATE_600 = 600,
BIT_RATE_4800 = 4800, BIT_RATE_1200 = 1200,
BIT_RATE_9600 = 9600, BIT_RATE_2400 = 2400,
BIT_RATE_4800 = 4800,
BIT_RATE_9600 = 9600,
BIT_RATE_19200 = 19200, BIT_RATE_19200 = 19200,
BIT_RATE_38400 = 38400, BIT_RATE_38400 = 38400,
BIT_RATE_57600 = 57600, BIT_RATE_57600 = 57600,
BIT_RATE_74880 = 74880, BIT_RATE_74880 = 74880,
BIT_RATE_115200 = 115200, BIT_RATE_115200 = 115200,
BIT_RATE_230400 = 230400, BIT_RATE_230400 = 230400,
BIT_RATE_460800 = 460800, BIT_RATE_256000 = 256000,
BIT_RATE_921600 = 921600 BIT_RATE_460800 = 460800,
BIT_RATE_921600 = 921600,
BIT_RATE_1843200 = 1843200,
BIT_RATE_3686400 = 3686400,
} UartBautRate; } UartBautRate;
typedef enum { typedef enum {
......
...@@ -394,5 +394,21 @@ extern sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip); ...@@ -394,5 +394,21 @@ extern sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
*******************************************************************************/ *******************************************************************************/
extern sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip); extern sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
/******************************************************************************
* FunctionName : espconn_recv_hold
* Description : hold tcp receive
* Parameters : espconn -- espconn to hold
* Returns : none
*******************************************************************************/
extern sint8 espconn_recv_hold(struct espconn *pespconn);
/******************************************************************************
* FunctionName : espconn_recv_unhold
* Description : unhold tcp receive
* Parameters : espconn -- espconn to unhold
* Returns : none
*******************************************************************************/
extern sint8 espconn_recv_unhold(struct espconn *pespconn);
#endif #endif
...@@ -277,6 +277,8 @@ struct tcp_pcb { ...@@ -277,6 +277,8 @@ struct tcp_pcb {
/* KEEPALIVE counter */ /* KEEPALIVE counter */
u8_t keep_cnt_sent; u8_t keep_cnt_sent;
u8_t hold;
}; };
struct tcp_pcb_listen { struct tcp_pcb_listen {
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
// #define FLASH_1M // #define FLASH_1M
// #define FLASH_2M // #define FLASH_2M
// #define FLASH_4M // #define FLASH_4M
// #define FLASH_8M
// #define FLASH_16M
#define FLASH_AUTOSIZE #define FLASH_AUTOSIZE
// #define DEVELOP_VERSION // #define DEVELOP_VERSION
#define FULL_VERSION_FOR_USER #define FULL_VERSION_FOR_USER
...@@ -40,7 +42,6 @@ ...@@ -40,7 +42,6 @@
#define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed)) #define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed))
#define ICACHE_STORE_ATTR __attribute__((aligned(4))) #define ICACHE_STORE_ATTR __attribute__((aligned(4)))
#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text"))) #define ICACHE_RAM_ATTR __attribute__((section(".iram0.text")))
// #define ICACHE_RODATA_ATTR __attribute__((section(".rodata2.text")))
#define CLIENT_SSL_ENABLE #define CLIENT_SSL_ENABLE
#define GPIO_INTERRUPT_ENABLE #define GPIO_INTERRUPT_ENABLE
...@@ -64,12 +65,10 @@ ...@@ -64,12 +65,10 @@
#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_WS2812
#endif /* LUA_USE_MODULES */ #endif /* LUA_USE_MODULES */
// #define LUA_NUMBER_INTEGRAL // #define LUA_NUMBER_INTEGRAL
#ifndef LUA_NUMBER_INTEGRAL
#define PRINTF_LONG_SUPPORT
#endif
#define LUA_OPTRAM #define LUA_OPTRAM
#ifdef LUA_OPTRAM #ifdef LUA_OPTRAM
......
#include "c_math.h" #include "c_math.h"
#include "c_types.h" #include "c_types.h"
#include "user_config.h"
double floor(double x) double floor(double x)
{ {
return (double) (x < 0.f ? (((int) x) - 1) : ((int) x)); return (double) (x < 0.f ? (((int) x) - 1) : ((int) x));
} }
double pow(double x, double y)
{
#define MAXEXP 2031 /* (MAX_EXP * 16) - 1 */ #define MAXEXP 2031 /* (MAX_EXP * 16) - 1 */
#define MINEXP -2047 /* (MIN_EXP * 16) - 1 */ #define MINEXP -2047 /* (MIN_EXP * 16) - 1 */
#define HUGE MAXFLOAT #define HUGE MAXFLOAT
double a1[] =
{
1.0,
0.95760328069857365,
0.91700404320467123,
0.87812608018664974,
0.84089641525371454,
0.80524516597462716,
0.77110541270397041,
0.73841307296974966,
0.70710678118654752,
0.67712777346844637,
0.64841977732550483,
0.62092890603674203,
0.59460355750136054,
0.56939431737834583,
0.54525386633262883,
0.52213689121370692,
0.50000000000000000
};
double a2[] =
{
0.24114209503420288E-17,
0.92291566937243079E-18,
-0.15241915231122319E-17,
-0.35421849765286817E-17,
-0.31286215245415074E-17,
-0.44654376565694490E-17,
0.29306999570789681E-17,
0.11260851040933474E-17
};
double p1 = 0.833333333333332114e-1;
double p2 = 0.125000000005037992e-1;
double p3 = 0.223214212859242590e-2;
double p4 = 0.434457756721631196e-3;
double q1 = 0.693147180559945296e0;
double q2 = 0.240226506959095371e0;
double q3 = 0.555041086640855953e-1;
double q4 = 0.961812905951724170e-2;
double q5 = 0.133335413135857847e-2;
double q6 = 0.154002904409897646e-3;
double q7 = 0.149288526805956082e-4;
double k = 0.442695040888963407;
double a1[] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =
{
1.0,
0.95760328069857365,
0.91700404320467123,
0.87812608018664974,
0.84089641525371454,
0.80524516597462716,
0.77110541270397041,
0.73841307296974966,
0.70710678118654752,
0.67712777346844637,
0.64841977732550483,
0.62092890603674203,
0.59460355750136054,
0.56939431737834583,
0.54525386633262883,
0.52213689121370692,
0.50000000000000000
};
double a2[] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =
{
0.24114209503420288E-17,
0.92291566937243079E-18,
-0.15241915231122319E-17,
-0.35421849765286817E-17,
-0.31286215245415074E-17,
-0.44654376565694490E-17,
0.29306999570789681E-17,
0.11260851040933474E-17
};
double p1 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.833333333333332114e-1;
double p2 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.125000000005037992e-1;
double p3 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.223214212859242590e-2;
double p4 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.434457756721631196e-3;
double q1 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.693147180559945296e0;
double q2 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.240226506959095371e0;
double q3 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.555041086640855953e-1;
double q4 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.961812905951724170e-2;
double q5 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.133335413135857847e-2;
double q6 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.154002904409897646e-3;
double q7 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.149288526805956082e-4;
double k ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.442695040888963407;
double pow(double x, double y)
{
double frexp(), g, ldexp(), r, u1, u2, v, w, w1, w2, y1, y2, z; double frexp(), g, ldexp(), r, u1, u2, v, w, w1, w2, y1, y2, z;
int iw1, m, p; int iw1, m, p;
......
...@@ -58,423 +58,1047 @@ int c_stderr = 1001; ...@@ -58,423 +58,1047 @@ int c_stderr = 1001;
#else #else
/* #define FLOATINGPT 1
File: printf.c #define NEWFP 1
#define ENDIAN_LITTLE 1234
#define ENDIAN_BIG 4321
#define ENDIAN_PDP 3412
#define ENDIAN ENDIAN_BIG
Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs /* $Id: strichr.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
All rights reserved. /*
* Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//#include <string.h>
#include "c_string.h"
Redistribution and use in source and binary forms, with or without modification, char *
are permitted provided that the following conditions are met: strichr(char *p, int c)
{
char *t;
Redistributions of source code must retain the above copyright notice, this list if (p != NULL) {
of conditions and the following disclaimer. for(t = p; *t; t++);
for (; t >= p; t--) {
*(t + 1) = *t;
}
*p = c;
}
return (p);
}
Redistributions in binary form must reproduce the above copyright notice, this /* $Id: str_fmt.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its /*
contributors may be used to endorse or promote products derived from this software * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
without specific prior written permission. *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//#include <string.h>
#include "c_string.h"
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" #define FMT_RJUST 0
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #define FMT_LJUST 1
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. #define FMT_RJUST0 2
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, #define FMT_CENTER 3
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
---------------------------------------------------------------------- /*
* Format string by inserting blanks.
*/
This library is realy just two files: 'printf.h' and 'printf.c'. void
str_fmt(char *p, int size, int fmt)
{
int n, m, len;
They provide a simple and small (+200 loc) printf functionality to len = strlen (p);
be used in embedded systems. switch (fmt) {
case FMT_RJUST:
for (n = size - len; n > 0; n--)
strichr (p, ' ');
break;
case FMT_LJUST:
for (m = size - len; m > 0; m--)
strcat (p, " ");
break;
case FMT_RJUST0:
for (n = size - len; n > 0; n--)
strichr (p, '0');
break;
case FMT_CENTER:
m = (size - len) / 2;
n = size - (len + m);
for (; m > 0; m--)
strcat (p, " ");
for (; n > 0; n--)
strichr (p, ' ');
break;
}
}
I've found them so usefull in debugging that I do not bother with a /* $Id: strtoupp.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
debugger at all.
They are distributed in source form, so to use them, just compile them /*
into your project. * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//#include <string.h>
//#include <ctype.h>
#include "c_string.h"
#include "c_ctype.h"
Two printf variants are provided: printf and sprintf. void
strtoupper(char *p)
{
if(!p)
return;
for (; *p; p++)
*p = toupper (*p);
}
The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. /* $Id: atob.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
Zero padding and field width are also supported. /*
* Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the //#include <sys/types.h>
long specifier is also //#include <string.h>
supported. Note that this will pull in some long math routines (pun intended!) //#include <pmon.h>
and thus make your executable noticably longer. #include "c_string.h"
typedef int int32_t;
typedef unsigned int u_int32_t;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef int32_t register_t;
typedef long long quad_t;
typedef unsigned long long u_quad_t;
typedef double rtype;
The memory foot print of course depends on the target cpu, compiler and #define __P(x) x
compiler options, but a rough guestimate (based on a H8S target) is about
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
Not too bad. Your milage may vary. By hacking the source code you can
get rid of some hunred bytes, I'm sure, but personally I feel the balance of
functionality and flexibility versus code size is close to optimal for
many embedded systems.
To use the printf you need to supply your own character output function, static char * _getbase __P((char *, int *));
something like : static int _atob __P((unsigned long long *, char *p, int));
void putc ( void* p, char c) static char *
{ _getbase(char *p, int *basep)
while (!SERIAL_PORT_EMPTY) ; {
SERIAL_PORT_TX_REGISTER = c; if (p[0] == '0') {
switch (p[1]) {
case 'x':
*basep = 16;
break;
case 't': case 'n':
*basep = 10;
break;
case 'o':
*basep = 8;
break;
default:
*basep = 10;
return (p);
}
return (p + 2);
} }
*basep = 10;
return (p);
}
Before you can call printf you need to initialize it to use your
character output function with something like:
init_printf(NULL,putc);
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', /*
the NULL (or any pointer) you pass into the 'init_printf' will eventually be * _atob(vp,p,base)
passed to your 'putc' routine. This allows you to pass some storage space (or */
anything realy) to the character output function, if necessary. static int
This is not often needed but it was implemented like that because it made _atob (u_quad_t *vp, char *p, int base)
implementing the sprintf function so neat (look at the source code). {
u_quad_t value, v1, v2;
char *q, tmp[20];
int digit;
The code is re-entrant, except for the 'init_printf' function, so it if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
is safe to call it from interupts too, although this may result in mixed output. base = 16;
If you rely on re-entrancy, take care that your 'putc' function is re-entrant! p += 2;
}
The printf and sprintf functions are actually macros that translate to if (base == 16 && (q = strchr (p, '.')) != 0) {
'tfp_printf' and 'tfp_sprintf'. This makes it possible if (q - p > sizeof(tmp) - 1)
to use them along with 'stdio.h' printf's in a single source file. return (0);
You just need to undef the names before you include the 'stdio.h'.
Note that these are not function like macros, so if you have variables
or struct members with these names, things will explode in your face.
Without variadic macros this is the best we can do to wrap these
fucnction. If it is a problem just give up the macros and use the
functions directly or rename them.
For further details see source code. strncpy (tmp, p, q - p);
tmp[q - p] = '\0';
if (!_atob (&v1, tmp, 16))
return (0);
regs Kusti, 23.10.2004 q++;
*/ if (strchr (q, '.'))
return (0);
/* if (!_atob (&v2, q, 16))
Add lightweight %g support by vowstar, <vowstar@gmail.com> return (0);
NodeMCU Team, 26.1.2015 *vp = (v1 << 16) + v2;
*/ return (1);
}
typedef void (*putcf) (void *, char); value = *vp = 0;
for (; *p; p++) {
if (*p >= '0' && *p <= '9')
digit = *p - '0';
else if (*p >= 'a' && *p <= 'f')
digit = *p - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
digit = *p - 'A' + 10;
else
return (0);
#ifdef PRINTF_LONG_SUPPORT if (digit >= base)
return (0);
value *= base;
value += digit;
}
*vp = value;
return (1);
}
static int uli2a(unsigned long int num, unsigned int base, int uc, char *bf) /*
* atob(vp,p,base)
* converts p to binary result in vp, rtn 1 on success
*/
int
atob(u_int32_t *vp, char *p, int base)
{ {
int n = 0; u_quad_t v;
unsigned long int d = 1;
int len = 1; if (base == 0)
while (num / d >= base) p = _getbase (p, &base);
{ if (_atob (&v, p, base)) {
d *= base; *vp = v;
len ++; return (1);
}
while (d != 0)
{
int dgt = num / d;
num %= d;
d /= base;
if (n || dgt > 0 || d == 0)
{
*bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
++n;
}
} }
*bf = 0; return (0);
return len;
} }
static int li2a (long num, char *bf)
/*
* llatob(vp,p,base)
* converts p to binary result in vp, rtn 1 on success
*/
int
llatob(u_quad_t *vp, char *p, int base)
{ {
int len = 0; if (base == 0)
if (num < 0) p = _getbase (p, &base);
{ return _atob(vp, p, base);
num = -num;
*bf++ = '-';
len ++;
}
len += uli2a(num, 10, 0, bf);
return len;
} }
#endif
static int ui2a(unsigned int num, unsigned int base, int uc, char *bf) /*
* char *btoa(dst,value,base)
* converts value to ascii, result in dst
*/
char *
btoa(char *dst, u_int value, int base)
{ {
int n = 0; char buf[34], digit;
unsigned int d = 1; int i, j, rem, neg;
int len = 1;
while (num / d >= base) if (value == 0) {
{ dst[0] = '0';
d *= base; dst[1] = 0;
len ++; return (dst);
} }
while (d != 0)
{ neg = 0;
int dgt = num / d; if (base == -10) {
num %= d; base = 10;
d /= base; if (value & (1L << 31)) {
if (n || dgt > 0 || d == 0) value = (~value) + 1;
{ neg = 1;
*bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
++n;
} }
} }
*bf = 0;
return len; for (i = 0; value != 0; i++) {
rem = value % base;
value /= base;
if (rem >= 0 && rem <= 9)
digit = rem + '0';
else if (rem >= 10 && rem <= 36)
digit = (rem - 10) + 'a';
buf[i] = digit;
}
buf[i] = 0;
if (neg)
strcat (buf, "-");
/* reverse the string */
for (i = 0, j = strlen (buf) - 1; j >= 0; i++, j--)
dst[i] = buf[j];
dst[i] = 0;
return (dst);
} }
static int i2a (int num, char *bf) /*
* char *btoa(dst,value,base)
* converts value to ascii, result in dst
*/
char *
llbtoa(char *dst, u_quad_t value, int base)
{ {
int len = 0; char buf[66], digit;
if (num < 0) int i, j, rem, neg;
{
num = -num; if (value == 0) {
*bf++ = '-'; dst[0] = '0';
len ++; dst[1] = 0;
return (dst);
}
neg = 0;
if (base == -10) {
base = 10;
if (value & (1LL << 63)) {
value = (~value) + 1;
neg = 1;
}
} }
len += ui2a(num, 10, 0, bf);
return len; for (i = 0; value != 0; i++) {
rem = value % base;
value /= base;
if (rem >= 0 && rem <= 9)
digit = rem + '0';
else if (rem >= 10 && rem <= 36)
digit = (rem - 10) + 'a';
buf[i] = digit;
}
buf[i] = 0;
if (neg)
strcat (buf, "-");
/* reverse the string */
for (i = 0, j = strlen (buf) - 1; j >= 0; i++, j--)
dst[i] = buf[j];
dst[i] = 0;
return (dst);
} }
// Converts a floating point number to string. /*
static int d2a(double num, char *bf) * gethex(vp,p,n)
* convert n hex digits from p to binary, result in vp,
* rtn 1 on success
*/
int
gethex(int32_t *vp, char *p, int n)
{ {
int len = 0; u_long v;
double ipart = 0; int digit;
double fpart = 0;
double absnum = num; for (v = 0; n > 0; n--) {
if (*p == 0)
// Add sign return (0);
if (absnum < 0) if (*p >= '0' && *p <= '9')
{ digit = *p - '0';
absnum = -absnum; else if (*p >= 'a' && *p <= 'f')
*bf++ = '-'; digit = *p - 'a' + 10;
// len must add 1 when return else if (*p >= 'A' && *p <= 'F')
// but can't add at here digit = *p - 'A' + 10;
else
return (0);
v <<= 4;
v |= digit;
p++;
} }
*vp = v;
return (1);
}
// Extract integer part /* $Id: vsprintf.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
ipart = (int)absnum;
// Extract floating part /*
fpart = absnum - (double)ipart; * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//#include <stdio.h>
//#include <stdarg.h>
//#include <string.h>
//#include <ctype.h>
//#include <pmon.h>
#include "c_stdarg.h"
#include "c_string.h"
#include "c_ctype.h"
// convert integer part to string /*
#ifdef PRINTF_LONG_SUPPORT * int vsprintf(d,s,ap)
len += li2a(ipart, bf); */
#else int
len += i2a(ipart, bf); vsprintf (char *d, const char *s, va_list ap)
{
const char *t;
char *p, *dst, tmp[40];
unsigned int n;
int fmt, trunc, haddot, width, base, longlong;
#ifdef FLOATINGPT
double dbl;
#ifndef NEWFP
EP ex;
#endif
#endif #endif
#ifndef EPSILON dst = d;
#define EPSILON ((double)(0.00000001)) for (; *s;) {
if (*s == '%') {
s++;
fmt = FMT_RJUST;
width = trunc = haddot = longlong = 0;
for (; *s; s++) {
if (strchr("bcdefgilopPrRsuxX%", *s))
break;
else if (*s == '-')
fmt = FMT_LJUST;
else if (*s == '0')
fmt = FMT_RJUST0;
else if (*s == '~')
fmt = FMT_CENTER;
else if (*s == '*') {
if (haddot)
trunc = va_arg(ap, int);
else
width = va_arg(ap, int);
} else if (*s >= '1' && *s <= '9') {
for (t = s; isdigit(*s); s++);
strncpy(tmp, t, s - t);
tmp[s - t] = '\0';
atob(&n, tmp, 10);
if (haddot)
trunc = n;
else
width = n;
s--;
} else if (*s == '.')
haddot = 1;
}
if (*s == '%') {
*d++ = '%';
*d = 0;
} else if (*s == 's') {
p = va_arg(ap, char *);
if (p)
strcpy(d, p);
else
strcpy(d, "(null)");
} else if (*s == 'c') {
n = va_arg (ap, int);
*d = n;
d[1] = 0;
} else {
if (*s == 'l') {
if (*++s == 'l') {
longlong = 1;
++s;
}
}
if (strchr("bdiopPrRxXu", *s)) {
if (*s == 'd' || *s == 'i')
base = -10;
else if (*s == 'u')
base = 10;
else if (*s == 'x' || *s == 'X')
base = 16;
else if(*s == 'p' || *s == 'P') {
base = 16;
if (*s == 'p') {
*d++ = '0';
*d++ = 'x';
}
fmt = FMT_RJUST0;
if (sizeof(long) > 4) {
width = 16;
longlong = 1;
} else {
width = 8;
}
}
else if(*s == 'r' || *s == 'R') {
base = 16;
if (*s == 'r') {
*d++ = '0';
*d++ = 'x';
}
fmt = FMT_RJUST0;
if (sizeof(register_t) > 4) {
width = 16;
longlong = 1;
} else {
width = 8;
}
}
else if (*s == 'o')
base = 8;
else if (*s == 'b')
base = 2;
if (longlong)
llbtoa(d, va_arg (ap, quad_t),
base);
else
btoa(d, va_arg (ap, int), base);
if (*s == 'X')
strtoupper(d);
}
#ifdef FLOATINGPT
else if (strchr ("eEfgG", *s)) {
//static void dtoa (char *, double, int, int, int);
void dtoa (char *dbuf, rtype arg, int fmtch, int width, int prec);
dbl = va_arg(ap, double);
dtoa(d, dbl, *s, width, trunc);
trunc = 0;
}
#endif #endif
if (fpart < EPSILON) }
{ if (trunc)
// fpart is zero d[trunc] = 0;
if (width)
str_fmt (d, width, fmt);
for (; *d; d++);
s++;
} else
*d++ = *s++;
} }
else *d = 0;
{ return (d - dst);
bf += len; }
// add dot
*bf ++ = '.'; #ifdef FLOATINGPT
len += 1; /*
// add zero after dot * Floating point output, cvt() onward lifted from BSD sources:
while (fpart < 0.1) *
{ * Copyright (c) 1990 The Regents of the University of California.
fpart *= 10; * All rights reserved.
*bf ++ = '0'; *
len += 1; * This code is derived from software contributed to Berkeley by
} * Chris Torek.
while ((fpart < (double)1.0 / EPSILON) && ((fpart - (int)fpart) > EPSILON)) *
{ * Redistribution and use in source and binary forms, with or without
fpart = fpart * 10; * modification, are permitted provided that the following conditions
} * are met:
#ifdef PRINTF_LONG_SUPPORT * 1. Redistributions of source code must retain the above copyright
len += li2a((int)fpart, bf); * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define MAX_FCONVERSION 512 /* largest possible real conversion */
#define MAX_EXPT 5 /* largest possible exponent field */
#define MAX_FRACT 39 /* largest possible fraction field */
#define TESTFLAG(x) 0
typedef double rtype;
extern double modf(double, double *);
#define to_char(n) ((n) + '0')
#define to_digit(c) ((c) - '0')
#define _isNan(arg) ((arg) != (arg))
static int cvt (rtype arg, int prec, char *signp, int fmtch,
char *startp, char *endp);
static char *c_round (double fract, int *exp, char *start, char *end,
char ch, char *signp);
static char *exponent(char *p, int exp, int fmtch);
/*
* _finite arg not Infinity or Nan
*/
static int _finite(rtype d)
{
#if ENDIAN == ENDIAN_LITTLE
struct IEEEdp {
unsigned manl:32;
unsigned manh:20;
unsigned exp:11;
unsigned sign:1;
} *ip;
#else #else
len += i2a((int)fpart, bf); struct IEEEdp {
unsigned sign:1;
unsigned exp:11;
unsigned manh:20;
unsigned manl:32;
} *ip;
#endif #endif
}
#undef EPSILON
if (num < 0)
{
len ++;
}
return len;
}
static int a2d(char ch) ip = (struct IEEEdp *)&d;
{ return (ip->exp != 0x7ff);
if (ch >= '0' && ch <= '9')
return ch - '0';
else if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
else if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
else return -1;
} }
static char a2i(char ch, char **src, int base, int *nump)
void dtoa (char *dbuf, rtype arg, int fmtch, int width, int prec)
{ {
char *p = *src; char buf[MAX_FCONVERSION+1], *cp;
int num = 0; char sign;
int digit; int size;
while ((digit = a2d(ch)) >= 0)
{ if( !_finite(arg) ) {
if (digit > base) break; if( _isNan(arg) )
num = num * base + digit; strcpy (dbuf, "NaN");
ch = *p++; else if( arg < 0)
strcpy (dbuf, "-Infinity");
else
strcpy (dbuf, "Infinity");
return;
} }
*src = p;
*nump = num;
return ch;
}
static void putchw(void *putp, putcf putf, int n, char z, char *bf) if (prec == 0)
{ prec = 6;
char fc = z ? '0' : ' '; else if (prec > MAX_FRACT)
char ch; prec = MAX_FRACT;
char *p = bf;
while (*p++ && n > 0) /* leave room for sign at start of buffer */
n--; cp = buf + 1;
while (n-- > 0)
putf(putp, fc); /*
while ((ch = *bf++)) * cvt may have to round up before the "start" of
putf(putp, ch); * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
* if the first character is still NUL, it did.
* softsign avoids negative 0 if _double < 0 but
* no significant digits will be shown.
*/
*cp = '\0';
size = cvt (arg, prec, &sign, fmtch, cp, buf + sizeof(buf));
if (*cp == '\0')
cp++;
if (sign)
*--cp = sign, size++;
cp[size] = 0;
memcpy (dbuf, cp, size + 1);
} }
void c_format(void *putp, putcf putf, char *fmt, va_list va)
static int
cvt(rtype number, int prec, char *signp, int fmtch, char *startp, char *endp)
{ {
char bf[12]; register char *p, *t;
register double fract;
double integer, tmp;
int dotrim, expcnt, gformat;
dotrim = expcnt = gformat = 0;
if (number < 0) {
number = -number;
*signp = '-';
} else
*signp = 0;
char ch; fract = modf(number, &integer);
/* get an extra slot for rounding. */
t = ++startp;
while ((ch = *(fmt++))) /*
{ * get integer portion of number; put into the end of the buffer; the
if (ch != '%') * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
putf(putp, ch); */
for (p = endp - 1; integer; ++expcnt) {
tmp = modf(integer / 10, &integer);
*p-- = to_char((int)((tmp + .01) * 10));
}
switch (fmtch) {
case 'f':
/* reverse integer into beginning of buffer */
if (expcnt)
for (; ++p < endp; *t++ = *p);
else else
{ *t++ = '0';
char lz = 0; /*
#ifdef PRINTF_LONG_SUPPORT * if precision required or alternate flag set, add in a
char lng = 0; * decimal point.
#endif */
int w = 0; if (prec || TESTFLAG(ALTERNATE_FORM))
ch = *(fmt++); *t++ = '.';
if (ch == '0') /* if requires more precision and some fraction left */
{ if (fract) {
ch = *(fmt++); if (prec)
lz = 1; do {
} fract = modf(fract * 10, &tmp);
if (ch >= '0' && ch <= '9') *t++ = to_char((int)tmp);
{ } while (--prec && fract);
ch = a2i(ch, &fmt, 10, &w); if (fract)
} startp = c_round(fract, (int *)NULL, startp,
#ifdef PRINTF_LONG_SUPPORT t - 1, (char)0, signp);
if (ch == 'l') }
{ for (; prec--; *t++ = '0');
ch = *(fmt++); break;
lng = 1; case 'e':
} case 'E':
#endif eformat: if (expcnt) {
switch (ch) *t++ = *++p;
{ if (prec || TESTFLAG(ALTERNATE_FORM))
case 0: *t++ = '.';
goto abort; /* if requires more precision and some integer left */
case 'u' : for (; prec && ++p < endp; --prec)
{ *t++ = *p;
#ifdef PRINTF_LONG_SUPPORT /*
if (lng) * if done precision and more of the integer component,
uli2a(va_arg(va, unsigned long int), 10, 0, bf); * round using it; adjust fract so we don't re-round
else * later.
#endif */
ui2a(va_arg(va, unsigned int), 10, 0, bf); if (!prec && ++p < endp) {
putchw(putp, putf, w, lz, bf); fract = 0;
break; startp = c_round((double)0, &expcnt, startp,
t - 1, *p, signp);
} }
case 'o' : /* adjust expcnt for digit in front of decimal */
{ --expcnt;
#ifdef PRINTF_LONG_SUPPORT }
if (lng) /* until first fractional digit, decrement exponent */
uli2a(va_arg(va, unsigned long int), 8, 0, bf); else if (fract) {
else /* adjust expcnt for digit in front of decimal */
#endif for (expcnt = -1;; --expcnt) {
ui2a(va_arg(va, unsigned int), 8, 0, bf); fract = modf(fract * 10, &tmp);
putchw(putp, putf, w, lz, bf); if (tmp)
break; break;
} }
case 'd' : case 'i': *t++ = to_char((int)tmp);
{ if (prec || TESTFLAG(ALTERNATE_FORM))
#ifdef PRINTF_LONG_SUPPORT *t++ = '.';
if (lng) }
li2a(va_arg(va, unsigned long int), bf); else {
else *t++ = '0';
#endif if (prec || TESTFLAG(ALTERNATE_FORM))
i2a(va_arg(va, int), bf); *t++ = '.';
putchw(putp, putf, w, lz, bf); }
break; /* if requires more precision and some fraction left */
if (fract) {
if (prec)
do {
fract = modf(fract * 10, &tmp);
*t++ = to_char((int)tmp);
} while (--prec && fract);
if (fract)
startp = c_round(fract, &expcnt, startp,
t - 1, (char)0, signp);
}
/* if requires more precision */
for (; prec--; *t++ = '0');
/* unless alternate flag, trim any g/G format trailing 0's */
if (gformat && !TESTFLAG(ALTERNATE_FORM)) {
while (t > startp && *--t == '0');
if (*t == '.')
--t;
++t;
}
t = exponent(t, expcnt, fmtch);
break;
case 'g':
case 'G':
/* a precision of 0 is treated as a precision of 1. */
if (!prec)
++prec;
/*
* ``The style used depends on the value converted; style e
* will be used only if the exponent resulting from the
* conversion is less than -4 or greater than the precision.''
* -- ANSI X3J11
*/
if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
/*
* g/G format counts "significant digits, not digits of
* precision; for the e/E format, this just causes an
* off-by-one problem, i.e. g/G considers the digit
* before the decimal point significant and e/E doesn't
* count it as precision.
*/
--prec;
fmtch -= 2; /* G->E, g->e */
gformat = 1;
goto eformat;
}
/*
* reverse integer into beginning of buffer,
* note, decrement precision
*/
if (expcnt)
for (; ++p < endp; *t++ = *p, --prec);
else
*t++ = '0';
/*
* if precision required or alternate flag set, add in a
* decimal point. If no digits yet, add in leading 0.
*/
if (prec || TESTFLAG(ALTERNATE_FORM)) {
dotrim = 1;
*t++ = '.';
}
else
dotrim = 0;
/* if requires more precision and some fraction left */
if (fract) {
if (prec) {
do {
fract = modf(fract * 10, &tmp);
*t++ = to_char((int)tmp);
} while(!tmp && !expcnt);
while (--prec && fract) {
fract = modf(fract * 10, &tmp);
*t++ = to_char((int)tmp);
}
} }
case 'x': case 'X' : if (fract)
#ifdef PRINTF_LONG_SUPPORT startp = c_round(fract, (int *)NULL, startp,
if (lng) t - 1, (char)0, signp);
uli2a(va_arg(va, unsigned long int), 16, (ch == 'X'), bf); }
else /* alternate format, adds 0's for precision, else trim 0's */
#endif if (TESTFLAG(ALTERNATE_FORM))
ui2a(va_arg(va, unsigned int), 16, (ch == 'X'), bf); for (; prec--; *t++ = '0');
putchw(putp, putf, w, lz, bf); else if (dotrim) {
while (t > startp && *--t == '0');
if (*t != '.')
++t;
}
}
return (t - startp);
}
static char *
c_round(double fract, int *exp, char *start, char *end, char ch, char *signp)
{
double tmp;
if (fract)
(void)modf(fract * 10, &tmp);
else
tmp = to_digit(ch);
if (tmp > 4)
for (;; --end) {
if (*end == '.')
--end;
if (++*end <= '9')
break; break;
case 'e': case 'E': case 'f': *end = '0';
case 'g': case 'G': if (end == start) {
{ if (exp) { /* e/E; increment exponent */
d2a(va_arg(va, double), bf); *end = '1';
putchw(putp, putf, w, lz, bf); ++*exp;
}
else { /* f; add extra digit */
*--end = '1';
--start;
}
break; break;
} }
case 'c' : }
putf(putp, (char)(va_arg(va, int))); /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
break; else if (*signp == '-')
case 's' : for (;; --end) {
putchw(putp, putf, w, 0, va_arg(va, char *)); if (*end == '.')
break; --end;
case '%' : if (*end != '0')
putf(putp, ch);
default:
break; break;
} if (end == start)
*signp = 0;
} }
} return (start);
abort:;
} }
static char *
static void putcp(void *p, char c) exponent(char *p, int exp, int fmtch)
{ {
*(*((char **)p))++ = c; char *t;
char expbuf[MAX_FCONVERSION];
*p++ = fmtch;
if (exp < 0) {
exp = -exp;
*p++ = '-';
}
else
*p++ = '+';
t = expbuf + MAX_FCONVERSION;
if (exp > 9) {
do {
*--t = to_char(exp % 10);
} while ((exp /= 10) > 9);
*--t = to_char(exp);
for (; t < expbuf + MAX_FCONVERSION; *p++ = *t++);
}
else {
*p++ = '0';
*p++ = to_char(exp);
}
return (p);
} }
#endif /* FLOATINGPT */
void c_sprintf(char *s, char *fmt, ...) void c_sprintf(char *s, char *fmt, ...)
{ {
va_list va; va_list arg;
va_start(va, fmt); va_start(arg, fmt);
c_format(&s, putcp, fmt, va); vsprintf(s, fmt, arg);
putcp(&s, 0); va_end(arg);
va_end(va);
} }
#endif #endif
...@@ -3,68 +3,65 @@ ...@@ -3,68 +3,65 @@
#include "c_types.h" #include "c_types.h"
#include "c_string.h" #include "c_string.h"
#include "user_interface.h" #include "user_interface.h"
#include "user_config.h"
// const char *lua_init_value = "print(\"Hello world\")"; // const char *lua_init_value = "print(\"Hello world\")";
const char *lua_init_value = "@init.lua"; const char *lua_init_value = "@init.lua";
// int c_abs(int x){ // int c_abs(int x){
// return x>0?x:0-x; // return x>0?x:0-x;
// } // }
// void c_exit(int e){ // void c_exit(int e){
// } // }
const char *c_getenv(const char *__string){ const char *c_getenv(const char *__string)
if (c_strcmp(__string, "LUA_INIT") == 0){ {
return lua_init_value; if (c_strcmp(__string, "LUA_INIT") == 0)
} {
return NULL; return lua_init_value;
}
return NULL;
} }
// make sure there is enough memory before real malloc, otherwise malloc will panic and reset // make sure there is enough memory before real malloc, otherwise malloc will panic and reset
// void *c_malloc(size_t __size){ // void *c_malloc(size_t __size){
// if(__size>system_get_free_heap_size()){ // if(__size>system_get_free_heap_size()){
// NODE_ERR("malloc: not enough memory\n"); // NODE_ERR("malloc: not enough memory\n");
// return NULL; // return NULL;
// } // }
// return (void *)os_malloc(__size); // return (void *)os_malloc(__size);
// } // }
// void *c_zalloc(size_t __size){ // void *c_zalloc(size_t __size){
// if(__size>system_get_free_heap_size()){ // if(__size>system_get_free_heap_size()){
// NODE_ERR("zalloc: not enough memory\n"); // NODE_ERR("zalloc: not enough memory\n");
// return NULL; // return NULL;
// } // }
// return (void *)os_zalloc(__size); // return (void *)os_zalloc(__size);
// } // }
// void c_free(void *p){ // void c_free(void *p){
// // NODE_ERR("free1: %d\n", system_get_free_heap_size()); // // NODE_ERR("free1: %d\n", system_get_free_heap_size());
// os_free(p); // os_free(p);
// // NODE_ERR("-free1: %d\n", system_get_free_heap_size()); // // NODE_ERR("-free1: %d\n", system_get_free_heap_size());
// } // }
// int c_rand(void){ // int c_rand(void){
// } // }
// void c_srand(unsigned int __seed){ // void c_srand(unsigned int __seed){
// } // }
// int c_atoi(const char *__nptr){ // int c_atoi(const char *__nptr){
// } // }
#include <_ansi.h> #include <_ansi.h>
//#include <reent.h> //#include <reent.h>
#include <string.h> #include <string.h>
//#include "mprec.h" //#include "mprec.h"
double c_strtod(const char *string, char **endPtr) double powersOf10[] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = /* Table giving binary powers of 10. Entry */
{ {
int maxExponent = 511; /* Largest possible base 10 exponent. Any 10., /* is 10^2^i. Used to convert decimal */
* exponent larger than this will already 100., /* exponents into floating-point numbers. */
* produce underflow or overflow, so there's
* no need to worry about additional digits.
*/
double powersOf10[] = { /* Table giving binary powers of 10. Entry */
10., /* is 10^2^i. Used to convert decimal */
100., /* exponents into floating-point numbers. */
1.0e4, 1.0e4,
1.0e8, 1.0e8,
1.0e16, 1.0e16,
...@@ -72,43 +69,57 @@ double c_strtod(const char *string, char **endPtr) ...@@ -72,43 +69,57 @@ double c_strtod(const char *string, char **endPtr)
1.0e64, 1.0e64,
1.0e128, 1.0e128,
1.0e256 1.0e256
}; };
double c_strtod(const char *string, char **endPtr)
{
int maxExponent = 511; /* Largest possible base 10 exponent. Any
* exponent larger than this will already
* produce underflow or overflow, so there's
* no need to worry about additional digits.
*/
int sign, expSign = FALSE; int sign, expSign = FALSE;
double fraction, dblExp, *d; double fraction, dblExp, *d;
register const char *p; register const char *p;
register int c; register int c;
int exp = 0; /* Exponent read from "EX" field. */ int exp = 0; /* Exponent read from "EX" field. */
int fracExp = 0; /* Exponent that derives from the fractional int fracExp = 0; /* Exponent that derives from the fractional
* part. Under normal circumstatnces, it is * part. Under normal circumstatnces, it is
* the negative of the number of digits in F. * the negative of the number of digits in F.
* However, if I is very long, the last digits * However, if I is very long, the last digits
* of I get dropped (otherwise a long I with a * of I get dropped (otherwise a long I with a
* large negative exponent could cause an * large negative exponent could cause an
* unnecessary overflow on I alone). In this * unnecessary overflow on I alone). In this
* case, fracExp is incremented one for each * case, fracExp is incremented one for each
* dropped digit. */ * dropped digit. */
int mantSize; /* Number of digits in mantissa. */ int mantSize; /* Number of digits in mantissa. */
int decPt; /* Number of mantissa digits BEFORE decimal int decPt; /* Number of mantissa digits BEFORE decimal
* point. */ * point. */
const char *pExp; /* Temporarily holds location of exponent const char *pExp; /* Temporarily holds location of exponent
* in string. */ * in string. */
/* /*
* Strip off leading blanks and check for a sign. * Strip off leading blanks and check for a sign.
*/ */
p = string; p = string;
while (isspace((unsigned char)(*p))) { while (isspace((unsigned char)(*p)))
p += 1; {
p += 1;
}
if (*p == '-')
{
sign = TRUE;
p += 1;
} }
if (*p == '-') { else
sign = TRUE; {
p += 1; if (*p == '+')
} else { {
if (*p == '+') { p += 1;
p += 1; }
} sign = FALSE;
sign = FALSE;
} }
/* /*
...@@ -119,14 +130,16 @@ double c_strtod(const char *string, char **endPtr) ...@@ -119,14 +130,16 @@ double c_strtod(const char *string, char **endPtr)
decPt = -1; decPt = -1;
for (mantSize = 0; ; mantSize += 1) for (mantSize = 0; ; mantSize += 1)
{ {
c = *p; c = *p;
if (!isdigit(c)) { if (!isdigit(c))
if ((c != '.') || (decPt >= 0)) { {
break; if ((c != '.') || (decPt >= 0))
} {
decPt = mantSize; break;
} }
p += 1; decPt = mantSize;
}
p += 1;
} }
/* /*
...@@ -135,49 +148,60 @@ double c_strtod(const char *string, char **endPtr) ...@@ -135,49 +148,60 @@ double c_strtod(const char *string, char **endPtr)
* If the mantissa has more than 18 digits, ignore the extras, since * If the mantissa has more than 18 digits, ignore the extras, since
* they can't affect the value anyway. * they can't affect the value anyway.
*/ */
pExp = p; pExp = p;
p -= mantSize; p -= mantSize;
if (decPt < 0) { if (decPt < 0)
decPt = mantSize; {
} else { decPt = mantSize;
mantSize -= 1; /* One of the digits was the point. */
} }
if (mantSize > 18) { else
fracExp = decPt - 18; {
mantSize = 18; mantSize -= 1; /* One of the digits was the point. */
} else {
fracExp = decPt - mantSize;
} }
if (mantSize == 0) { if (mantSize > 18)
fraction = 0.0; {
p = string; fracExp = decPt - 18;
goto done; mantSize = 18;
} else { }
int frac1, frac2; else
frac1 = 0; {
for ( ; mantSize > 9; mantSize -= 1) fracExp = decPt - mantSize;
{ }
c = *p; if (mantSize == 0)
p += 1; {
if (c == '.') { fraction = 0.0;
c = *p; p = string;
p += 1; goto done;
} }
frac1 = 10*frac1 + (c - '0'); else
} {
frac2 = 0; int frac1, frac2;
for (; mantSize > 0; mantSize -= 1) frac1 = 0;
{ for ( ; mantSize > 9; mantSize -= 1)
c = *p; {
p += 1; c = *p;
if (c == '.') { p += 1;
c = *p; if (c == '.')
p += 1; {
} c = *p;
frac2 = 10*frac2 + (c - '0'); p += 1;
} }
fraction = (1.0e9 * frac1) + frac2; frac1 = 10 * frac1 + (c - '0');
}
frac2 = 0;
for (; mantSize > 0; mantSize -= 1)
{
c = *p;
p += 1;
if (c == '.')
{
c = *p;
p += 1;
}
frac2 = 10 * frac2 + (c - '0');
}
fraction = (1.0e9 * frac1) + frac2;
} }
/* /*
...@@ -185,30 +209,40 @@ double c_strtod(const char *string, char **endPtr) ...@@ -185,30 +209,40 @@ double c_strtod(const char *string, char **endPtr)
*/ */
p = pExp; p = pExp;
if ((*p == 'E') || (*p == 'e')) { if ((*p == 'E') || (*p == 'e'))
p += 1; {
if (*p == '-') { p += 1;
expSign = TRUE; if (*p == '-')
p += 1; {
} else { expSign = TRUE;
if (*p == '+') { p += 1;
p += 1; }
} else
expSign = FALSE; {
} if (*p == '+')
if (!isdigit((unsigned char)(*p))) { {
p = pExp; p += 1;
goto done; }
} expSign = FALSE;
while (isdigit((unsigned char)(*p))) { }
exp = exp * 10 + (*p - '0'); if (!isdigit((unsigned char)(*p)))
p += 1; {
} p = pExp;
goto done;
}
while (isdigit((unsigned char)(*p)))
{
exp = exp * 10 + (*p - '0');
p += 1;
}
} }
if (expSign) { if (expSign)
exp = fracExp - exp; {
} else { exp = fracExp - exp;
exp = fracExp + exp; }
else
{
exp = fracExp + exp;
} }
/* /*
...@@ -217,41 +251,52 @@ double c_strtod(const char *string, char **endPtr) ...@@ -217,41 +251,52 @@ double c_strtod(const char *string, char **endPtr)
* many powers of 2 of 10. Then combine the exponent with the * many powers of 2 of 10. Then combine the exponent with the
* fraction. * fraction.
*/ */
if (exp < 0) { if (exp < 0)
expSign = TRUE; {
exp = -exp; expSign = TRUE;
} else { exp = -exp;
expSign = FALSE;
} }
if (exp > maxExponent) { else
exp = maxExponent; {
// errno = ERANGE; expSign = FALSE;
}
if (exp > maxExponent)
{
exp = maxExponent;
// errno = ERANGE;
} }
dblExp = 1.0; dblExp = 1.0;
for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { for (d = powersOf10; exp != 0; exp >>= 1, d += 1)
if (exp & 01) { {
dblExp *= *d; if (exp & 01)
} {
dblExp *= *d;
}
}
if (expSign)
{
fraction /= dblExp;
} }
if (expSign) { else
fraction /= dblExp; {
} else { fraction *= dblExp;
fraction *= dblExp;
} }
done: done:
if (endPtr != NULL) { if (endPtr != NULL)
*endPtr = (char *) p; {
*endPtr = (char *) p;
} }
if (sign) { if (sign)
return -fraction; {
return -fraction;
} }
return fraction; return fraction;
} }
// long c_strtol(const char *__n, char **__end_PTR, int __base){ // long c_strtol(const char *__n, char **__end_PTR, int __base){
// } // }
// unsigned long c_strtoul(const char *__n, char **__end_PTR, int __base){ // unsigned long c_strtoul(const char *__n, char **__end_PTR, int __base){
// } // }
......
...@@ -601,8 +601,7 @@ extern int readline4lua(const char *prompt, char *buffer, int length); ...@@ -601,8 +601,7 @@ extern int readline4lua(const char *prompt, char *buffer, int length);
#endif // #if !defined LUA_INTEGRAL_LONGLONG #endif // #if !defined LUA_INTEGRAL_LONGLONG
#else #else
#define LUA_NUMBER_SCAN "%lf" #define LUA_NUMBER_SCAN "%lf"
//#define LUA_NUMBER_FMT "%.14g" #define LUA_NUMBER_FMT "%.14g"
#define LUA_NUMBER_FMT "%g"
#endif // #if defined LUA_NUMBER_INTEGRAL #endif // #if defined LUA_NUMBER_INTEGRAL
#define lua_number2str(s,n) c_sprintf((s), LUA_NUMBER_FMT, (n)) #define lua_number2str(s,n) c_sprintf((s), LUA_NUMBER_FMT, (n))
#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ #define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
......
...@@ -718,3 +718,32 @@ espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t ...@@ -718,3 +718,32 @@ espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t
return dns_gethostbyname(hostname, addr, found, pespconn); return dns_gethostbyname(hostname, addr, found, pespconn);
} }
sint8 espconn_recv_hold(struct espconn *pespconn) {
espconn_msg *pnode = NULL;
if (pespconn == NULL) {
return ESPCONN_ARG;
}
pespconn->state = ESPCONN_WRITE;
if (!espconn_find_connection(pespconn, &pnode)) {
return ESPCONN_ARG;
}
espconn_tcp_hold(pnode);
return ESPCONN_OK;
}
sint8 espconn_recv_unhold(struct espconn *pespconn) {
espconn_msg *pnode = NULL;
if (pespconn == NULL) {
return ESPCONN_ARG;
}
pespconn->state = ESPCONN_WRITE;
if (!espconn_find_connection(pespconn, &pnode)) {
return ESPCONN_ARG;
}
espconn_tcp_unhold(pnode);
return ESPCONN_OK;
}
...@@ -948,3 +948,19 @@ sint8 ICACHE_FLASH_ATTR espconn_tcp_delete(struct espconn *pdeletecon) ...@@ -948,3 +948,19 @@ sint8 ICACHE_FLASH_ATTR espconn_tcp_delete(struct espconn *pdeletecon)
return ESPCONN_ARG; return ESPCONN_ARG;
} }
} }
void espconn_tcp_hold(void *arg) {
espconn_msg *ptcp_sent = arg;
struct tcp_pcb *pcb = NULL;
pcb = ptcp_sent->pcommon.pcb;
pcb->hold = 1;
}
void espconn_tcp_unhold(void *arg) {
espconn_msg *ptcp_sent = arg;
struct tcp_pcb *pcb = NULL;
pcb = ptcp_sent->pcommon.pcb;
pcb->hold = 0;
}
...@@ -1259,6 +1259,7 @@ tcp_alloc(u8_t prio) ...@@ -1259,6 +1259,7 @@ tcp_alloc(u8_t prio)
#endif /* LWIP_TCP_KEEPALIVE */ #endif /* LWIP_TCP_KEEPALIVE */
pcb->keep_cnt_sent = 0; //���ķ��ʹ��� pcb->keep_cnt_sent = 0; //���ķ��ʹ���
pcb->hold = 0;
} }
return pcb; return pcb;
} }
......
...@@ -1137,7 +1137,7 @@ tcp_receive(struct tcp_pcb *pcb) ...@@ -1137,7 +1137,7 @@ tcp_receive(struct tcp_pcb *pcb)
/* If the incoming segment contains data, we must process it /* If the incoming segment contains data, we must process it
further. */ further. */
if (tcplen > 0) { if ((tcplen > 0) && (!pcb->hold)) {
/* This code basically does three things: /* This code basically does three things:
+) If the incoming segment contains data that is the next +) If the incoming segment contains data that is the next
......
...@@ -125,7 +125,7 @@ static int file_remove( lua_State* L ) ...@@ -125,7 +125,7 @@ static int file_remove( lua_State* L )
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");
file_close(L); file_close(L);
SPIFFS_remove(&fs, fname); SPIFFS_remove(&fs, (char *)fname);
return 0; return 0;
} }
...@@ -150,6 +150,31 @@ static int file_check( lua_State* L ) ...@@ -150,6 +150,31 @@ static int file_check( lua_State* L )
} }
#endif #endif
// Lua: rename("oldname", "newname")
static int file_rename( lua_State* L )
{
size_t len;
if((FS_OPEN_OK - 1)!=file_fd){
fs_close(file_fd);
file_fd = FS_OPEN_OK - 1;
}
const char *oldname = luaL_checklstring( L, 1, &len );
if( len > FS_NAME_MAX_LENGTH )
return luaL_error(L, "filename too long");
const char *newname = luaL_checklstring( L, 2, &len );
if( len > FS_NAME_MAX_LENGTH )
return luaL_error(L, "filename too long");
if(SPIFFS_OK==myspiffs_rename( oldname, newname )){
lua_pushboolean(L, 1);
} else {
lua_pushboolean(L, 0);
}
return 1;
}
#endif #endif
// g_read() // g_read()
...@@ -282,6 +307,7 @@ const LUA_REG_TYPE file_map[] = ...@@ -282,6 +307,7 @@ const LUA_REG_TYPE file_map[] =
{ LSTRKEY( "seek" ), LFUNCVAL( file_seek ) }, { LSTRKEY( "seek" ), LFUNCVAL( file_seek ) },
{ 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 ) },
#endif #endif
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
......
...@@ -117,6 +117,15 @@ ...@@ -117,6 +117,15 @@
#define ROM_MODULES_BIT #define ROM_MODULES_BIT
#endif #endif
#if defined(LUA_USE_MODULES_WS2812)
#define MODULES_WS2812 "ws2812"
#define ROM_MODULES_WS2812 \
_ROM(MODULES_WS2812, luaopen_ws2812, ws2812_map)
#else
#define ROM_MODULES_WS2812
#endif
#define LUA_MODULES_ROM \ #define LUA_MODULES_ROM \
ROM_MODULES_GPIO \ ROM_MODULES_GPIO \
ROM_MODULES_PWM \ ROM_MODULES_PWM \
...@@ -131,7 +140,8 @@ ...@@ -131,7 +140,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
#endif #endif
...@@ -1193,6 +1193,54 @@ static int net_socket_send( lua_State* L ) ...@@ -1193,6 +1193,54 @@ static int net_socket_send( lua_State* L )
return net_send(L, mt); return net_send(L, mt);
} }
static int net_socket_hold( lua_State* L )
{
const char *mt = "net.socket";
struct espconn *pesp_conn = NULL;
lnet_userdata *nud;
size_t l;
nud = (lnet_userdata *)luaL_checkudata(L, 1, mt);
luaL_argcheck(L, nud, 1, "Server/Socket expected");
if(nud==NULL){
NODE_DBG("userdata is nil.\n");
return 0;
}
if(nud->pesp_conn == NULL){
NODE_DBG("nud->pesp_conn is NULL.\n");
return 0;
}
pesp_conn = nud->pesp_conn;
espconn_recv_hold(pesp_conn);
return 0;
}
static int net_socket_unhold( lua_State* L )
{
const char *mt = "net.socket";
struct espconn *pesp_conn = NULL;
lnet_userdata *nud;
size_t l;
nud = (lnet_userdata *)luaL_checkudata(L, 1, mt);
luaL_argcheck(L, nud, 1, "Server/Socket expected");
if(nud==NULL){
NODE_DBG("userdata is nil.\n");
return 0;
}
if(nud->pesp_conn == NULL){
NODE_DBG("nud->pesp_conn is NULL.\n");
return 0;
}
pesp_conn = nud->pesp_conn;
espconn_recv_unhold(pesp_conn);
return 0;
}
// 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 )
{ {
...@@ -1251,6 +1299,8 @@ static const LUA_REG_TYPE net_socket_map[] = ...@@ -1251,6 +1299,8 @@ static const LUA_REG_TYPE net_socket_map[] =
{ LSTRKEY( "close" ), LFUNCVAL ( net_socket_close ) }, { LSTRKEY( "close" ), LFUNCVAL ( net_socket_close ) },
{ LSTRKEY( "on" ), LFUNCVAL ( net_socket_on ) }, { LSTRKEY( "on" ), LFUNCVAL ( net_socket_on ) },
{ LSTRKEY( "send" ), LFUNCVAL ( net_socket_send ) }, { LSTRKEY( "send" ), LFUNCVAL ( net_socket_send ) },
{ LSTRKEY( "hold" ), LFUNCVAL ( net_socket_hold ) },
{ LSTRKEY( "unhold" ), LFUNCVAL ( net_socket_unhold ) },
{ LSTRKEY( "dns" ), LFUNCVAL ( net_socket_dns ) }, { LSTRKEY( "dns" ), LFUNCVAL ( net_socket_dns ) },
// { LSTRKEY( "delete" ), LFUNCVAL ( net_socket_delete ) }, // { LSTRKEY( "delete" ), LFUNCVAL ( net_socket_delete ) },
{ LSTRKEY( "__gc" ), LFUNCVAL ( net_socket_delete ) }, { LSTRKEY( "__gc" ), LFUNCVAL ( net_socket_delete ) },
......
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
/**
* All this code is mostly from http://www.esp8266.com/viewtopic.php?f=21&t=1143&sid=a620a377672cfe9f666d672398415fcb
* from user Markus Gritsch.
* 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.
*
*/
// ----------------------------------------------------------------------------
// -- This WS2812 code must be compiled with -O2 to get the timing right.
// -- 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.
static void ICACHE_FLASH_ATTR send_ws_0(uint8_t gpio) {
uint8_t i;
i = 4;
while (i--)
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) {
uint8_t i;
i = 8;
while (i--)
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")
// Byte triples in the string are interpreted as G R B values.
// ws2812.write(4, string.char(0, 255, 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(4, string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white.
static int ICACHE_FLASH_ATTR ws2812_write(lua_State* L) {
const uint8_t pin = luaL_checkinteger(L, 1);
size_t length;
const char *buffer = luaL_checklstring(L, 2, &length);
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
platform_gpio_write(pin, 0);
os_delay_us(10);
os_intr_lock();
const char * const end = buffer + length;
while (buffer != end) {
uint8_t mask = 0x80;
while (mask) {
(*buffer & mask) ? send_ws_1(pin_num[pin]) : send_ws_0(pin_num[pin]);
mask >>= 1;
}
++buffer;
}
os_intr_unlock();
return 0;
}
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE ws2812_map[] =
{
{ LSTRKEY( "write" ), LFUNCVAL( ws2812_write )},
{ LNILKEY, LNILVAL}
};
LUALIB_API int luaopen_ws2812(lua_State *L) {
// TODO: Make sure that the GPIO system is initialized
LREGISTER(L, "ws2812", ws2812_map);
return 1;
}
// ----------------------------------------------------------------------------
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
#define FLASH_SEC_NUM 0x200 #define FLASH_SEC_NUM 0x200
#elif defined(FLASH_4M) #elif defined(FLASH_4M)
#define FLASH_SEC_NUM 0x400 #define FLASH_SEC_NUM 0x400
#elif defined(FLASH_8M)
#define FLASH_SEC_NUM 0x800
#elif defined(FLASH_16M)
#define FLASH_SEC_NUM 0x1000
#elif defined(FLASH_AUTOSIZE) #elif defined(FLASH_AUTOSIZE)
#define FLASH_SEC_NUM (flash_get_sec_num()) #define FLASH_SEC_NUM (flash_get_sec_num())
#else #else
......
...@@ -56,6 +56,12 @@ uint32_t flash_get_size_byte(void) ...@@ -56,6 +56,12 @@ uint32_t flash_get_size_byte(void)
case SIZE_32MBIT: case SIZE_32MBIT:
// 32Mbit, 4MByte // 32Mbit, 4MByte
flash_size = 4 * 1024 * 1024; flash_size = 4 * 1024 * 1024;
case SIZE_64MBIT:
// 64Mbit, 8MByte
flash_size = 8 * 1024 * 1024;
case SIZE_128MBIT:
// 128Mbit, 16MByte
flash_size = 16 * 1024 * 1024;
break; break;
default: default:
// Unknown flash size, fall back mode. // Unknown flash size, fall back mode.
......
...@@ -52,6 +52,8 @@ typedef struct ...@@ -52,6 +52,8 @@ typedef struct
SIZE_8MBIT = 2, SIZE_8MBIT = 2,
SIZE_16MBIT = 3, SIZE_16MBIT = 3,
SIZE_32MBIT = 4, SIZE_32MBIT = 4,
SIZE_64MBIT = 5,
SIZE_128MBIT = 6,
} size : 4; } size : 4;
} ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo; } ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo;
......
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