Removed all currently-unused code & docs.

Heading towards having only ESP32-aware/capable code in this branch.
This commit is contained in:
Johny Mattsson 2016-09-21 13:47:44 +10:00
parent ddeb26c458
commit fe602d2d7e
493 changed files with 6 additions and 407818 deletions

4
.gitmodules vendored
View File

@ -1,9 +1,7 @@
[submodule "esp8266-rtos-sdk"]
path = sdk/esp8266-rtos-sdk
url = https://github.com/espressif/ESP8266_RTOS_SDK.git
[submodule "toolchains"]
path = tools/toolchains
url = https://github.com/jmattsson/nodemcu-prebuilt-toolchains.git
[submodule "sdk/esp32-esp-idf"]
path = sdk/esp32-esp-idf
url = https://github.com/espressif/esp-idf.git
ignore = dirty

108
README.md
View File

@ -1,108 +0,0 @@
# **NodeMCU 1.5.1** #
[![Join the chat at https://gitter.im/nodemcu/nodemcu-firmware](https://img.shields.io/gitter/room/badges/shields.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)
[![Documentation Status](https://readthedocs.com/projects/nodemcu/badge/?version=dev)](http://nodemcu.readthedocs.io/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/nodemcu/nodemcu-firmware/blob/master/LICENSE)
### A Lua based firmware for ESP8266 WiFi SOC
NodeMCU is an [eLua](http://www.eluaproject.net/) based firmware for the [ESP8266 WiFi SOC from Espressif](http://espressif.com/en/products/esp8266/). The firmware is based on the [Espressif NON-OS SDK 1.5.1](http://bbs.espressif.com/viewtopic.php?f=46&p=5315) and uses a file system based on [spiffs](https://github.com/pellepl/spiffs). The code repository consists of 98.1% C-code that glues the thin Lua veneer to the SDK.
The NodeMCU *firmware* is a companion project to the popular [NodeMCU dev kits](https://github.com/nodemcu/nodemcu-devkit-v1.0), ready-made open source development boards with ESP8266-12E chips.
# Summary
- Easy to program wireless node and/or access point
- Based on Lua 5.1.4 (without *debug, os* modules)
- Asynchronous event-driven programming model
- 40+ built-in modules
- Firmware available with or without floating point support (integer-only uses less memory)
- Up-to-date documentation at [https://nodemcu.readthedocs.io](https://nodemcu.readthedocs.io)
# Programming Model
The NodeMCU programming model is similar to that of [Node.js](https://en.wikipedia.org/wiki/Node.js), only in Lua. It is asynchronous and event-driven. Many functions, therefore, have parameters for callback functions. To give you an idea what a NodeMCU program looks like study the short snippets below. For more extensive examples have a look at the [`/lua_examples`](lua_examples) folder in the repository on GitHub.
```lua
-- a simple HTTP server
srv = net.createServer(net.TCP)
srv:listen(80, function(conn)
conn:on("receive", function(conn, payload)
print(payload)
conn:send("<h1> Hello, NodeMCU.</h1>")
end)
conn:on("sent", function(conn) conn:close() end)
end)
```
```lua
-- connect to WiFi access point
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID", "password")
```
# Documentation
The entire [NodeMCU documentation](https://nodemcu.readthedocs.io) is maintained right in this repository at [/docs](docs). The fact that the API documentation is mainted in the same repository as the code that *provides* the API ensures consistency between the two. With every commit the documentation is rebuilt by Read the Docs and thus transformed from terse Markdown into a nicely browsable HTML site at [https://nodemcu.readthedocs.io](https://nodemcu.readthedocs.io).
- How to [build the firmware](https://nodemcu.readthedocs.io/en/dev/en/build/)
- How to [flash the firmware](https://nodemcu.readthedocs.io/en/dev/en/flash/)
- How to [upload code and NodeMCU IDEs](https://nodemcu.readthedocs.io/en/dev/en/upload/)
- API documentation for every module
# Support
See [https://nodemcu.readthedocs.io/en/dev/en/support/](https://nodemcu.readthedocs.io/en/dev/en/support/).
# License
[MIT](https://github.com/nodemcu/nodemcu-firmware/blob/master/LICENSE) © [zeroday](https://github.com/NodeMCU)/[nodemcu.com](http://nodemcu.com/index_en.html)
# Build Options
The following sections explain some of the options you have if you want to [build your own NodeMCU firmware](http://nodemcu.readthedocs.io/en/dev/en/build/).
### Select Modules
Disable modules you won't be using to reduce firmware size and free up some RAM. The ESP8266 is quite limited in available RAM and running out of memory can cause a system panic. The default configuration is designed to run on all ESP modules including the 512 KB modules like ESP-01 and only includes general purpose interface modules which require at most two GPIO pins.
Edit `app/include/user_modules.h` and comment-out the `#define` statement for modules you don't need. Example:
```c
...
#define LUA_USE_MODULES_MQTT
// #define LUA_USE_MODULES_COAP
// #define LUA_USE_MODULES_U8G
...
```
### Tag Your Build
Identify your firmware builds by editing `app/include/user_version.h`
```c
#define NODE_VERSION "NodeMCU 1.5.1+myname"
#ifndef BUILD_DATE
#define BUILD_DATE "YYYYMMDD"
#endif
```
### Set UART Bit Rate
The initial baud rate at boot time is 115200bps. You can change this by
editing `BIT_RATE_DEFAULT` in `app/include/user_config.h`:
```c
#define BIT_RATE_DEFAULT BIT_RATE_115200
```
Note that, by default, the firmware runs an auto-baudrate detection algorithm so that typing a few characters at boot time will cause
the firmware to lock onto that baud rate (between 1200 and 230400).
### Debugging
To enable runtime debug messages to serial console edit `app/include/user_config.h`
```c
#define DEVELOP_VERSION
```

3
app/.gitignore vendored
View File

@ -1,3 +0,0 @@
*.output*
mapfile*
!.gitignore

View File

@ -1,181 +0,0 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of object file images to be generated ()
# GEN_BINS - list of binaries to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
#FLAVOR = release
FLAVOR = debug
#EXTRA_CCFLAGS += -u
ifndef PDIR # {
GEN_IMAGES= eagle.app.v6.out
GEN_BINS= eagle.app.v6.bin
SPECIAL_MKTARGETS=$(APP_MKTARGETS)
SUBDIRS= \
user \
driver \
json \
platform \
lua \
coap \
mqtt \
task \
u8glib \
ucglib \
smart \
modules \
spiffs \
cjson \
crypto \
dhtlib \
tsl2561 \
net \
http
endif # } PDIR
APPDIR = .
LDDIR = ../ld
CCFLAGS += -Os
TARGET_LDFLAGS = \
-nostdlib \
-Wl,-EL \
--longcalls \
--text-section-literals
ifeq ($(FLAVOR),debug)
TARGET_LDFLAGS += -g -Os
endif
ifeq ($(FLAVOR),release)
TARGET_LDFLAGS += -Os
endif
COMPONENTS_eagle.app.v6 = \
user/libuser.a \
driver/libdriver.a \
json/libjson.a \
platform/libplatform.a \
task/libtask.a \
lua/liblua.a \
coap/coap.a \
mqtt/mqtt.a \
u8glib/u8glib.a \
ucglib/ucglib.a \
smart/smart.a \
spiffs/spiffs.a \
cjson/libcjson.a \
crypto/libcrypto.a \
dhtlib/libdhtlib.a \
tsl2561/tsl2561lib.a \
http/libhttp.a \
net/libnodemcu_net.a \
modules/libmodules.a \
# Inspect the modules library and work out which modules need to be linked.
# For each enabled module, a symbol name of the form XYZ_module_selected is
# returned. At link time those names are declared undefined, so those (and
# only those) modules are pulled in.
SELECTED_MODULE_SYMS=$(filter %_module_selected %module_selected1,$(shell $(NM) modules/.output/$(TARGET)/$(FLAVOR)/lib/libmodules.a))
USED_SDK_LIBS= \
crypto \
freertos \
gcc \
lwip \
main \
net80211 \
phy \
pp \
smartconfig \
ssl \
wpa \
wps \
$(TARGET_SDK_LIBS) \
LINKFLAGS_eagle.app.v6 = \
-Wl,--gc-sections \
-Wl,-Map=mapfile.$(TARGET) \
-nostdlib \
-T$(LD_FILE) \
-Wl,@$(LDDIR)/defsym.rom \
-T$(LDDIR)/extrasyms.rom \
-Wl,--no-check-sections \
-Wl,-static \
$(TARGET_LDFLAGS) \
$(addprefix -u , $(SELECTED_MODULE_SYMS)) \
-Wl,--start-group \
$(DEP_LIBS_eagle.app.v6) \
-Wl,--end-group \
-Wl,--no-gc-sections \
-Wl,--start-group \
$(addprefix -l,$(USED_SDK_LIBS)) \
-lhal \
-Wl,--end-group \
DEPENDS_eagle.app.v6 = \
$(LD_FILE) \
Makefile
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#UNIVERSAL_TARGET_DEFINES = \
# Other potential configuration flags include:
# -DTXRX_TXBUF_DEBUG
# -DTXRX_RXBUF_DEBUG
# -DWLAN_CONFIG_CCX
CONFIGURATION_DEFINES = -D__ets__ \
-DICACHE_FLASH \
-DLUA_OPTIMIZE_MEMORY=2 \
-DMIN_OPT_LEVEL=2 \
-DLWIP_OPEN_SRC \
-DPBUF_RSV_FOR_WLAN \
-DEBUF_LWIP \
DEFINES += \
$(UNIVERSAL_TARGET_DEFINES) \
$(CONFIGURATION_DEFINES)
DDEFINES += \
$(UNIVERSAL_TARGET_DEFINES) \
$(CONFIGURATION_DEFINES)
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
.PHONY: FORCE
FORCE:

View File

@ -1,76 +0,0 @@
# If Lua is installed in a non-standard location, please set the LUA_DIR
# environment variable to point to prefix for the install. Eg:
# Unix: export LUA_DIR=/home/user/pkg
# Windows: set LUA_DIR=c:\lua51
project(lua-cjson C)
cmake_minimum_required(VERSION 2.6)
option(USE_INTERNAL_FPCONV "Use internal strtod() / g_fmt() code for performance")
option(MULTIPLE_THREADS "Support multi-threaded apps with internal fpconv - recommended" ON)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
find_package(Lua51 REQUIRED)
include_directories(${LUA_INCLUDE_DIR})
if(NOT USE_INTERNAL_FPCONV)
# Use libc number conversion routines (strtod(), sprintf())
set(FPCONV_SOURCES fpconv.c)
else()
# Use internal number conversion routines
add_definitions(-DUSE_INTERNAL_FPCONV)
set(FPCONV_SOURCES g_fmt.c dtoa.c)
include(TestBigEndian)
TEST_BIG_ENDIAN(IEEE_BIG_ENDIAN)
if(IEEE_BIG_ENDIAN)
add_definitions(-DIEEE_BIG_ENDIAN)
endif()
if(MULTIPLE_THREADS)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
if(NOT CMAKE_USE_PTHREADS_INIT)
message(FATAL_ERROR
"Pthreads not found - required by MULTIPLE_THREADS option")
endif()
add_definitions(-DMULTIPLE_THREADS)
endif()
endif()
# Handle platforms missing isinf() macro (Eg, some Solaris systems).
include(CheckSymbolExists)
CHECK_SYMBOL_EXISTS(isinf math.h HAVE_ISINF)
if(NOT HAVE_ISINF)
add_definitions(-DUSE_INTERNAL_ISINF)
endif()
set(_MODULE_LINK "${CMAKE_THREAD_LIBS_INIT}")
get_filename_component(_lua_lib_dir ${LUA_LIBRARY} PATH)
if(APPLE)
set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS
"${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -undefined dynamic_lookup")
endif()
if(WIN32)
# Win32 modules need to be linked to the Lua library.
set(_MODULE_LINK ${LUA_LIBRARY} ${_MODULE_LINK})
set(_lua_module_dir "${_lua_lib_dir}")
# Windows sprintf()/strtod() handle NaN/inf differently. Not supported.
add_definitions(-DDISABLE_INVALID_NUMBERS)
else()
set(_lua_module_dir "${_lua_lib_dir}/lua/5.1")
endif()
add_library(cjson MODULE lua_cjson.c strbuf.c ${FPCONV_SOURCES})
set_target_properties(cjson PROPERTIES PREFIX "")
target_link_libraries(cjson ${_MODULE_LINK})
install(TARGETS cjson DESTINATION "${_lua_module_dir}")
# vi:ai et sw=4 ts=4:

View File

@ -1,21 +0,0 @@
Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
2015 Zeroday Hong <zeroday@nodemcu.com> nodemcu.com
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,47 +0,0 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libcjson.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../libc
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -1,9 +0,0 @@
The following people have helped with bug reports, testing and/or
suggestions:
- Louis-Philippe Perron (@loopole)
- Ondřej Jirman
- Steve Donovan <steve.j.donovan@gmail.com>
- Zhang "agentzh" Yichun <agentzh@gmail.com>
Thanks!

View File

@ -1,28 +0,0 @@
#include "cjson_mem.h"
#include "../lua/lauxlib.h"
#include <stdlib.h>
static lua_State *gL;
static const char errfmt[] = "cjson %salloc: out of mem (%d bytes)";
void cjson_mem_setlua (lua_State *L)
{
gL = L;
}
void *cjson_mem_malloc (uint32_t sz)
{
void *p = (void*)malloc (sz);
if (!p && gL)
luaL_error (gL, errfmt, "m", sz);
return p;
}
void *cjson_mem_realloc (void *o, uint32_t sz)
{
void *p = (void*)realloc (o, sz);
if (!p && gL)
luaL_error (gL, errfmt, "re", sz);
return p;
}

View File

@ -1,12 +0,0 @@
#ifndef _CJSON_MEM_H_
#define _CJSON_MEM_H_
#include <stdint.h>
#include "../lua/lua.h"
void cjson_mem_setlua (lua_State *L);
void *cjson_mem_malloc (uint32_t sz);
void *cjson_mem_realloc (void *p, uint32_t sz);
#endif

View File

@ -1,50 +0,0 @@
parser:
- call parse_value
- next_token
? <EOF> nop.
parse_value:
- next_token
? <OBJ_BEGIN> call parse_object.
? <ARR_BEGIN> call parse_array.
? <STRING> push. return.
? <BOOLEAN> push. return.
? <NULL> push. return.
? <NUMBER> push. return.
parse_object:
- push table
- next_token
? <STRING> push.
- next_token
? <COLON> nop.
- call parse_value
- set table
- next_token
? <OBJ_END> return.
? <COMMA> loop parse_object.
parse_array:
- push table
- call parse_value
- table append
- next_token
? <COMMA> loop parse_array.
? ] return.
next_token:
- check next character
? { return <OBJ_BEGIN>
? } return <OBJ_END>
? [ return <ARR_BEGIN>
? ] return <ARR_END>
? , return <COMMA>
? : return <COLON>
? [-0-9] gobble number. return <NUMBER>
? " gobble string. return <STRING>
? [ \t\n] eat whitespace.
? n Check "null". return <NULL> or <UNKNOWN>
? t Check "true". return <BOOLEAN> or <UNKNOWN>
? f Check "false". return <BOOLEAN> or <UNKNOWN>
? . return <UNKNOWN>
? \0 return <END>

File diff suppressed because it is too large Load Diff

View File

@ -1,74 +0,0 @@
#ifndef _DTOA_CONFIG_H
#define _DTOA_CONFIG_H
#if 0
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
/* Ensure dtoa.c does not USE_LOCALE. Lua CJSON must not use locale
* aware conversion routines. */
#undef USE_LOCALE
/* dtoa.c should not touch errno, Lua CJSON does not use it, and it
* may not be threadsafe */
#define NO_ERRNO
#define Long int32_t
#define ULong uint32_t
#define Llong int64_t
#define ULLong uint64_t
#ifdef IEEE_BIG_ENDIAN
#define IEEE_MC68k
#else
#define IEEE_8087
#endif
#define MALLOC(n) xmalloc(n)
static void *xmalloc(size_t size)
{
void *p;
p = malloc(size);
if (!p) {
fprintf(stderr, "Out of memory");
abort();
}
return p;
}
#ifdef MULTIPLE_THREADS
/* Enable locking to support multi-threaded applications */
#include <pthread.h>
static pthread_mutex_t private_dtoa_lock[2] = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER
};
#define ACQUIRE_DTOA_LOCK(n) do { \
int r = pthread_mutex_lock(&private_dtoa_lock[n]); \
if (r) { \
fprintf(stderr, "pthread_mutex_lock failed with %d\n", r); \
abort(); \
} \
} while (0)
#define FREE_DTOA_LOCK(n) do { \
int r = pthread_mutex_unlock(&private_dtoa_lock[n]); \
if (r) { \
fprintf(stderr, "pthread_mutex_unlock failed with %d\n", r);\
abort(); \
} \
} while (0)
#endif /* MULTIPLE_THREADS */
#endif
#endif /* _DTOA_CONFIG_H */
/* vi:ai et sw=4 ts=4:
*/

View File

@ -1,209 +0,0 @@
/* fpconv - Floating point conversion routines
*
* Copyright (c) 2011-2012 Mark Pulford <mark@kyne.com.au>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries
* with locale support will break when the decimal separator is a comma.
*
* fpconv_* will around these issues with a translation buffer if required.
*/
#include <stdio.h>
#include <stdlib.h>
// #include <assert.h>
#include <string.h>
#include "fpconv.h"
#if 0
/* Lua CJSON assumes the locale is the same for all threads within a
* process and doesn't change after initialisation.
*
* This avoids the need for per thread storage or expensive checks
* for call. */
static char locale_decimal_point = '.';
/* In theory multibyte decimal_points are possible, but
* Lua CJSON only supports UTF-8 and known locales only have
* single byte decimal points ([.,]).
*
* localconv() may not be thread safe (=>crash), and nl_langinfo() is
* not supported on some platforms. Use sprintf() instead - if the
* locale does change, at least Lua CJSON won't crash. */
static void fpconv_update_locale()
{
char buf[8];
sprintf(buf, "%g", 0.5);
/* Failing this test might imply the platform has a buggy dtoa
* implementation or wide characters */
if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) {
NODE_ERR("Error: wide characters found or printf() bug.");
return;
}
locale_decimal_point = buf[1];
}
/* Check for a valid number character: [-+0-9a-yA-Y.]
* Eg: -0.6e+5, infinity, 0xF0.F0pF0
*
* Used to find the probable end of a number. It doesn't matter if
* invalid characters are counted - strtod() will find the valid
* number if it exists. The risk is that slightly more memory might
* be allocated before a parse error occurs. */
static inline int valid_number_character(char ch)
{
char lower_ch;
if ('0' <= ch && ch <= '9')
return 1;
if (ch == '-' || ch == '+' || ch == '.')
return 1;
/* Hex digits, exponent (e), base (p), "infinity",.. */
lower_ch = ch | 0x20;
if ('a' <= lower_ch && lower_ch <= 'y')
return 1;
return 0;
}
/* Calculate the size of the buffer required for a strtod locale
* conversion. */
static int strtod_buffer_size(const char *s)
{
const char *p = s;
while (valid_number_character(*p))
p++;
return p - s;
}
/* Similar to strtod(), but must be passed the current locale's decimal point
* character. Guaranteed to be called at the start of any valid number in a string */
double fpconv_strtod(const char *nptr, char **endptr)
{
char localbuf[FPCONV_G_FMT_BUFSIZE];
char *buf, *endbuf, *dp;
int buflen;
double value;
/* System strtod() is fine when decimal point is '.' */
if (locale_decimal_point == '.')
return c_strtod(nptr, endptr);
buflen = strtod_buffer_size(nptr);
if (!buflen) {
/* No valid characters found, standard strtod() return */
*endptr = (char *)nptr;
return 0;
}
/* Duplicate number into buffer */
if (buflen >= FPCONV_G_FMT_BUFSIZE) {
/* Handle unusually large numbers */
buf = malloc(buflen + 1);
if (!buf) {
NODE_ERR("not enough memory\n");
return;
}
} else {
/* This is the common case.. */
buf = localbuf;
}
memcpy(buf, nptr, buflen);
buf[buflen] = 0;
/* Update decimal point character if found */
dp = strchr(buf, '.');
if (dp)
*dp = locale_decimal_point;
value = c_strtod(buf, &endbuf);
*endptr = (char *)&nptr[endbuf - buf];
if (buflen >= FPCONV_G_FMT_BUFSIZE)
free(buf);
return value;
}
/* "fmt" must point to a buffer of at least 6 characters */
static void set_number_format(char *fmt, int precision)
{
int d1, d2, i;
if(!(1 <= precision && precision <= 14)) return;
/* Create printf format (%.14g) from precision */
d1 = precision / 10;
d2 = precision % 10;
fmt[0] = '%';
fmt[1] = '.';
i = 2;
if (d1) {
fmt[i++] = '0' + d1;
}
fmt[i++] = '0' + d2;
fmt[i++] = 'g';
fmt[i] = 0;
}
/* Assumes there is always at least 32 characters available in the target buffer */
int fpconv_g_fmt(char *str, double num, int precision)
{
char buf[FPCONV_G_FMT_BUFSIZE];
char fmt[6];
int len;
char *b;
set_number_format(fmt, precision);
/* Pass through when decimal point character is dot. */
if (locale_decimal_point == '.'){
sprintf(str, fmt, num);
return strlen(str);
}
/* snprintf() to a buffer then translate for other decimal point characters */
sprintf(buf, fmt, num);
len = strlen(buf);
/* Copy into target location. Translate decimal point if required */
b = buf;
do {
*str++ = (*b == locale_decimal_point ? '.' : *b);
} while(*b++);
return len;
}
void fpconv_init()
{
fpconv_update_locale();
}
#endif
/* vi:ai et sw=4 ts=4:
*/

View File

@ -1,24 +0,0 @@
/* Lua CJSON floating point conversion routines */
/* Buffer required to store the largest string representation of a double.
*
* Longest double printed with %.14g is 21 characters long:
* -1.7976931348623e+308 */
# define FPCONV_G_FMT_BUFSIZE 32
#if 0
#ifdef USE_INTERNAL_FPCONV
static inline void fpconv_init()
{
/* Do nothing - not required */
}
#else
extern inline void fpconv_init();
#endif
#endif
extern int fpconv_g_fmt(char*, double, int);
extern double fpconv_strtod(const char*, char**);
/* vi:ai et sw=4 ts=4:
*/

View File

@ -1,112 +0,0 @@
/****************************************************************
*
* The author of this software is David M. Gay.
*
* Copyright (c) 1991, 1996 by Lucent Technologies.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
*
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*
***************************************************************/
/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
* it suffices to declare buf
* char buf[32];
*/
#if 0
#ifdef __cplusplus
extern "C" {
#endif
extern char *dtoa(double, int, int, int *, int *, char **);
extern int g_fmt(char *, double, int);
extern void freedtoa(char*);
#ifdef __cplusplus
}
#endif
int
fpconv_g_fmt(char *b, double x, int precision)
{
register int i, k;
register char *s;
int decpt, j, sign;
char *b0, *s0, *se;
b0 = b;
#ifdef IGNORE_ZERO_SIGN
if (!x) {
*b++ = '0';
*b = 0;
goto done;
}
#endif
s = s0 = dtoa(x, 2, precision, &decpt, &sign, &se);
if (sign)
*b++ = '-';
if (decpt == 9999) /* Infinity or Nan */ {
while((*b++ = *s++));
/* "b" is used to calculate the return length. Decrement to exclude the
* Null terminator from the length */
b--;
goto done0;
}
if (decpt <= -4 || decpt > precision) {
*b++ = *s++;
if (*s) {
*b++ = '.';
while((*b = *s++))
b++;
}
*b++ = 'e';
/* sprintf(b, "%+.2d", decpt - 1); */
if (--decpt < 0) {
*b++ = '-';
decpt = -decpt;
}
else
*b++ = '+';
for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
for(;;) {
i = decpt / k;
*b++ = i + '0';
if (--j <= 0)
break;
decpt -= i*k;
decpt *= 10;
}
*b = 0;
}
else if (decpt <= 0) {
*b++ = '0';
*b++ = '.';
for(; decpt < 0; decpt++)
*b++ = '0';
while((*b++ = *s++));
b--;
}
else {
while((*b = *s++)) {
b++;
if (--decpt == 0 && *s)
*b++ = '.';
}
for(; decpt > 0; decpt--)
*b++ = '0';
*b = 0;
}
done0:
freedtoa(s0);
#ifdef IGNORE_ZERO_SIGN
done:
#endif
return b - b0;
}
#endif

View File

@ -1,271 +0,0 @@
local json = require "cjson"
-- Various common routines used by the Lua CJSON package
--
-- Mark Pulford <mark@kyne.com.au>
-- Determine with a Lua table can be treated as an array.
-- Explicitly returns "not an array" for very sparse arrays.
-- Returns:
-- -1 Not an array
-- 0 Empty table
-- >0 Highest index in the array
local function is_array(table)
local max = 0
local count = 0
for k, v in pairs(table) do
if type(k) == "number" then
if k > max then max = k end
count = count + 1
else
return -1
end
end
if max > count * 2 then
return -1
end
return max
end
local serialise_value
local function serialise_table(value, indent, depth)
local spacing, spacing2, indent2
if indent then
spacing = "\n" .. indent
spacing2 = spacing .. " "
indent2 = indent .. " "
else
spacing, spacing2, indent2 = " ", " ", false
end
depth = depth + 1
if depth > 50 then
return "Cannot serialise any further: too many nested tables"
end
local max = is_array(value)
local comma = false
local fragment = { "{" .. spacing2 }
if max > 0 then
-- Serialise array
for i = 1, max do
if comma then
table.insert(fragment, "," .. spacing2)
end
table.insert(fragment, serialise_value(value[i], indent2, depth))
comma = true
end
elseif max < 0 then
-- Serialise table
for k, v in pairs(value) do
if comma then
table.insert(fragment, "," .. spacing2)
end
table.insert(fragment,
("[%s] = %s"):format(serialise_value(k, indent2, depth),
serialise_value(v, indent2, depth)))
comma = true
end
end
table.insert(fragment, spacing .. "}")
return table.concat(fragment)
end
function serialise_value(value, indent, depth)
if indent == nil then indent = "" end
if depth == nil then depth = 0 end
if value == json.null then
return "json.null"
elseif type(value) == "string" then
return ("%q"):format(value)
elseif type(value) == "nil" or type(value) == "number" or
type(value) == "boolean" then
return tostring(value)
elseif type(value) == "table" then
return serialise_table(value, indent, depth)
else
return "\"<" .. type(value) .. ">\""
end
end
local function file_load(filename)
local file
if filename == nil then
file = io.stdin
else
local err
file, err = io.open(filename, "rb")
if file == nil then
error(("Unable to read '%s': %s"):format(filename, err))
end
end
local data = file:read("*a")
if filename ~= nil then
file:close()
end
if data == nil then
error("Failed to read " .. filename)
end
return data
end
local function file_save(filename, data)
local file
if filename == nil then
file = io.stdout
else
local err
file, err = io.open(filename, "wb")
if file == nil then
error(("Unable to write '%s': %s"):format(filename, err))
end
end
file:write(data)
if filename ~= nil then
file:close()
end
end
local function compare_values(val1, val2)
local type1 = type(val1)
local type2 = type(val2)
if type1 ~= type2 then
return false
end
-- Check for NaN
if type1 == "number" and val1 ~= val1 and val2 ~= val2 then
return true
end
if type1 ~= "table" then
return val1 == val2
end
-- check_keys stores all the keys that must be checked in val2
local check_keys = {}
for k, _ in pairs(val1) do
check_keys[k] = true
end
for k, v in pairs(val2) do
if not check_keys[k] then
return false
end
if not compare_values(val1[k], val2[k]) then
return false
end
check_keys[k] = nil
end
for k, _ in pairs(check_keys) do
-- Not the same if any keys from val1 were not found in val2
return false
end
return true
end
local test_count_pass = 0
local test_count_total = 0
local function run_test_summary()
return test_count_pass, test_count_total
end
local function run_test(testname, func, input, should_work, output)
local function status_line(name, status, value)
local statusmap = { [true] = ":success", [false] = ":error" }
if status ~= nil then
name = name .. statusmap[status]
end
print(("[%s] %s"):format(name, serialise_value(value, false)))
end
local result = { pcall(func, unpack(input)) }
local success = table.remove(result, 1)
local correct = false
if success == should_work and compare_values(result, output) then
correct = true
test_count_pass = test_count_pass + 1
end
test_count_total = test_count_total + 1
local teststatus = { [true] = "PASS", [false] = "FAIL" }
print(("==> Test [%d] %s: %s"):format(test_count_total, testname,
teststatus[correct]))
status_line("Input", nil, input)
if not correct then
status_line("Expected", should_work, output)
end
status_line("Received", success, result)
print()
return correct, result
end
local function run_test_group(tests)
local function run_helper(name, func, input)
if type(name) == "string" and #name > 0 then
print("==> " .. name)
end
-- Not a protected call, these functions should never generate errors.
func(unpack(input or {}))
print()
end
for _, v in ipairs(tests) do
-- Run the helper if "should_work" is missing
if v[4] == nil then
run_helper(unpack(v))
else
run_test(unpack(v))
end
end
end
-- Run a Lua script in a separate environment
local function run_script(script, env)
local env = env or {}
local func
-- Use setfenv() if it exists, otherwise assume Lua 5.2 load() exists
if _G.setfenv then
func = loadstring(script)
if func then
setfenv(func, env)
end
else
func = load(script, nil, nil, env)
end
if func == nil then
error("Invalid syntax.")
end
func()
return env
end
-- Export functions
return {
serialise_value = serialise_value,
file_load = file_load,
file_save = file_save,
compare_values = compare_values,
run_test_summary = run_test_summary,
run_test = run_test,
run_test_group = run_test_group,
run_script = run_script
}
-- vi:ai et sw=4 ts=4:

View File

@ -1,14 +0,0 @@
#!/usr/bin/env lua
-- usage: json2lua.lua [json_file]
--
-- Eg:
-- echo '[ "testing" ]' | ./json2lua.lua
-- ./json2lua.lua test.json
local json = require "cjson"
local util = require "cjson.util"
local json_text = util.file_load(arg[1])
local t = json.decode(json_text)
print(util.serialise_value(t))

View File

@ -1,20 +0,0 @@
#!/usr/bin/env lua
-- usage: lua2json.lua [lua_file]
--
-- Eg:
-- echo '{ "testing" }' | ./lua2json.lua
-- ./lua2json.lua test.lua
local json = require "cjson"
local util = require "cjson.util"
local env = {
json = { null = json.null },
null = json.null
}
local t = util.run_script("data = " .. util.file_load(arg[1]), env)
print(json.encode(t.data))
-- vi:ai et sw=4 ts=4:

View File

@ -1,168 +0,0 @@
= Lua CJSON 2.1devel Manual =
Mark Pulford <mark@kyne.com.au>
:revdate: 1st March 2012
Overview
--------
The Lua CJSON module provides JSON support for Lua.
*Features*::
- Fast, standards compliant encoding/parsing routines
- Full support for JSON with UTF-8, including decoding surrogate pairs
- Optional run-time support for common exceptions to the JSON
specification (infinity, NaN,..)
- No dependencies on other libraries
*Caveats*::
- UTF-16 and UTF-32 are not supported
Lua CJSON is covered by the MIT license. Review the file +LICENSE+ for
details.
API (Functions)
---------------
Synopsis
~~~~~~~~
[source,lua]
------------
-- Translate Lua value to/from JSON
text = cjson.encode(value)
value = cjson.decode(text)
Module Instantiation
~~~~~~~~~~~~~~~~~~~~
decode
~~~~~~
[source,lua]
------------
value = cjson.decode(json_text)
------------
+cjson.decode+ will deserialise any UTF-8 JSON string into a Lua value
or table.
UTF-16 and UTF-32 JSON strings are not supported.
+cjson.decode+ requires that any NULL (ASCII 0) and double quote (ASCII
34) characters are escaped within strings. All escape codes will be
decoded and other bytes will be passed transparently. UTF-8 characters
are not validated during decoding and should be checked elsewhere if
required.
JSON +null+ will be converted to a NULL +lightuserdata+ value. This can
be compared with +cjson.null+ for convenience.
By default, numbers incompatible with the JSON specification (infinity,
NaN, hexadecimal) can be decoded. This default can be changed with
<<decode_invalid_numbers,+cjson.decode_invalid_numbers+>>.
.Example: Decoding
[source,lua]
json_text = '[ true, { "foo": "bar" } ]'
value = cjson.decode(json_text)
-- Returns: { true, { foo = "bar" } }
[CAUTION]
Care must be taken after decoding JSON objects with numeric keys. Each
numeric key will be stored as a Lua +string+. Any subsequent code
assuming type +number+ may break.
[[encode]]
encode
~~~~~~
[source,lua]
------------
json_text = cjson.encode(value)
------------
+cjson.encode+ will serialise a Lua value into a string containing the
JSON representation.
+cjson.encode+ supports the following types:
- +boolean+
- +lightuserdata+ (NULL value only)
- +nil+
- +number+
- +string+
- +table+
The remaining Lua types will generate an error:
- +function+
- +lightuserdata+ (non-NULL values)
- +thread+
- +userdata+
By default, numbers are encoded with 14 significant digits. Refer to
<<encode_number_precision,+cjson.encode_number_precision+>> for details.
Lua CJSON will escape the following characters within each UTF-8 string:
- Control characters (ASCII 0 - 31)
- Double quote (ASCII 34)
- Forward slash (ASCII 47)
- Blackslash (ASCII 92)
- Delete (ASCII 127)
All other bytes are passed transparently.
[CAUTION]
=========
Lua CJSON will successfully encode/decode binary strings, but this is
technically not supported by JSON and may not be compatible with other
JSON libraries. To ensure the output is valid JSON, applications should
ensure all Lua strings passed to +cjson.encode+ are UTF-8.
Base64 is commonly used to encode binary data as the most efficient
encoding under UTF-8 can only reduce the encoded size by a further
&#126;8%. Lua Base64 routines can be found in the
http://w3.impa.br/%7Ediego/software/luasocket/[LuaSocket] and
http://www.tecgraf.puc-rio.br/%7Elhf/ftp/lua/#lbase64[lbase64] packages.
=========
Lua CJSON uses a heuristic to determine whether to encode a Lua table as
a JSON array or an object. A Lua table with only positive integer keys
of type +number+ will be encoded as a JSON array. All other tables will
be encoded as a JSON object.
Lua CJSON does not use metamethods when serialising tables.
- +rawget+ is used to iterate over Lua arrays
- +next+ is used to iterate over Lua objects
Lua arrays with missing entries (_sparse arrays_) may optionally be
encoded in several different ways. Refer to
<<encode_sparse_array,+cjson.encode_sparse_array+>> for details.
JSON object keys are always strings. Hence +cjson.encode+ only supports
table keys which are type +number+ or +string+. All other types will
generate an error.
[NOTE]
Standards compliant JSON must be encapsulated in either an object (+{}+)
or an array (+[]+). If strictly standards compliant JSON is desired, a
table must be passed to +cjson.encode+.
By default, encoding the following Lua values will generate errors:
- Numbers incompatible with the JSON specification (infinity, NaN)
- Tables nested more than 1000 levels deep
- Excessively sparse Lua arrays
.Example: Encoding
[source,lua]
value = { true, { foo = "bar" } }
json_text = cjson.encode(value)
-- Returns: '[true,{"foo":"bar"}]'
// vi:ft=asciidoc tw=72:

View File

@ -1,563 +0,0 @@
Network Working Group D. Crockford
Request for Comments: 4627 JSON.org
Category: Informational July 2006
The application/json Media Type for JavaScript Object Notation (JSON)
Status of This Memo
This memo provides information for the Internet community. It does
not specify an Internet standard of any kind. Distribution of this
memo is unlimited.
Copyright Notice
Copyright (C) The Internet Society (2006).
Abstract
JavaScript Object Notation (JSON) is a lightweight, text-based,
language-independent data interchange format. It was derived from
the ECMAScript Programming Language Standard. JSON defines a small
set of formatting rules for the portable representation of structured
data.
1. Introduction
JavaScript Object Notation (JSON) is a text format for the
serialization of structured data. It is derived from the object
literals of JavaScript, as defined in the ECMAScript Programming
Language Standard, Third Edition [ECMA].
JSON can represent four primitive types (strings, numbers, booleans,
and null) and two structured types (objects and arrays).
A string is a sequence of zero or more Unicode characters [UNICODE].
An object is an unordered collection of zero or more name/value
pairs, where a name is a string and a value is a string, number,
boolean, null, object, or array.
An array is an ordered sequence of zero or more values.
The terms "object" and "array" come from the conventions of
JavaScript.
JSON's design goals were for it to be minimal, portable, textual, and
a subset of JavaScript.
Crockford Informational [Page 1]
RFC 4627 JSON July 2006
1.1. Conventions Used in This Document
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [RFC2119].
The grammatical rules in this document are to be interpreted as
described in [RFC4234].
2. JSON Grammar
A JSON text is a sequence of tokens. The set of tokens includes six
structural characters, strings, numbers, and three literal names.
A JSON text is a serialized object or array.
JSON-text = object / array
These are the six structural characters:
begin-array = ws %x5B ws ; [ left square bracket
begin-object = ws %x7B ws ; { left curly bracket
end-array = ws %x5D ws ; ] right square bracket
end-object = ws %x7D ws ; } right curly bracket
name-separator = ws %x3A ws ; : colon
value-separator = ws %x2C ws ; , comma
Insignificant whitespace is allowed before or after any of the six
structural characters.
ws = *(
%x20 / ; Space
%x09 / ; Horizontal tab
%x0A / ; Line feed or New line
%x0D ; Carriage return
)
2.1. Values
A JSON value MUST be an object, array, number, or string, or one of
the following three literal names:
false null true
Crockford Informational [Page 2]
RFC 4627 JSON July 2006
The literal names MUST be lowercase. No other literal names are
allowed.
value = false / null / true / object / array / number / string
false = %x66.61.6c.73.65 ; false
null = %x6e.75.6c.6c ; null
true = %x74.72.75.65 ; true
2.2. Objects
An object structure is represented as a pair of curly brackets
surrounding zero or more name/value pairs (or members). A name is a
string. A single colon comes after each name, separating the name
from the value. A single comma separates a value from a following
name. The names within an object SHOULD be unique.
object = begin-object [ member *( value-separator member ) ]
end-object
member = string name-separator value
2.3. Arrays
An array structure is represented as square brackets surrounding zero
or more values (or elements). Elements are separated by commas.
array = begin-array [ value *( value-separator value ) ] end-array
2.4. Numbers
The representation of numbers is similar to that used in most
programming languages. A number contains an integer component that
may be prefixed with an optional minus sign, which may be followed by
a fraction part and/or an exponent part.
Octal and hex forms are not allowed. Leading zeros are not allowed.
A fraction part is a decimal point followed by one or more digits.
An exponent part begins with the letter E in upper or lowercase,
which may be followed by a plus or minus sign. The E and optional
sign are followed by one or more digits.
Numeric values that cannot be represented as sequences of digits
(such as Infinity and NaN) are not permitted.
Crockford Informational [Page 3]
RFC 4627 JSON July 2006
number = [ minus ] int [ frac ] [ exp ]
decimal-point = %x2E ; .
digit1-9 = %x31-39 ; 1-9
e = %x65 / %x45 ; e E
exp = e [ minus / plus ] 1*DIGIT
frac = decimal-point 1*DIGIT
int = zero / ( digit1-9 *DIGIT )
minus = %x2D ; -
plus = %x2B ; +
zero = %x30 ; 0
2.5. Strings
The representation of strings is similar to conventions used in the C
family of programming languages. A string begins and ends with
quotation marks. All Unicode characters may be placed within the
quotation marks except for the characters that must be escaped:
quotation mark, reverse solidus, and the control characters (U+0000
through U+001F).
Any character may be escaped. If the character is in the Basic
Multilingual Plane (U+0000 through U+FFFF), then it may be
represented as a six-character sequence: a reverse solidus, followed
by the lowercase letter u, followed by four hexadecimal digits that
encode the character's code point. The hexadecimal letters A though
F can be upper or lowercase. So, for example, a string containing
only a single reverse solidus character may be represented as
"\u005C".
Alternatively, there are two-character sequence escape
representations of some popular characters. So, for example, a
string containing only a single reverse solidus character may be
represented more compactly as "\\".
To escape an extended character that is not in the Basic Multilingual
Plane, the character is represented as a twelve-character sequence,
encoding the UTF-16 surrogate pair. So, for example, a string
containing only the G clef character (U+1D11E) may be represented as
"\uD834\uDD1E".
Crockford Informational [Page 4]
RFC 4627 JSON July 2006
string = quotation-mark *char quotation-mark
char = unescaped /
escape (
%x22 / ; " quotation mark U+0022
%x5C / ; \ reverse solidus U+005C
%x2F / ; / solidus U+002F
%x62 / ; b backspace U+0008
%x66 / ; f form feed U+000C
%x6E / ; n line feed U+000A
%x72 / ; r carriage return U+000D
%x74 / ; t tab U+0009
%x75 4HEXDIG ) ; uXXXX U+XXXX
escape = %x5C ; \
quotation-mark = %x22 ; "
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
3. Encoding
JSON text SHALL be encoded in Unicode. The default encoding is
UTF-8.
Since the first two characters of a JSON text will always be ASCII
characters [RFC0020], it is possible to determine whether an octet
stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
at the pattern of nulls in the first four octets.
00 00 00 xx UTF-32BE
00 xx 00 xx UTF-16BE
xx 00 00 00 UTF-32LE
xx 00 xx 00 UTF-16LE
xx xx xx xx UTF-8
4. Parsers
A JSON parser transforms a JSON text into another representation. A
JSON parser MUST accept all texts that conform to the JSON grammar.
A JSON parser MAY accept non-JSON forms or extensions.
An implementation may set limits on the size of texts that it
accepts. An implementation may set limits on the maximum depth of
nesting. An implementation may set limits on the range of numbers.
An implementation may set limits on the length and character contents
of strings.
Crockford Informational [Page 5]
RFC 4627 JSON July 2006
5. Generators
A JSON generator produces JSON text. The resulting text MUST
strictly conform to the JSON grammar.
6. IANA Considerations
The MIME media type for JSON text is application/json.
Type name: application
Subtype name: json
Required parameters: n/a
Optional parameters: n/a
Encoding considerations: 8bit if UTF-8; binary if UTF-16 or UTF-32
JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON
is written in UTF-8, JSON is 8bit compatible. When JSON is
written in UTF-16 or UTF-32, the binary content-transfer-encoding
must be used.
Security considerations:
Generally there are security issues with scripting languages. JSON
is a subset of JavaScript, but it is a safe subset that excludes
assignment and invocation.
A JSON text can be safely passed into JavaScript's eval() function
(which compiles and executes a string) if all the characters not
enclosed in strings are in the set of characters that form JSON
tokens. This can be quickly determined in JavaScript with two
regular expressions and calls to the test and replace methods.
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + text + ')');
Interoperability considerations: n/a
Published specification: RFC 4627
Crockford Informational [Page 6]
RFC 4627 JSON July 2006
Applications that use this media type:
JSON has been used to exchange data between applications written
in all of these programming languages: ActionScript, C, C#,
ColdFusion, Common Lisp, E, Erlang, Java, JavaScript, Lua,
Objective CAML, Perl, PHP, Python, Rebol, Ruby, and Scheme.
Additional information:
Magic number(s): n/a
File extension(s): .json
Macintosh file type code(s): TEXT
Person & email address to contact for further information:
Douglas Crockford
douglas@crockford.com
Intended usage: COMMON
Restrictions on usage: none
Author:
Douglas Crockford
douglas@crockford.com
Change controller:
Douglas Crockford
douglas@crockford.com
7. Security Considerations
See Security Considerations in Section 6.
8. Examples
This is a JSON object:
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": "100"
},
"IDs": [116, 943, 234, 38793]
Crockford Informational [Page 7]
RFC 4627 JSON July 2006
}
}
Its Image member is an object whose Thumbnail member is an object
and whose IDs member is an array of numbers.
This is a JSON array containing two objects:
[
{
"precision": "zip",
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
"Zip": "94107",
"Country": "US"
},
{
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
"Zip": "94085",
"Country": "US"
}
]
9. References
9.1. Normative References
[ECMA] European Computer Manufacturers Association, "ECMAScript
Language Specification 3rd Edition", December 1999,
<http://www.ecma-international.org/publications/files/
ecma-st/ECMA-262.pdf>.
[RFC0020] Cerf, V., "ASCII format for network interchange", RFC 20,
October 1969.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC4234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
Specifications: ABNF", RFC 4234, October 2005.
Crockford Informational [Page 8]
RFC 4627 JSON July 2006
[UNICODE] The Unicode Consortium, "The Unicode Standard Version 4.0",
2003, <http://www.unicode.org/versions/Unicode4.1.0/>.
Author's Address
Douglas Crockford
JSON.org
EMail: douglas@crockford.com
Crockford Informational [Page 9]
RFC 4627 JSON July 2006
Full Copyright Statement
Copyright (C) The Internet Society (2006).
This document is subject to the rights, licenses and restrictions
contained in BCP 78, and except as set forth therein, the authors
retain all their rights.
This document and the information contained herein are provided on an
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Intellectual Property
The IETF takes no position regarding the validity or scope of any
Intellectual Property Rights or other rights that might be claimed to
pertain to the implementation or use of the technology described in
this document or the extent to which any license under such rights
might or might not be available; nor does it represent that it has
made any independent effort to identify any such rights. Information
on the procedures with respect to rights in RFC documents can be
found in BCP 78 and BCP 79.
Copies of IPR disclosures made to the IETF Secretariat and any
assurances of licenses to be made available, or the result of an
attempt made to obtain a general license or permission for the use of
such proprietary rights by implementers or users of this
specification can be obtained from the IETF on-line IPR repository at
http://www.ietf.org/ipr.
The IETF invites any interested party to bring to its attention any
copyrights, patents or patent applications, or other proprietary
rights that may cover technology that may be required to implement
this standard. Please address the information to the IETF at
ietf-ipr@ietf.org.
Acknowledgement
Funding for the RFC Editor function is provided by the IETF
Administrative Support Activity (IASA).
Crockford Informational [Page 10]

View File

@ -1,253 +0,0 @@
/* strbuf - String buffer routines
*
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "strbuf.h"
#include "cjson_mem.h"
int strbuf_init(strbuf_t *s, int len)
{
int size;
if (len <= 0)
size = STRBUF_DEFAULT_SIZE;
else
size = len + 1; /* \0 terminator */
s->buf = NULL;
s->size = size;
s->length = 0;
s->increment = STRBUF_DEFAULT_INCREMENT;
s->dynamic = 0;
s->reallocs = 0;
s->debug = 0;
s->buf = (char *)cjson_mem_malloc(size);
if (!s->buf){
NODE_ERR("not enough memory\n");
return -1;
}
strbuf_ensure_null(s);
return 0;
}
strbuf_t *strbuf_new(int len)
{
strbuf_t *s;
s = (strbuf_t *)cjson_mem_malloc(sizeof(strbuf_t));
if (!s){
NODE_ERR("not enough memory\n");
return NULL;
}
strbuf_init(s, len);
/* Dynamic strbuf allocation / deallocation */
s->dynamic = 1;
return s;
}
int strbuf_set_increment(strbuf_t *s, int increment)
{
/* Increment > 0: Linear buffer growth rate
* Increment < -1: Exponential buffer growth rate */
if (increment == 0 || increment == -1){
NODE_ERR("BUG: Invalid string increment");
return -1;
}
s->increment = increment;
return 0;
}
static inline void debug_stats(strbuf_t *s)
{
if (s->debug) {
NODE_ERR("strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
(long)s, s->reallocs, s->length, s->size);
}
}
/* If strbuf_t has not been dynamically allocated, strbuf_free() can
* be called any number of times strbuf_init() */
void strbuf_free(strbuf_t *s)
{
debug_stats(s);
if (s->buf) {
free(s->buf);
s->buf = NULL;
}
if (s->dynamic)
free(s);
}
char *strbuf_free_to_string(strbuf_t *s, int *len)
{
char *buf;
debug_stats(s);
strbuf_ensure_null(s);
buf = s->buf;
if (len)
*len = s->length;
if (s->dynamic)
free(s);
return buf;
}
static int calculate_new_size(strbuf_t *s, int len)
{
int reqsize, newsize;
if (len <= 0){
NODE_ERR("BUG: Invalid strbuf length requested");
return 0;
}
/* Ensure there is room for optional NULL termination */
reqsize = len + 1;
/* If the user has requested to shrink the buffer, do it exactly */
if (s->size > reqsize)
return reqsize;
newsize = s->size;
if (s->increment < 0) {
/* Exponential sizing */
while (newsize < reqsize)
newsize *= -s->increment;
} else {
/* Linear sizing */
newsize = (((reqsize -1) / s->increment) + 1) * s->increment;
}
return newsize;
}
/* Ensure strbuf can handle a string length bytes long (ignoring NULL
* optional termination). */
int strbuf_resize(strbuf_t *s, int len)
{
int newsize;
newsize = calculate_new_size(s, len);
if (s->debug > 1) {
NODE_ERR("strbuf(%lx) resize: %d => %d\n",
(long)s, s->size, newsize);
}
s->buf = (char *)cjson_mem_realloc(s->buf, newsize);
if (!s->buf){
NODE_ERR("not enough memory");
return -1;
}
s->size = newsize;
s->reallocs++;
return 0;
}
void strbuf_append_string(strbuf_t *s, const char *str)
{
int space, i;
space = strbuf_empty_length(s);
for (i = 0; str[i]; i++) {
if (space < 1) {
strbuf_resize(s, s->length + 1);
space = strbuf_empty_length(s);
}
s->buf[s->length] = str[i];
s->length++;
space--;
}
}
#if 0
/* strbuf_append_fmt() should only be used when an upper bound
* is known for the output string. */
void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
{
va_list arg;
int fmt_len;
strbuf_ensure_empty_length(s, len);
va_start(arg, fmt);
fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
va_end(arg);
if (fmt_len < 0)
die("BUG: Unable to convert number"); /* This should never happen.. */
s->length += fmt_len;
}
/* strbuf_append_fmt_retry() can be used when the there is no known
* upper bound for the output string. */
void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
{
va_list arg;
int fmt_len, try;
int empty_len;
/* If the first attempt to append fails, resize the buffer appropriately
* and try again */
for (try = 0; ; try++) {
va_start(arg, fmt);
/* Append the new formatted string */
/* fmt_len is the length of the string required, excluding the
* trailing NULL */
empty_len = strbuf_empty_length(s);
/* Add 1 since there is also space to store the terminating NULL. */
fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
va_end(arg);
if (fmt_len <= empty_len)
break; /* SUCCESS */
if (try > 0)
die("BUG: length of formatted string changed");
strbuf_resize(s, s->length + fmt_len);
}
s->length += fmt_len;
}
#endif
/* vi:ai et sw=4 ts=4:
*/

View File

@ -1,155 +0,0 @@
/* strbuf - String buffer routines
*
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdarg.h>
#include "user_config.h"
/* Size: Total bytes allocated to *buf
* Length: String length, excluding optional NULL terminator.
* Increment: Allocation increments when resizing the string buffer.
* Dynamic: True if created via strbuf_new()
*/
typedef struct {
char *buf;
int size;
int length;
int increment;
int dynamic;
int reallocs;
int debug;
} strbuf_t;
#ifndef STRBUF_DEFAULT_SIZE
#define STRBUF_DEFAULT_SIZE 1023
#endif
#ifndef STRBUF_DEFAULT_INCREMENT
#define STRBUF_DEFAULT_INCREMENT -2
#endif
/* Initialise */
extern strbuf_t *strbuf_new(int len);
extern int strbuf_init(strbuf_t *s, int len);
extern int strbuf_set_increment(strbuf_t *s, int increment);
/* Release */
extern void strbuf_free(strbuf_t *s);
extern char *strbuf_free_to_string(strbuf_t *s, int *len);
/* Management */
extern int strbuf_resize(strbuf_t *s, int len);
static int strbuf_empty_length(strbuf_t *s);
static int strbuf_length(strbuf_t *s);
static char *strbuf_string(strbuf_t *s, int *len);
static void strbuf_ensure_empty_length(strbuf_t *s, int len);
static char *strbuf_empty_ptr(strbuf_t *s);
static void strbuf_extend_length(strbuf_t *s, int len);
/* Update */
extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
extern void strbuf_append_string(strbuf_t *s, const char *str);
static void strbuf_append_char(strbuf_t *s, const char c);
static void strbuf_ensure_null(strbuf_t *s);
/* Reset string for before use */
static inline void strbuf_reset(strbuf_t *s)
{
s->length = 0;
}
static inline int strbuf_allocated(strbuf_t *s)
{
return s->buf != NULL;
}
/* Return bytes remaining in the string buffer
* Ensure there is space for a NULL terminator. */
static inline int strbuf_empty_length(strbuf_t *s)
{
return s->size - s->length - 1;
}
static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
{
if (len > strbuf_empty_length(s))
strbuf_resize(s, s->length + len);
}
static inline char *strbuf_empty_ptr(strbuf_t *s)
{
return s->buf + s->length;
}
static inline void strbuf_extend_length(strbuf_t *s, int len)
{
s->length += len;
}
static inline int strbuf_length(strbuf_t *s)
{
return s->length;
}
static inline void strbuf_append_char(strbuf_t *s, const char c)
{
strbuf_ensure_empty_length(s, 1);
s->buf[s->length++] = c;
}
static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
{
s->buf[s->length++] = c;
}
static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
{
strbuf_ensure_empty_length(s, len);
memcpy(s->buf + s->length, c, len);
s->length += len;
}
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
{
memcpy(s->buf + s->length, c, len);
s->length += len;
}
static inline void strbuf_ensure_null(strbuf_t *s)
{
s->buf[s->length] = 0;
}
static inline char *strbuf_string(strbuf_t *s, int *len)
{
if (len)
*len = s->length;
return s->buf;
}
/* vi:ai et sw=4 ts=4:
*/

View File

@ -1,4 +0,0 @@
These JSON examples were taken from the JSON website
(http://json.org/example.html) and RFC 4627.
Used with permission.

View File

@ -1,131 +0,0 @@
#!/usr/bin/env lua
-- This benchmark script measures wall clock time and should be
-- run on an unloaded system.
--
-- Your Mileage May Vary.
--
-- Mark Pulford <mark@kyne.com.au>
local json_module = os.getenv("JSON_MODULE") or "cjson"
require "socket"
local json = require(json_module)
local util = require "cjson.util"
local function find_func(mod, funcnames)
for _, v in ipairs(funcnames) do
if mod[v] then
return mod[v]
end
end
return nil
end
local json_encode = find_func(json, { "encode", "Encode", "to_string", "stringify", "json" })
local json_decode = find_func(json, { "decode", "Decode", "to_value", "parse" })
local function average(t)
local total = 0
for _, v in ipairs(t) do
total = total + v
end
return total / #t
end
function benchmark(tests, seconds, rep)
local function bench(func, iter)
-- Use socket.gettime() to measure microsecond resolution
-- wall clock time.
local t = socket.gettime()
for i = 1, iter do
func(i)
end
t = socket.gettime() - t
-- Don't trust any results when the run lasted for less than a
-- millisecond - return nil.
if t < 0.001 then
return nil
end
return (iter / t)
end
-- Roughly calculate the number of interations required
-- to obtain a particular time period.
local function calc_iter(func, seconds)
local iter = 1
local rate
-- Warm up the bench function first.
func()
while not rate do
rate = bench(func, iter)
iter = iter * 10
end
return math.ceil(seconds * rate)
end
local test_results = {}
for name, func in pairs(tests) do
-- k(number), v(string)
-- k(string), v(function)
-- k(number), v(function)
if type(func) == "string" then
name = func
func = _G[name]
end
local iter = calc_iter(func, seconds)
local result = {}
for i = 1, rep do
result[i] = bench(func, iter)
end
-- Remove the slowest half (round down) of the result set
table.sort(result)
for i = 1, math.floor(#result / 2) do
table.remove(result, 1)
end
test_results[name] = average(result)
end
return test_results
end
function bench_file(filename)
local data_json = util.file_load(filename)
local data_obj = json_decode(data_json)
local function test_encode()
json_encode(data_obj)
end
local function test_decode()
json_decode(data_json)
end
local tests = {}
if json_encode then tests.encode = test_encode end
if json_decode then tests.decode = test_decode end
return benchmark(tests, 0.1, 5)
end
-- Optionally load any custom configuration required for this module
local success, data = pcall(util.file_load, ("bench-%s.lua"):format(json_module))
if success then
util.run_script(data, _G)
configure(json)
end
for i = 1, #arg do
local results = bench_file(arg[i])
for k, v in pairs(results) do
print(("%s\t%s\t%d"):format(arg[i], k, v))
end
end
-- vi:ai et sw=4 ts=4:

View File

@ -1,22 +0,0 @@
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Mark up Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}

View File

@ -1,11 +0,0 @@
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}

View File

@ -1,26 +0,0 @@
{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

View File

@ -1,88 +0,0 @@
{"web-app": {
"servlet": [
{
"servlet-name": "cofaxCDS",
"servlet-class": "org.cofax.cds.CDSServlet",
"init-param": {
"configGlossary:installationAt": "Philadelphia, PA",
"configGlossary:adminEmail": "ksm@pobox.com",
"configGlossary:poweredBy": "Cofax",
"configGlossary:poweredByIcon": "/images/cofax.gif",
"configGlossary:staticPath": "/content/static",
"templateProcessorClass": "org.cofax.WysiwygTemplate",
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
"templatePath": "templates",
"templateOverridePath": "",
"defaultListTemplate": "listTemplate.htm",
"defaultFileTemplate": "articleTemplate.htm",
"useJSP": false,
"jspListTemplate": "listTemplate.jsp",
"jspFileTemplate": "articleTemplate.jsp",
"cachePackageTagsTrack": 200,
"cachePackageTagsStore": 200,
"cachePackageTagsRefresh": 60,
"cacheTemplatesTrack": 100,
"cacheTemplatesStore": 50,
"cacheTemplatesRefresh": 15,
"cachePagesTrack": 200,
"cachePagesStore": 100,
"cachePagesRefresh": 10,
"cachePagesDirtyRead": 10,
"searchEngineListTemplate": "forSearchEnginesList.htm",
"searchEngineFileTemplate": "forSearchEngines.htm",
"searchEngineRobotsDb": "WEB-INF/robots.db",
"useDataStore": true,
"dataStoreClass": "org.cofax.SqlDataStore",
"redirectionClass": "org.cofax.SqlRedirection",
"dataStoreName": "cofax",
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
"dataStoreUser": "sa",
"dataStorePassword": "dataStoreTestQuery",
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
"dataStoreInitConns": 10,
"dataStoreMaxConns": 100,
"dataStoreConnUsageLimit": 100,
"dataStoreLogLevel": "debug",
"maxUrlLength": 500}},
{
"servlet-name": "cofaxEmail",
"servlet-class": "org.cofax.cds.EmailServlet",
"init-param": {
"mailHost": "mail1",
"mailHostOverride": "mail2"}},
{
"servlet-name": "cofaxAdmin",
"servlet-class": "org.cofax.cds.AdminServlet"},
{
"servlet-name": "fileServlet",
"servlet-class": "org.cofax.cds.FileServlet"},
{
"servlet-name": "cofaxTools",
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
"init-param": {
"templatePath": "toolstemplates/",
"log": 1,
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
"logMaxSize": "",
"dataLog": 1,
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
"dataLogMaxSize": "",
"removePageCache": "/content/admin/remove?cache=pages&id=",
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
"lookInContext": 1,
"adminGroupID": 4,
"betaServer": true}}],
"servlet-mapping": {
"cofaxCDS": "/",
"cofaxEmail": "/cofaxutil/aemail/*",
"cofaxAdmin": "/admin/*",
"fileServlet": "/static/*",
"cofaxTools": "/tools/*"},
"taglib": {
"taglib-uri": "cofax.tld",
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}

View File

@ -1,27 +0,0 @@
{"menu": {
"header": "SVG Viewer",
"items": [
{"id": "Open"},
{"id": "OpenNew", "label": "Open New"},
null,
{"id": "ZoomIn", "label": "Zoom In"},
{"id": "ZoomOut", "label": "Zoom Out"},
{"id": "OriginalView", "label": "Original View"},
null,
{"id": "Quality"},
{"id": "Pause"},
{"id": "Mute"},
null,
{"id": "Find", "label": "Find..."},
{"id": "FindAgain", "label": "Find Again"},
{"id": "Copy"},
{"id": "CopyAgain", "label": "Copy Again"},
{"id": "CopySVG", "label": "Copy SVG"},
{"id": "ViewSVG", "label": "View SVG"},
{"id": "ViewSource", "label": "View Source"},
{"id": "SaveAs", "label": "Save As"},
null,
{"id": "Help"},
{"id": "About", "label": "About Adobe CVG Viewer..."}
]
}}

View File

@ -1,23 +0,0 @@
#!/usr/bin/env perl
# Create test comparison data using a different UTF-8 implementation.
# The generated utf8.dat file must have the following MD5 sum:
# cff03b039d850f370a7362f3313e5268
use strict;
# 0xD800 - 0xDFFF are used to encode supplementary codepoints
# 0x10000 - 0x10FFFF are supplementary codepoints
my (@codepoints) = (0 .. 0xD7FF, 0xE000 .. 0x10FFFF);
my $utf8 = pack("U*", @codepoints);
defined($utf8) or die "Unable create UTF-8 string\n";
open(FH, ">:utf8", "utf8.dat")
or die "Unable to open utf8.dat: $!\n";
print FH $utf8
or die "Unable to write utf8.dat\n";
close(FH);
# vi:ai et sw=4 ts=4:

View File

@ -1,7 +0,0 @@
[ 0.110001,
0.12345678910111,
0.412454033640,
2.6651441426902,
2.718281828459,
3.1415926535898,
2.1406926327793 ]

View File

@ -1 +0,0 @@
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-.\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f<37><66><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"

View File

@ -1,13 +0,0 @@
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": "100"
},
"IDs": [116, 943, 234, 38793]
}
}

View File

@ -1,22 +0,0 @@
[
{
"precision": "zip",
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
"Zip": "94107",
"Country": "US"
},
{
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
"Zip": "94085",
"Country": "US"
}
]

View File

@ -1,425 +0,0 @@
#!/usr/bin/env lua
-- Lua CJSON tests
--
-- Mark Pulford <mark@kyne.com.au>
--
-- Note: The output of this script is easier to read with "less -S"
local json = require "cjson"
local json_safe = require "cjson.safe"
local util = require "cjson.util"
local function gen_raw_octets()
local chars = {}
for i = 0, 255 do chars[i + 1] = string.char(i) end
return table.concat(chars)
end
-- Generate every UTF-16 codepoint, including supplementary codes
local function gen_utf16_escaped()
-- Create raw table escapes
local utf16_escaped = {}
local count = 0
local function append_escape(code)
local esc = ('\\u%04X'):format(code)
table.insert(utf16_escaped, esc)
end
table.insert(utf16_escaped, '"')
for i = 0, 0xD7FF do
append_escape(i)
end
-- Skip 0xD800 - 0xDFFF since they are used to encode supplementary
-- codepoints
for i = 0xE000, 0xFFFF do
append_escape(i)
end
-- Append surrogate pair for each supplementary codepoint
for high = 0xD800, 0xDBFF do
for low = 0xDC00, 0xDFFF do
append_escape(high)
append_escape(low)
end
end
table.insert(utf16_escaped, '"')
return table.concat(utf16_escaped)
end
function load_testdata()
local data = {}
-- Data for 8bit raw <-> escaped octets tests
data.octets_raw = gen_raw_octets()
data.octets_escaped = util.file_load("octets-escaped.dat")
-- Data for \uXXXX -> UTF-8 test
data.utf16_escaped = gen_utf16_escaped()
-- Load matching data for utf16_escaped
local utf8_loaded
utf8_loaded, data.utf8_raw = pcall(util.file_load, "utf8.dat")
if not utf8_loaded then
data.utf8_raw = "Failed to load utf8.dat - please run genutf8.pl"
end
data.table_cycle = {}
data.table_cycle[1] = data.table_cycle
local big = {}
for i = 1, 1100 do
big = { { 10, false, true, json.null }, "string", a = big }
end
data.deeply_nested_data = big
return data
end
function test_decode_cycle(filename)
local obj1 = json.decode(util.file_load(filename))
local obj2 = json.decode(json.encode(obj1))
return util.compare_values(obj1, obj2)
end
-- Set up data used in tests
local Inf = math.huge;
local NaN = math.huge * 0;
local testdata = load_testdata()
local cjson_tests = {
-- Test API variables
{ "Check module name, version",
function () return json._NAME, json._VERSION end, { },
true, { "cjson", "2.1devel" } },
-- Test decoding simple types
{ "Decode string",
json.decode, { '"test string"' }, true, { "test string" } },
{ "Decode numbers",
json.decode, { '[ 0.0, -5e3, -1, 0.3e-3, 1023.2, 0e10 ]' },
true, { { 0.0, -5000, -1, 0.0003, 1023.2, 0 } } },
{ "Decode null",
json.decode, { 'null' }, true, { json.null } },
{ "Decode true",
json.decode, { 'true' }, true, { true } },
{ "Decode false",
json.decode, { 'false' }, true, { false } },
{ "Decode object with numeric keys",
json.decode, { '{ "1": "one", "3": "three" }' },
true, { { ["1"] = "one", ["3"] = "three" } } },
{ "Decode object with string keys",
json.decode, { '{ "a": "a", "b": "b" }' },
true, { { a = "a", b = "b" } } },
{ "Decode array",
json.decode, { '[ "one", null, "three" ]' },
true, { { "one", json.null, "three" } } },
-- Test decoding errors
{ "Decode UTF-16BE [throw error]",
json.decode, { '\0"\0"' },
false, { "JSON parser does not support UTF-16 or UTF-32" } },
{ "Decode UTF-16LE [throw error]",
json.decode, { '"\0"\0' },
false, { "JSON parser does not support UTF-16 or UTF-32" } },
{ "Decode UTF-32BE [throw error]",
json.decode, { '\0\0\0"' },
false, { "JSON parser does not support UTF-16 or UTF-32" } },
{ "Decode UTF-32LE [throw error]",
json.decode, { '"\0\0\0' },
false, { "JSON parser does not support UTF-16 or UTF-32" } },
{ "Decode partial JSON [throw error]",
json.decode, { '{ "unexpected eof": ' },
false, { "Expected value but found T_END at character 21" } },
{ "Decode with extra comma [throw error]",
json.decode, { '{ "extra data": true }, false' },
false, { "Expected the end but found T_COMMA at character 23" } },
{ "Decode invalid escape code [throw error]",
json.decode, { [[ { "bad escape \q code" } ]] },
false, { "Expected object key string but found invalid escape code at character 16" } },
{ "Decode invalid unicode escape [throw error]",
json.decode, { [[ { "bad unicode \u0f6 escape" } ]] },
false, { "Expected object key string but found invalid unicode escape code at character 17" } },
{ "Decode invalid keyword [throw error]",
json.decode, { ' [ "bad barewood", test ] ' },
false, { "Expected value but found invalid token at character 20" } },
{ "Decode invalid number #1 [throw error]",
json.decode, { '[ -+12 ]' },
false, { "Expected value but found invalid number at character 3" } },
{ "Decode invalid number #2 [throw error]",
json.decode, { '-v' },
false, { "Expected value but found invalid number at character 1" } },
{ "Decode invalid number exponent [throw error]",
json.decode, { '[ 0.4eg10 ]' },
false, { "Expected comma or array end but found invalid token at character 6" } },
-- Test decoding nested arrays / objects
{ "Set decode_max_depth(5)",
json.decode_max_depth, { 5 }, true, { 5 } },
{ "Decode array at nested limit",
json.decode, { '[[[[[ "nested" ]]]]]' },
true, { {{{{{ "nested" }}}}} } },
{ "Decode array over nested limit [throw error]",
json.decode, { '[[[[[[ "nested" ]]]]]]' },
false, { "Found too many nested data structures (6) at character 6" } },
{ "Decode object at nested limit",
json.decode, { '{"a":{"b":{"c":{"d":{"e":"nested"}}}}}' },
true, { {a={b={c={d={e="nested"}}}}} } },
{ "Decode object over nested limit [throw error]",
json.decode, { '{"a":{"b":{"c":{"d":{"e":{"f":"nested"}}}}}}' },
false, { "Found too many nested data structures (6) at character 26" } },
{ "Set decode_max_depth(1000)",
json.decode_max_depth, { 1000 }, true, { 1000 } },
{ "Decode deeply nested array [throw error]",
json.decode, { string.rep("[", 1100) .. '1100' .. string.rep("]", 1100)},
false, { "Found too many nested data structures (1001) at character 1001" } },
-- Test encoding nested tables
{ "Set encode_max_depth(5)",
json.encode_max_depth, { 5 }, true, { 5 } },
{ "Encode nested table as array at nested limit",
json.encode, { {{{{{"nested"}}}}} }, true, { '[[[[["nested"]]]]]' } },
{ "Encode nested table as array after nested limit [throw error]",
json.encode, { { {{{{{"nested"}}}}} } },
false, { "Cannot serialise, excessive nesting (6)" } },
{ "Encode nested table as object at nested limit",
json.encode, { {a={b={c={d={e="nested"}}}}} },
true, { '{"a":{"b":{"c":{"d":{"e":"nested"}}}}}' } },
{ "Encode nested table as object over nested limit [throw error]",
json.encode, { {a={b={c={d={e={f="nested"}}}}}} },
false, { "Cannot serialise, excessive nesting (6)" } },
{ "Encode table with cycle [throw error]",
json.encode, { testdata.table_cycle },
false, { "Cannot serialise, excessive nesting (6)" } },
{ "Set encode_max_depth(1000)",
json.encode_max_depth, { 1000 }, true, { 1000 } },
{ "Encode deeply nested data [throw error]",
json.encode, { testdata.deeply_nested_data },
false, { "Cannot serialise, excessive nesting (1001)" } },
-- Test encoding simple types
{ "Encode null",
json.encode, { json.null }, true, { 'null' } },
{ "Encode true",
json.encode, { true }, true, { 'true' } },
{ "Encode false",
json.encode, { false }, true, { 'false' } },
{ "Encode empty object",
json.encode, { { } }, true, { '{}' } },
{ "Encode integer",
json.encode, { 10 }, true, { '10' } },
{ "Encode string",
json.encode, { "hello" }, true, { '"hello"' } },
{ "Encode Lua function [throw error]",
json.encode, { function () end },
false, { "Cannot serialise function: type not supported" } },
-- Test decoding invalid numbers
{ "Set decode_invalid_numbers(true)",
json.decode_invalid_numbers, { true }, true, { true } },
{ "Decode hexadecimal",
json.decode, { '0x6.ffp1' }, true, { 13.9921875 } },
{ "Decode numbers with leading zero",
json.decode, { '[ 0123, 00.33 ]' }, true, { { 123, 0.33 } } },
{ "Decode +-Inf",
json.decode, { '[ +Inf, Inf, -Inf ]' }, true, { { Inf, Inf, -Inf } } },
{ "Decode +-Infinity",
json.decode, { '[ +Infinity, Infinity, -Infinity ]' },
true, { { Inf, Inf, -Inf } } },
{ "Decode +-NaN",
json.decode, { '[ +NaN, NaN, -NaN ]' }, true, { { NaN, NaN, NaN } } },
{ "Decode Infrared (not infinity) [throw error]",
json.decode, { 'Infrared' },
false, { "Expected the end but found invalid token at character 4" } },
{ "Decode Noodle (not NaN) [throw error]",
json.decode, { 'Noodle' },
false, { "Expected value but found invalid token at character 1" } },
{ "Set decode_invalid_numbers(false)",
json.decode_invalid_numbers, { false }, true, { false } },
{ "Decode hexadecimal [throw error]",
json.decode, { '0x6' },
false, { "Expected value but found invalid number at character 1" } },
{ "Decode numbers with leading zero [throw error]",
json.decode, { '[ 0123, 00.33 ]' },
false, { "Expected value but found invalid number at character 3" } },
{ "Decode +-Inf [throw error]",
json.decode, { '[ +Inf, Inf, -Inf ]' },
false, { "Expected value but found invalid token at character 3" } },
{ "Decode +-Infinity [throw error]",
json.decode, { '[ +Infinity, Infinity, -Infinity ]' },
false, { "Expected value but found invalid token at character 3" } },
{ "Decode +-NaN [throw error]",
json.decode, { '[ +NaN, NaN, -NaN ]' },
false, { "Expected value but found invalid token at character 3" } },
{ 'Set decode_invalid_numbers("on")',
json.decode_invalid_numbers, { "on" }, true, { true } },
-- Test encoding invalid numbers
{ "Set encode_invalid_numbers(false)",
json.encode_invalid_numbers, { false }, true, { false } },
{ "Encode NaN [throw error]",
json.encode, { NaN },
false, { "Cannot serialise number: must not be NaN or Infinity" } },
{ "Encode Infinity [throw error]",
json.encode, { Inf },
false, { "Cannot serialise number: must not be NaN or Infinity" } },
{ "Set encode_invalid_numbers(\"null\")",
json.encode_invalid_numbers, { "null" }, true, { "null" } },
{ "Encode NaN as null",
json.encode, { NaN }, true, { "null" } },
{ "Encode Infinity as null",
json.encode, { Inf }, true, { "null" } },
{ "Set encode_invalid_numbers(true)",
json.encode_invalid_numbers, { true }, true, { true } },
{ "Encode NaN",
json.encode, { NaN }, true, { "NaN" } },
{ "Encode +Infinity",
json.encode, { Inf }, true, { "Infinity" } },
{ "Encode -Infinity",
json.encode, { -Inf }, true, { "-Infinity" } },
{ 'Set encode_invalid_numbers("off")',
json.encode_invalid_numbers, { "off" }, true, { false } },
-- Test encoding tables
{ "Set encode_sparse_array(true, 2, 3)",
json.encode_sparse_array, { true, 2, 3 }, true, { true, 2, 3 } },
{ "Encode sparse table as array #1",
json.encode, { { [3] = "sparse test" } },
true, { '[null,null,"sparse test"]' } },
{ "Encode sparse table as array #2",
json.encode, { { [1] = "one", [4] = "sparse test" } },
true, { '["one",null,null,"sparse test"]' } },
{ "Encode sparse array as object",
json.encode, { { [1] = "one", [5] = "sparse test" } },
true, { '{"1":"one","5":"sparse test"}' } },
{ "Encode table with numeric string key as object",
json.encode, { { ["2"] = "numeric string key test" } },
true, { '{"2":"numeric string key test"}' } },
{ "Set encode_sparse_array(false)",
json.encode_sparse_array, { false }, true, { false, 2, 3 } },
{ "Encode table with incompatible key [throw error]",
json.encode, { { [false] = "wrong" } },
false, { "Cannot serialise boolean: table key must be a number or string" } },
-- Test escaping
{ "Encode all octets (8-bit clean)",
json.encode, { testdata.octets_raw }, true, { testdata.octets_escaped } },
{ "Decode all escaped octets",
json.decode, { testdata.octets_escaped }, true, { testdata.octets_raw } },
{ "Decode single UTF-16 escape",
json.decode, { [["\uF800"]] }, true, { "\239\160\128" } },
{ "Decode all UTF-16 escapes (including surrogate combinations)",
json.decode, { testdata.utf16_escaped }, true, { testdata.utf8_raw } },
{ "Decode swapped surrogate pair [throw error]",
json.decode, { [["\uDC00\uD800"]] },
false, { "Expected value but found invalid unicode escape code at character 2" } },
{ "Decode duplicate high surrogate [throw error]",
json.decode, { [["\uDB00\uDB00"]] },
false, { "Expected value but found invalid unicode escape code at character 2" } },
{ "Decode duplicate low surrogate [throw error]",
json.decode, { [["\uDB00\uDB00"]] },
false, { "Expected value but found invalid unicode escape code at character 2" } },
{ "Decode missing low surrogate [throw error]",
json.decode, { [["\uDB00"]] },
false, { "Expected value but found invalid unicode escape code at character 2" } },
{ "Decode invalid low surrogate [throw error]",
json.decode, { [["\uDB00\uD"]] },
false, { "Expected value but found invalid unicode escape code at character 2" } },
-- Test locale support
--
-- The standard Lua interpreter is ANSI C online doesn't support locales
-- by default. Force a known problematic locale to test strtod()/sprintf().
{ "Set locale to cs_CZ (comma separator)", function ()
os.setlocale("cs_CZ")
json.new()
end },
{ "Encode number under comma locale",
json.encode, { 1.5 }, true, { '1.5' } },
{ "Decode number in array under comma locale",
json.decode, { '[ 10, "test" ]' }, true, { { 10, "test" } } },
{ "Revert locale to POSIX", function ()
os.setlocale("C")
json.new()
end },
-- Test encode_keep_buffer() and enable_number_precision()
{ "Set encode_keep_buffer(false)",
json.encode_keep_buffer, { false }, true, { false } },
{ "Set encode_number_precision(3)",
json.encode_number_precision, { 3 }, true, { 3 } },
{ "Encode number with precision 3",
json.encode, { 1/3 }, true, { "0.333" } },
{ "Set encode_number_precision(14)",
json.encode_number_precision, { 14 }, true, { 14 } },
{ "Set encode_keep_buffer(true)",
json.encode_keep_buffer, { true }, true, { true } },
-- Test config API errors
-- Function is listed as '?' due to pcall
{ "Set encode_number_precision(0) [throw error]",
json.encode_number_precision, { 0 },
false, { "bad argument #1 to '?' (expected integer between 1 and 14)" } },
{ "Set encode_number_precision(\"five\") [throw error]",
json.encode_number_precision, { "five" },
false, { "bad argument #1 to '?' (number expected, got string)" } },
{ "Set encode_keep_buffer(nil, true) [throw error]",
json.encode_keep_buffer, { nil, true },
false, { "bad argument #2 to '?' (found too many arguments)" } },
{ "Set encode_max_depth(\"wrong\") [throw error]",
json.encode_max_depth, { "wrong" },
false, { "bad argument #1 to '?' (number expected, got string)" } },
{ "Set decode_max_depth(0) [throw error]",
json.decode_max_depth, { "0" },
false, { "bad argument #1 to '?' (expected integer between 1 and 2147483647)" } },
{ "Set encode_invalid_numbers(-2) [throw error]",
json.encode_invalid_numbers, { -2 },
false, { "bad argument #1 to '?' (invalid option '-2')" } },
{ "Set decode_invalid_numbers(true, false) [throw error]",
json.decode_invalid_numbers, { true, false },
false, { "bad argument #2 to '?' (found too many arguments)" } },
{ "Set encode_sparse_array(\"not quite on\") [throw error]",
json.encode_sparse_array, { "not quite on" },
false, { "bad argument #1 to '?' (invalid option 'not quite on')" } },
{ "Reset Lua CJSON configuration", function () json = json.new() end },
-- Wrap in a function to ensure the table returned by json.new() is used
{ "Check encode_sparse_array()",
function (...) return json.encode_sparse_array(...) end, { },
true, { false, 2, 10 } },
{ "Encode (safe) simple value",
json_safe.encode, { true },
true, { "true" } },
{ "Encode (safe) argument validation [throw error]",
json_safe.encode, { "arg1", "arg2" },
false, { "bad argument #1 to '?' (expected 1 argument)" } },
{ "Decode (safe) error generation",
json_safe.decode, { "Oops" },
true, { nil, "Expected value but found invalid token at character 1" } },
{ "Decode (safe) error generation after new()",
function(...) return json_safe.new().decode(...) end, { "Oops" },
true, { nil, "Expected value but found invalid token at character 1" } },
}
print(("==> Testing Lua CJSON version %s\n"):format(json._VERSION))
util.run_test_group(cjson_tests)
for _, filename in ipairs(arg) do
util.run_test("Decode cycle " .. filename, test_decode_cycle, { filename },
true, { true })
end
local pass, total = util.run_test_summary()
if pass == total then
print("==> Summary: all tests succeeded")
else
print(("==> Summary: %d/%d tests failed"):format(total - pass, total))
os.exit(1)
end
-- vi:ai et sw=4 ts=4:

View File

@ -1 +0,0 @@
{ "array": [ 10, true, null ] }

View File

@ -1,20 +0,0 @@
Copyright (c) 2013 Toby Jaffey <toby@1248.io>
2015 Zeroday Hong <zeroday@nodemcu.com> nodemcu.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,45 +0,0 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = coap.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../libc
INCLUDES += -I ../lua
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -1,556 +0,0 @@
#include "user_config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "coap.h"
#include "uri.h"
extern void endpoint_setup(void);
extern const coap_endpoint_t endpoints[];
#ifdef COAP_DEBUG
void coap_dumpHeader(coap_header_t *hdr)
{
printf("Header:\n");
printf(" ver 0x%02X\n", hdr->ver);
printf(" t 0x%02X\n", hdr->ver);
printf(" tkl 0x%02X\n", hdr->tkl);
printf(" code 0x%02X\n", hdr->code);
printf(" id 0x%02X%02X\n", hdr->id[0], hdr->id[1]);
}
void coap_dump(const uint8_t *buf, size_t buflen, bool bare)
{
if (bare)
{
while(buflen--)
printf("%02X%s", *buf++, (buflen > 0) ? " " : "");
}
else
{
printf("Dump: ");
while(buflen--)
printf("%02X%s", *buf++, (buflen > 0) ? " " : "");
printf("\n");
}
}
#endif
int coap_parseHeader(coap_header_t *hdr, const uint8_t *buf, size_t buflen)
{
if (buflen < 4)
return COAP_ERR_HEADER_TOO_SHORT;
hdr->ver = (buf[0] & 0xC0) >> 6;
if (hdr->ver != 1)
return COAP_ERR_VERSION_NOT_1;
hdr->t = (buf[0] & 0x30) >> 4;
hdr->tkl = buf[0] & 0x0F;
hdr->code = buf[1];
hdr->id[0] = buf[2];
hdr->id[1] = buf[3];
return 0;
}
int coap_buildHeader(const coap_header_t *hdr, uint8_t *buf, size_t buflen)
{
// build header
if (buflen < 4)
return COAP_ERR_BUFFER_TOO_SMALL;
buf[0] = (hdr->ver & 0x03) << 6;
buf[0] |= (hdr->t & 0x03) << 4;
buf[0] |= (hdr->tkl & 0x0F);
buf[1] = hdr->code;
buf[2] = hdr->id[0];
buf[3] = hdr->id[1];
return 4;
}
int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)
{
if (hdr->tkl == 0)
{
tokbuf->p = NULL;
tokbuf->len = 0;
return 0;
}
else
if (hdr->tkl <= 8)
{
if (4U + hdr->tkl > buflen)
return COAP_ERR_TOKEN_TOO_SHORT; // tok bigger than packet
tokbuf->p = buf+4; // past header
tokbuf->len = hdr->tkl;
return 0;
}
else
{
// invalid size
return COAP_ERR_TOKEN_TOO_SHORT;
}
}
int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8_t *buf, size_t buflen)
{
// inject token
uint8_t *p;
if (buflen < (4U + hdr->tkl))
return COAP_ERR_BUFFER_TOO_SMALL;
p = buf + 4;
if ((hdr->tkl > 0) && (hdr->tkl != tokbuf->len))
return COAP_ERR_UNSUPPORTED;
if (hdr->tkl > 0)
memcpy(p, tokbuf->p, hdr->tkl);
// http://tools.ietf.org/html/rfc7252#section-3.1
// inject options
return hdr->tkl;
}
// advances p
int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen)
{
const uint8_t *p = *buf;
uint8_t headlen = 1;
uint16_t len, delta;
if (buflen < headlen) // too small
return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
delta = (p[0] & 0xF0) >> 4;
len = p[0] & 0x0F;
// These are untested and may be buggy
if (delta == 13)
{
headlen++;
if (buflen < headlen)
return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
delta = p[1] + 13;
p++;
}
else
if (delta == 14)
{
headlen += 2;
if (buflen < headlen)
return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
delta = ((p[1] << 8) | p[2]) + 269;
p+=2;
}
else
if (delta == 15)
return COAP_ERR_OPTION_DELTA_INVALID;
if (len == 13)
{
headlen++;
if (buflen < headlen)
return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
len = p[1] + 13;
p++;
}
else
if (len == 14)
{
headlen += 2;
if (buflen < headlen)
return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
len = ((p[1] << 8) | p[2]) + 269;
p+=2;
}
else
if (len == 15)
return COAP_ERR_OPTION_LEN_INVALID;
if ((p + 1 + len) > (*buf + buflen))
return COAP_ERR_OPTION_TOO_BIG;
//printf("option num=%d\n", delta + *running_delta);
option->num = delta + *running_delta;
option->buf.p = p+1;
option->buf.len = len;
//coap_dump(p+1, len, false);
// advance buf
*buf = p + 1 + len;
*running_delta += delta;
return 0;
}
// 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)
{
size_t optionIndex = 0;
uint16_t delta = 0;
const uint8_t *p = buf + 4 + hdr->tkl;
const uint8_t *end = buf + buflen;
int rc;
if (p > end)
return COAP_ERR_OPTION_OVERRUNS_PACKET; // out of bounds
//coap_dump(p, end - p);
// 0xFF is payload marker
while((optionIndex < *numOptions) && (p < end) && (*p != 0xFF))
{
if (0 != (rc = coap_parseOption(&options[optionIndex], &delta, &p, end-p)))
return rc;
optionIndex++;
}
*numOptions = optionIndex;
if (p+1 < end && *p == 0xFF) // payload marker
{
payload->p = p+1;
payload->len = end-(p+1);
}
else
{
payload->p = NULL;
payload->len = 0;
}
return 0;
}
int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen)
{
int n = 0;
uint8_t *p = buf;
uint8_t len, delta = 0;
if (buflen < 5)
return COAP_ERR_BUFFER_TOO_SMALL;
coap_option_nibble(optDelta, &delta);
coap_option_nibble(length, &len);
*p++ = (0xFF & (delta << 4 | len));
n++;
if (delta == 13)
{
*p++ = (optDelta - 13);
n++;
}
else
if (delta == 14)
{
*p++ = ((optDelta-269) >> 8);
*p++ = (0xFF & (optDelta-269));
n+=2;
}
if (len == 13)
{
*p++ = (length - 13);
n++;
}
else
if (len == 14)
{
*p++ = (length >> 8);
*p++ = (0xFF & (length-269));
n+=2;
}
return n;
}
#ifdef COAP_DEBUG
void coap_dumpOptions(coap_option_t *opts, size_t numopt)
{
size_t i;
printf(" Options:\n");
for (i=0;i<numopt;i++)
{
printf(" 0x%02X [ ", opts[i].num);
coap_dump(opts[i].buf.p, opts[i].buf.len, true);
printf(" ]\n");
}
}
void coap_dumpPacket(coap_packet_t *pkt)
{
coap_dumpHeader(&pkt->hdr);
coap_dumpOptions(pkt->opts, pkt->numopts);
printf("Payload: ");
coap_dump(pkt->payload.p, pkt->payload.len, true);
printf("\n");
}
#endif
int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen)
{
int rc;
// coap_dump(buf, buflen, false);
if (0 != (rc = coap_parseHeader(&pkt->hdr, buf, buflen)))
return rc;
// coap_dumpHeader(&hdr);
if (0 != (rc = coap_parseToken(&pkt->tok, &pkt->hdr, buf, buflen)))
return rc;
pkt->numopts = MAXOPT;
if (0 != (rc = coap_parseOptionsAndPayload(pkt->opts, &(pkt->numopts), &(pkt->payload), &pkt->hdr, buf, buflen)))
return rc;
// coap_dumpOptions(opts, numopt);
return 0;
}
// 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)
{
// FIXME, options is always sorted, can find faster than this
size_t i;
const coap_option_t *first = NULL;
*count = 0;
for (i=0;i<pkt->numopts;i++)
{
if (pkt->opts[i].num == num)
{
if (NULL == first)
first = &pkt->opts[i];
(*count)++;
}
else
{
if (NULL != first)
break;
}
}
return first;
}
int coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf)
{
if (buf->len+1 > strbuflen)
return COAP_ERR_BUFFER_TOO_SMALL;
memcpy(strbuf, buf->p, buf->len);
strbuf[buf->len] = 0;
return 0;
}
int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)
{
size_t opts_len = 0, hdr_len = 0, tok_len = 0;
size_t i;
uint8_t *p = buf;
size_t left = *buflen;
uint16_t running_delta = 0;
hdr_len = coap_buildHeader(&(pkt->hdr), buf, *buflen);
p += hdr_len;
left -= hdr_len;
tok_len = coap_buildToken(&(pkt->tok), &(pkt->hdr), buf, *buflen);
p += tok_len;
left -= tok_len;
for (i=0;i<pkt->numopts;i++)
{
uint8_t len, delta = 0;
uint16_t optDelta = 0;
int rc = 0;
if (((size_t)(p-buf)) > *buflen)
return COAP_ERR_BUFFER_TOO_SMALL;
optDelta = pkt->opts[i].num - running_delta;
rc = coap_buildOptionHeader(optDelta, pkt->opts[i].buf.len, p, left);
p += rc;
left -= rc;
memcpy(p, pkt->opts[i].buf.p, pkt->opts[i].buf.len);
p += pkt->opts[i].buf.len;
left -= pkt->opts[i].buf.len;
running_delta = pkt->opts[i].num;
}
opts_len = (p - buf) - 4; // number of bytes used by options
if (pkt->payload.len > 0)
{
if (*buflen < 4 + 1 + pkt->payload.len + opts_len)
return COAP_ERR_BUFFER_TOO_SMALL;
buf[4 + opts_len] = 0xFF; // payload marker
memcpy(buf+5 + opts_len, pkt->payload.p, pkt->payload.len);
*buflen = opts_len + 5 + pkt->payload.len;
}
else
*buflen = opts_len + 4;
return 0;
}
void coap_option_nibble(uint32_t value, uint8_t *nibble)
{
if (value<13)
{
*nibble = (0xFF & value);
}
else
if (value<=0xFF+13)
{
*nibble = 13;
} else if (value<=0xFFFF+269)
{
*nibble = 14;
}
}
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)
{
pkt->hdr.ver = 0x01;
pkt->hdr.t = COAP_TYPE_ACK;
pkt->hdr.tkl = 0;
pkt->hdr.code = rspcode;
pkt->hdr.id[0] = msgid_hi;
pkt->hdr.id[1] = msgid_lo;
pkt->numopts = 1;
// need token in response
if (tok) {
pkt->hdr.tkl = tok->len;
pkt->tok = *tok;
}
// safe because 1 < MAXOPT
pkt->opts[0].num = COAP_OPTION_CONTENT_FORMAT;
pkt->opts[0].buf.p = scratch->p;
if (scratch->len < 2)
return COAP_ERR_BUFFER_TOO_SMALL;
scratch->p[0] = ((uint16_t)content_type & 0xFF00) >> 8;
scratch->p[1] = ((uint16_t)content_type & 0x00FF);
pkt->opts[0].buf.len = 2;
pkt->payload.p = content;
pkt->payload.len = content_len;
return 0;
}
unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val) {
unsigned int n, i;
for (n = 0, i = val; i && n < sizeof(val); ++n)
i >>= 8;
i = n;
while (i--) {
buf[i] = val & 0xff;
val >>= 8;
}
return n;
}
static uint8_t _token_data[4] = {'n','o','d','e'};
coap_buffer_t the_token = { _token_data, 4 };
static unsigned short message_id;
int coap_make_request(coap_rw_buffer_t *scratch, coap_packet_t *pkt, coap_msgtype_t t, coap_method_t m, coap_uri_t *uri, const uint8_t *payload, size_t payload_len)
{
int res;
pkt->hdr.ver = 0x01;
pkt->hdr.t = t;
pkt->hdr.tkl = 0;
pkt->hdr.code = m;
pkt->hdr.id[0] = (message_id >> 8) & 0xFF; //msgid_hi;
pkt->hdr.id[1] = message_id & 0xFF; //msgid_lo;
message_id++;
NODE_DBG("message_id: %d.\n", message_id);
pkt->numopts = 0;
if (the_token.len) {
pkt->hdr.tkl = the_token.len;
pkt->tok = the_token;
}
if (scratch->len < 2) // TBD...
return COAP_ERR_BUFFER_TOO_SMALL;
uint8_t *saved = scratch->p;
/* split arg into Uri-* options */
// const char *addr = uri->host.s;
// if(uri->host.length && (strlen(addr) != uri->host.length || memcmp(addr, uri->host.s, uri->host.length) != 0)){
if(uri->host.length){
/* add Uri-Host */
// addr is destination address
pkt->opts[pkt->numopts].num = COAP_OPTION_URI_HOST;
pkt->opts[pkt->numopts].buf.p = uri->host.s;
pkt->opts[pkt->numopts].buf.len = uri->host.length;
pkt->numopts++;
}
if (uri->port != COAP_DEFAULT_PORT) {
pkt->opts[pkt->numopts].num = COAP_OPTION_URI_PORT;
res = coap_encode_var_bytes(scratch->p, uri->port);
pkt->opts[pkt->numopts].buf.len = res;
pkt->opts[pkt->numopts].buf.p = scratch->p;
scratch->p += res;
scratch->len -= res;
pkt->numopts++;
}
if (uri->path.length) {
res = coap_split_path(scratch, pkt, uri->path.s, uri->path.length);
}
if (uri->query.length) {
res = coap_split_query(scratch, pkt, uri->query.s, uri->query.length);
}
pkt->payload.p = payload;
pkt->payload.len = payload_len;
scratch->p = saved; // save back the pointer.
return 0;
}
// FIXME, if this looked in the table at the path before the method then
// it could more easily return 405 errors
int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt)
{
const coap_option_t *opt;
int i;
uint8_t count;
const coap_endpoint_t *ep = endpoints;
while(NULL != ep->handler)
{
if (ep->method != inpkt->hdr.code)
goto next;
if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))
{
// if (count != ep->path->count)
if ((count != ep->path->count ) && (count != ep->path->count + 1)) // +1 for /f/[function], /v/[variable]
goto next;
for (i=0;i<ep->path->count;i++)
{
if (opt[i].buf.len != strlen(ep->path->elems[i]))
goto next;
if (0 != memcmp(ep->path->elems[i], opt[i].buf.p, opt[i].buf.len))
goto next;
}
// pre-path match!
if (count==ep->path->count+1 && ep->user_entry == NULL)
goto next;
return ep->handler(ep, scratch, inpkt, outpkt, inpkt->hdr.id[0], inpkt->hdr.id[1]);
}
next:
ep++;
}
coap_make_response(scratch, outpkt, NULL, 0, inpkt->hdr.id[0], inpkt->hdr.id[1], &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
return 0;
}
void coap_setup(void)
{
message_id = (unsigned short)rand(); // calculate only once
}
inline int
check_token(coap_packet_t *pkt) {
return pkt->tok.len == the_token.len && memcmp(pkt->tok.p, the_token.p, the_token.len) == 0;
}

View File

@ -1,205 +0,0 @@
#ifndef COAP_H
#define COAP_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include "lualib.h"
#include "lauxlib.h"
#define MAXOPT 16
#define MAX_MESSAGE_SIZE 1152
#define MAX_PAYLOAD_SIZE 1024
#define MAX_REQUEST_SIZE 576
#define MAX_REQ_SCRATCH_SIZE 60
#define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF)
//http://tools.ietf.org/html/rfc7252#section-3
typedef struct
{
uint8_t ver; /* CoAP version number */
uint8_t t; /* CoAP Message Type */
uint8_t tkl; /* Token length: indicates length of the Token field */
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];
} coap_header_t;
typedef struct
{
const uint8_t *p;
size_t len;
} coap_buffer_t;
typedef struct
{
uint8_t *p;
size_t len;
} coap_rw_buffer_t;
typedef struct
{
uint8_t num; /* Option number. See http://tools.ietf.org/html/rfc7252#section-5.10 */
coap_buffer_t buf; /* Option value */
} coap_option_t;
typedef struct
{
coap_header_t hdr; /* Header of the packet */
coap_buffer_t tok; /* Token value, size as specified by hdr.tkl */
uint8_t numopts; /* Number of options */
coap_option_t opts[MAXOPT]; /* Options of the packet. For possible entries see
* http://tools.ietf.org/html/rfc7252#section-5.10 */
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;
/////////////////////////////////////////
//http://tools.ietf.org/html/rfc7252#section-12.2
typedef enum
{
COAP_OPTION_IF_MATCH = 1,
COAP_OPTION_URI_HOST = 3,
COAP_OPTION_ETAG = 4,
COAP_OPTION_IF_NONE_MATCH = 5,
COAP_OPTION_OBSERVE = 6,
COAP_OPTION_URI_PORT = 7,
COAP_OPTION_LOCATION_PATH = 8,
COAP_OPTION_URI_PATH = 11,
COAP_OPTION_CONTENT_FORMAT = 12,
COAP_OPTION_MAX_AGE = 14,
COAP_OPTION_URI_QUERY = 15,
COAP_OPTION_ACCEPT = 17,
COAP_OPTION_LOCATION_QUERY = 20,
COAP_OPTION_PROXY_URI = 35,
COAP_OPTION_PROXY_SCHEME = 39
} coap_option_num_t;
//http://tools.ietf.org/html/rfc7252#section-12.1.1
typedef enum
{
COAP_METHOD_GET = 1,
COAP_METHOD_POST = 2,
COAP_METHOD_PUT = 3,
COAP_METHOD_DELETE = 4
} coap_method_t;
//http://tools.ietf.org/html/rfc7252#section-12.1.1
typedef enum
{
COAP_TYPE_CON = 0,
COAP_TYPE_NONCON = 1,
COAP_TYPE_ACK = 2,
COAP_TYPE_RESET = 3
} coap_msgtype_t;
//http://tools.ietf.org/html/rfc7252#section-5.2
//http://tools.ietf.org/html/rfc7252#section-12.1.2
#define MAKE_RSPCODE(clas, det) ((clas << 5) | (det))
typedef enum
{
COAP_RSPCODE_CONTENT = MAKE_RSPCODE(2, 5),
COAP_RSPCODE_NOT_FOUND = MAKE_RSPCODE(4, 4),
COAP_RSPCODE_BAD_REQUEST = MAKE_RSPCODE(4, 0),
COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4)
} coap_responsecode_t;
//http://tools.ietf.org/html/rfc7252#section-12.3
typedef enum
{
COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block
COAP_CONTENTTYPE_TEXT_PLAIN = 0,
COAP_CONTENTTYPE_APPLICATION_LINKFORMAT = 40,
COAP_CONTENTTYPE_APPLICATION_XML = 41,
COAP_CONTENTTYPE_APPLICATION_OCTET_STREAM = 42,
COAP_CONTENTTYPE_APPLICATION_EXI = 47,
COAP_CONTENTTYPE_APPLICATION_JSON = 50,
} coap_content_type_t;
///////////////////////
typedef enum
{
COAP_ERR_NONE = 0,
COAP_ERR_HEADER_TOO_SHORT = 1,
COAP_ERR_VERSION_NOT_1 = 2,
COAP_ERR_TOKEN_TOO_SHORT = 3,
COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER = 4,
COAP_ERR_OPTION_TOO_SHORT = 5,
COAP_ERR_OPTION_OVERRUNS_PACKET = 6,
COAP_ERR_OPTION_TOO_BIG = 7,
COAP_ERR_OPTION_LEN_INVALID = 8,
COAP_ERR_BUFFER_TOO_SMALL = 9,
COAP_ERR_UNSUPPORTED = 10,
COAP_ERR_OPTION_DELTA_INVALID = 11,
} coap_error_t;
///////////////////////
typedef struct coap_endpoint_t coap_endpoint_t;
typedef int (*coap_endpoint_func)(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);
#define MAX_SEGMENTS 3 // 2 = /foo/bar, 3 = /foo/bar/baz
#define MAX_SEGMENTS_SIZE 16
typedef struct
{
int count;
const char *elems[MAX_SEGMENTS];
} coap_endpoint_path_t;
typedef struct coap_luser_entry coap_luser_entry;
struct coap_luser_entry{
lua_State *L;
// int ref;
// char name[MAX_SEGMENTS_SIZE+1]; // +1 for string '\0'
const char *name;
coap_luser_entry *next;
int content_type;
};
struct coap_endpoint_t{
coap_method_t method; /* (i.e. POST, PUT or GET) */
coap_endpoint_func handler; /* callback function which handles this
* type of endpoint (and calls
* coap_make_response() at some point) */
const coap_endpoint_path_t *path; /* path towards a resource (i.e. foo/bar/) */
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);
int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen);
int coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf);
const coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count);
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);
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);
void coap_option_nibble(uint32_t value, uint8_t *nibble);
void coap_setup(void);
void endpoint_setup(void);
int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen);
int check_token(coap_packet_t *pkt);
#include "uri.h"
int coap_make_request(coap_rw_buffer_t *scratch, coap_packet_t *pkt, coap_msgtype_t t, coap_method_t m, coap_uri_t *uri, const uint8_t *payload, size_t payload_len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,70 +0,0 @@
#include "user_config.h"
#include "c_types.h"
#include "coap.h"
#include "coap_timer.h"
#include "hash.h"
#include "node.h"
extern coap_queue_t *gQueue;
void coap_client_response_handler(char *data, unsigned short len, unsigned short size, const uint32_t ip, const uint32_t port)
{
NODE_DBG("coap_client_response_handler is called.\n");
coap_packet_t pkt;
pkt.content.p = NULL;
pkt.content.len = 0;
int rc;
if (0 != (rc = coap_parse(&pkt, data, len))){
NODE_DBG("Bad packet rc=%d\n", rc);
}
else
{
#ifdef COAP_DEBUG
coap_dumpPacket(&pkt);
#endif
/* check if this is a response to our original request */
if (!check_token(&pkt)) {
/* drop if this was just some message, or send RST in case of notification */
if (pkt.hdr.t == COAP_TYPE_CON || pkt.hdr.t == COAP_TYPE_NONCON){
// coap_send_rst(pkt); // send RST response
// or, just ignore it.
}
goto end;
}
if (pkt.hdr.t == COAP_TYPE_RESET) {
NODE_DBG("got RST\n");
goto end;
}
coap_tid_t id = COAP_INVALID_TID;
coap_transaction_id(ip, port, &pkt, &id);
/* transaction done, remove the node from queue */
// stop timer
coap_timer_stop();
// remove the node
coap_remove_node(&gQueue, id);
// calculate time elapsed
coap_timer_update(&gQueue);
coap_timer_start(&gQueue);
if (COAP_RESPONSE_CLASS(pkt.hdr.code) == 2)
{
/* There is no block option set, just read the data and we are done. */
NODE_DBG("%d.%02d\t", (pkt.hdr.code >> 5), pkt.hdr.code & 0x1F);
NODE_DBG((char *)(pkt.payload.p));
}
else if (COAP_RESPONSE_CLASS(pkt.hdr.code) >= 4)
{
NODE_DBG("%d.%02d\t", (pkt.hdr.code >> 5), pkt.hdr.code & 0x1F);
NODE_DBG((char *)(pkt.payload.p));
}
}
end:
if(!gQueue){ // if there is no node pending in the queue, disconnect from host.
}
}

View File

@ -1,14 +0,0 @@
#ifndef _COAP_CLIENT_H
#define _COAP_CLIENT_H 1
#ifdef __cplusplus
extern "C" {
#endif
void coap_client_response_handler(char *data, unsigned short len, unsigned short size, const uint32_t ip, const uint32_t port);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,76 +0,0 @@
// No espconn on ESP32
#ifdef __ESP8266__
#include <string.h>
#include "coap_io.h"
#include "node.h"
#include "espconn.h"
#include "coap_timer.h"
extern coap_queue_t *gQueue;
/* releases space allocated by PDU if free_pdu is set */
coap_tid_t coap_send(struct espconn *pesp_conn, coap_pdu_t *pdu) {
coap_tid_t id = COAP_INVALID_TID;
uint32_t ip = 0, port = 0;
if ( !pesp_conn || !pdu )
return id;
espconn_sent(pesp_conn, (unsigned char *)(pdu->msg.p), pdu->msg.len);
if(pesp_conn->type == ESPCONN_TCP){
memcpy(&ip, pesp_conn->proto.tcp->remote_ip, sizeof(ip));
port = pesp_conn->proto.tcp->remote_port;
}else{
memcpy(&ip, pesp_conn->proto.udp->remote_ip, sizeof(ip));
port = pesp_conn->proto.udp->remote_port;
}
coap_transaction_id(ip, port, pdu->pkt, &id);
return id;
}
coap_tid_t coap_send_confirmed(struct espconn *pesp_conn, coap_pdu_t *pdu) {
coap_queue_t *node;
coap_tick_t diff;
uint32_t r;
node = coap_new_node();
if (!node) {
NODE_DBG("coap_send_confirmed: insufficient memory\n");
return COAP_INVALID_TID;
}
node->retransmit_cnt = 0;
node->id = coap_send(pesp_conn, pdu);
if (COAP_INVALID_TID == node->id) {
NODE_DBG("coap_send_confirmed: error sending pdu\n");
coap_free_node(node);
return COAP_INVALID_TID;
}
r = rand();
/* add randomized RESPONSE_TIMEOUT to determine retransmission timeout */
node->timeout = COAP_DEFAULT_RESPONSE_TIMEOUT * COAP_TICKS_PER_SECOND +
(COAP_DEFAULT_RESPONSE_TIMEOUT >> 1) *
((COAP_TICKS_PER_SECOND * (r & 0xFF)) >> 8);
node->pconn = pesp_conn;
node->pdu = pdu;
/* Set timer for pdu retransmission. If this is the first element in
* the retransmission queue, the base time is set to the current
* time and the retransmission time is node->timeout. If there is
* already an entry in the sendqueue, we must check if this node is
* to be retransmitted earlier. Therefore, node->timeout is first
* normalized to the timeout and then inserted into the queue with
* an adjusted relative time.
*/
coap_timer_stop();
coap_timer_update(&gQueue);
node->t = node->timeout;
coap_insert_node(&gQueue, node);
coap_timer_start(&gQueue);
return node->id;
}
#endif

View File

@ -1,22 +0,0 @@
#ifndef _COAP_IO_H
#define _COAP_IO_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "c_types.h"
#include "lwip/ip_addr.h"
#include "espconn.h"
#include "pdu.h"
#include "hash.h"
coap_tid_t coap_send(struct espconn *pesp_conn, coap_pdu_t *pdu);
coap_tid_t coap_send_confirmed(struct espconn *pesp_conn, coap_pdu_t *pdu);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,60 +0,0 @@
#include "user_config.h"
#include <ctype.h>
#include <stdlib.h>
#include "coap.h"
size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned short rsplen)
{
NODE_DBG("coap_server_respond is called.\n");
size_t rlen = rsplen;
coap_packet_t pkt;
pkt.content.p = NULL;
pkt.content.len = 0;
uint8_t scratch_raw[4];
coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};
int rc;
#ifdef COAP_DEBUG
NODE_DBG("Received: ");
coap_dump(req, reqlen, true);
NODE_DBG("\n");
#endif
if (0 != (rc = coap_parse(&pkt, req, reqlen))){
NODE_DBG("Bad packet rc=%d\n", rc);
return 0;
}
else
{
coap_packet_t rsppkt;
rsppkt.content.p = NULL;
rsppkt.content.len = 0;
#ifdef COAP_DEBUG
coap_dumpPacket(&pkt);
#endif
coap_handle_req(&scratch_buf, &pkt, &rsppkt);
if (0 != (rc = coap_build(rsp, &rlen, &rsppkt))){
NODE_DBG("coap_build failed rc=%d\n", rc);
// return 0;
rlen = 0;
}
else
{
#ifdef COAP_DEBUG
NODE_DBG("Responding: ");
coap_dump(rsp, rlen, true);
NODE_DBG("\n");
#endif
#ifdef COAP_DEBUG
coap_dumpPacket(&rsppkt);
#endif
}
if(rsppkt.content.p){
free(rsppkt.content.p);
rsppkt.content.p = NULL;
rsppkt.content.len = 0;
}
return rlen;
}
}

View File

@ -1,14 +0,0 @@
#ifndef _COAP_SERVER_H
#define _COAP_SERVER_H 1
#ifdef __cplusplus
extern "C" {
#endif
size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned short rsplen);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,83 +0,0 @@
// No espconn on ESP32
#ifdef __ESP8266__
#include "node.h"
#include "coap_timer.h"
#include "coap_io.h"
#include "esp_timer.h"
#include "esp_system.h"
static os_timer_t coap_timer;
static coap_tick_t basetime = 0;
void coap_timer_elapsed(coap_tick_t *diff){
coap_tick_t now = system_get_time() / 1000; // coap_tick_t is in ms. also sys_timer
if(now>=basetime){
*diff = now-basetime;
} else {
*diff = now + SYS_TIME_MAX -basetime;
}
basetime = now;
}
void coap_timer_tick(void *arg){
if( !arg )
return;
coap_queue_t **queue = (coap_queue_t **)arg;
if( !(*queue) )
return;
coap_queue_t *node = coap_pop_next( queue );
/* re-initialize timeout when maximum number of retransmissions are not reached yet */
if (node->retransmit_cnt < COAP_DEFAULT_MAX_RETRANSMIT) {
node->retransmit_cnt++;
node->t = node->timeout << node->retransmit_cnt;
NODE_DBG("** retransmission #%d of transaction %d\n",
node->retransmit_cnt, (((uint16_t)(node->pdu->pkt->hdr.id[0]))<<8)+node->pdu->pkt->hdr.id[1]);
node->id = coap_send(node->pconn, node->pdu);
if (COAP_INVALID_TID == node->id) {
NODE_DBG("retransmission: error sending pdu\n");
coap_delete_node(node);
} else {
coap_insert_node(queue, node);
}
} else {
/* And finally delete the node */
coap_delete_node( node );
}
coap_timer_start(queue);
}
void coap_timer_setup(coap_queue_t ** queue, coap_tick_t t){
os_timer_disarm(&coap_timer);
os_timer_setfn(&coap_timer, (os_timer_func_t *)coap_timer_tick, queue);
os_timer_arm(&coap_timer, t, 0); // no repeat
}
void coap_timer_stop(void){
os_timer_disarm(&coap_timer);
}
void coap_timer_update(coap_queue_t ** queue){
if (!queue)
return;
coap_tick_t diff = 0;
coap_queue_t *first = *queue;
coap_timer_elapsed(&diff); // update: basetime = now, diff = now - oldbase, means time elapsed
if (first) {
// diff ms time is elapsed, re-calculate the first node->t
if (first->t >= diff){
first->t -= diff;
} else {
first->t = 0; // when timer enabled, time out almost immediately
}
}
}
void coap_timer_start(coap_queue_t ** queue){
if(*queue){ // if there is node in the queue, set timeout to its ->t.
coap_timer_setup(queue, (*queue)->t);
}
}
#endif

View File

@ -1,31 +0,0 @@
#ifndef _COAP_TIMER_H
#define _COAP_TIMER_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "node.h"
#define SYS_TIME_MAX (0xFFFFFFFF / 1000)
#define COAP_DEFAULT_RESPONSE_TIMEOUT 2 /* response timeout in seconds */
#define COAP_DEFAULT_MAX_RETRANSMIT 4 /* max number of retransmissions */
#define COAP_TICKS_PER_SECOND 1000 // ms
#define DEFAULT_MAX_TRANSMIT_WAIT 90
void coap_timer_elapsed(coap_tick_t *diff);
void coap_timer_setup(coap_queue_t ** queue, coap_tick_t t);
void coap_timer_stop(void);
void coap_timer_update(coap_queue_t ** queue);
void coap_timer_start(coap_queue_t ** queue);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,301 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "esp_libc.h"
#include "coap.h"
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "os_type.h"
#include "user_interface.h"
#include "user_config.h"
void build_well_known_rsp(char *rsp, uint16_t rsplen);
void endpoint_setup(void)
{
coap_setup();
}
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)
{
outpkt->content.p = (uint8_t *)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, 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 int handle_get_variable(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)
{
const coap_option_t *opt;
uint8_t count;
int n;
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]
{
NODE_DBG("should never happen.\n");
goto end;
}
if (count == ep->path->count + 1)
{
coap_luser_entry *h = ep->user_entry->next; // ->next: skip the first entry(head)
while(NULL != h){
if (opt[count-1].buf.len != strlen(h->name))
{
h = h->next;
continue;
}
if (0 == memcmp(h->name, opt[count-1].buf.p, opt[count-1].buf.len))
{
NODE_DBG("/v1/v/");
NODE_DBG((char *)h->name);
NODE_DBG(" match.\n");
if(h->L == NULL)
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
if(strlen(h->name))
{
n = lua_gettop(h->L);
lua_getglobal(h->L, h->name);
if (!lua_isnumber(h->L, -1) && !lua_isstring(h->L, -1)) {
NODE_DBG ("should be a number or string.\n");
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);
} else {
const char *res = lua_tostring(h->L,-1);
lua_settop(h->L, n);
return coap_make_response(scratch, outpkt, (const uint8_t *)res, strlen(res), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, h->content_type);
}
}
} else {
h = h->next;
}
}
}else{
NODE_DBG("/v1/v match.\n");
goto end;
}
}
NODE_DBG("none match.\n");
end:
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
}
static const coap_endpoint_path_t path_function = {2, {"v1", "f"}};
static int handle_post_function(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)
{
const coap_option_t *opt;
uint8_t count;
int n;
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]
{
NODE_DBG("should never happen.\n");
goto end;
}
if (count == ep->path->count + 1)
{
coap_luser_entry *h = ep->user_entry->next; // ->next: skip the first entry(head)
while(NULL != h){
if (opt[count-1].buf.len != strlen(h->name))
{
h = h->next;
continue;
}
if (0 == memcmp(h->name, opt[count-1].buf.p, opt[count-1].buf.len))
{
NODE_DBG("/v1/f/");
NODE_DBG((char *)h->name);
NODE_DBG(" match.\n");
if(h->L == NULL)
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
if(strlen(h->name))
{
n = lua_gettop(h->L);
lua_getglobal(h->L, h->name);
if (lua_type(h->L, -1) != LUA_TFUNCTION) {
NODE_DBG ("should be a function\n");
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);
} 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_call(h->L, 1, 1);
if (!lua_isnil(h->L, -1)){ /* get return? */
if( lua_isstring(h->L, -1) ) // deal with the return string
{
size_t len = 0;
const char *ret = luaL_checklstring( h->L, -1, &len );
if(len > MAX_PAYLOAD_SIZE){
lua_settop(h->L, n);
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);
}
NODE_DBG((char *)ret);
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);
}
} 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);
}
}
}
} else {
h = h->next;
}
}
}else{
NODE_DBG("/v1/f match.\n");
goto end;
}
}
NODE_DBG("none match.\n");
end:
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
}
extern lua_Load gLoad;
static const coap_endpoint_path_t path_command = {2, {"v1", "c"}};
static int handle_post_command(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)
{
if (inpkt->payload.len == 0)
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);
if (inpkt->payload.len > 0)
{
lua_Load *load = &gLoad;
if(load->line_position == 0){
coap_buffer_to_string(load->line, load->len,&inpkt->payload);
load->line_position = strlen(load->line)+1;
// load->line[load->line_position-1] = '\n';
// load->line[load->line_position] = 0;
// load->line_position++;
load->done = 1;
NODE_DBG("Get command:\n");
NODE_DBG(load->line); // buggy here
NODE_DBG("\nResult(if any):\n");
#if 0 // FIXME
system_os_post (LUA_TASK_PRIO, LUA_PROCESS_LINE_SIG, 0);
#endif
}
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
}
}
static uint32_t id = 0;
static const coap_endpoint_path_t path_id = {2, {"v1", "id"}};
static int handle_get_id(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)
{
#if defined(__ESP8266__)
id = system_get_chip_id();
#elif defined(__ESP32__)
uint8_t tmp;
system_get_chip_id (&tmp); // TODO: deal with failure
id = tmp;
#endif
return coap_make_response(scratch, outpkt, (const uint8_t *)(&id), sizeof(uint32_t), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
}
coap_luser_entry var_head = {NULL,NULL,NULL,0};
coap_luser_entry *variable_entry = &var_head;
coap_luser_entry func_head = {NULL,NULL,NULL,0};
coap_luser_entry *function_entry = &func_head;
const coap_endpoint_t endpoints[] =
{
{COAP_METHOD_GET, handle_get_well_known_core, &path_well_known_core, "ct=40", NULL},
{COAP_METHOD_GET, handle_get_variable, &path_variable, "ct=0", &var_head},
{COAP_METHOD_POST, handle_post_function, &path_function, NULL, &func_head},
{COAP_METHOD_POST, handle_post_command, &path_command, NULL, NULL},
{COAP_METHOD_GET, handle_get_id, &path_id, "ct=0", NULL},
{(coap_method_t)0, NULL, NULL, NULL, NULL}
};
void build_well_known_rsp(char *rsp, uint16_t rsplen)
{
const coap_endpoint_t *ep = endpoints;
int i;
uint16_t len = rsplen;
memset(rsp, 0, len);
len--; // Null-terminated string
while(NULL != ep->handler)
{
if (NULL == ep->core_attr) {
ep++;
continue;
}
if (NULL == ep->user_entry){
if (0 < strlen(rsp)) {
strncat(rsp, ",", len);
len--;
}
strncat(rsp, "<", len);
len--;
for (i = 0; i < ep->path->count; i++) {
strncat(rsp, "/", len);
len--;
strncat(rsp, ep->path->elems[i], len);
len -= strlen(ep->path->elems[i]);
}
strncat(rsp, ">;", len);
len -= 2;
strncat(rsp, ep->core_attr, len);
len -= strlen(ep->core_attr);
} else {
coap_luser_entry *h = ep->user_entry->next; // ->next: skip the first entry(head)
while(NULL != h){
if (0 < strlen(rsp)) {
strncat(rsp, ",", len);
len--;
}
strncat(rsp, "<", len);
len--;
for (i = 0; i < ep->path->count; i++) {
strncat(rsp, "/", len);
len--;
strncat(rsp, ep->path->elems[i], len);
len -= strlen(ep->path->elems[i]);
}
strncat(rsp, "/", len);
len--;
strncat(rsp, h->name, len);
len -= strlen(h->name);
strncat(rsp, ">;", len);
len -= 2;
strncat(rsp, ep->core_attr, len);
len -= strlen(ep->core_attr);
h = h->next;
}
}
ep++;
}
}

View File

@ -1,30 +0,0 @@
#include "hash.h"
#include <string.h>
/* Caution: When changing this, update COAP_DEFAULT_WKC_HASHKEY
* accordingly (see int coap_hash_path());
*/
void coap_hash(const unsigned char *s, unsigned int len, coap_key_t h) {
size_t j;
while (len--) {
j = sizeof(coap_key_t)-1;
while (j) {
h[j] = ((h[j] << 7) | (h[j-1] >> 1)) + h[j];
--j;
}
h[0] = (h[0] << 7) + h[0] + *s++;
}
}
void coap_transaction_id(const uint32_t ip, const uint32_t port, const coap_packet_t *pkt, coap_tid_t *id) {
coap_key_t h;
memset(h, 0, sizeof(coap_key_t));
/* Compare the transport address. */
coap_hash((const unsigned char *)&(port), sizeof(port), h);
coap_hash((const unsigned char *)&(ip), sizeof(ip), h);
coap_hash((const unsigned char *)(pkt->hdr.id), sizeof(pkt->hdr.id), h);
*id = ((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3]);
}

View File

@ -1,23 +0,0 @@
#ifndef _HASH_H
#define _HASH_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "coap.h"
typedef unsigned char coap_key_t[4];
/* CoAP transaction id */
/*typedef unsigned short coap_tid_t; */
typedef int coap_tid_t;
#define COAP_INVALID_TID -1
void coap_transaction_id(const uint32_t ip, const uint32_t port, const coap_packet_t *pkt, coap_tid_t *id);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,142 +0,0 @@
#include <string.h>
#include <stdlib.h>
#include "esp_libc.h"
#include "node.h"
static inline coap_queue_t *
coap_malloc_node(void) {
return (coap_queue_t *)zalloc(sizeof(coap_queue_t));
}
void coap_free_node(coap_queue_t *node) {
free(node);
}
int coap_insert_node(coap_queue_t **queue, coap_queue_t *node) {
coap_queue_t *p, *q;
if ( !queue || !node )
return 0;
/* set queue head if empty */
if ( !*queue ) {
*queue = node;
return 1;
}
/* replace queue head if PDU's time is less than head's time */
q = *queue;
if (node->t < q->t) {
node->next = q;
*queue = node;
q->t -= node->t; /* make q->t relative to node->t */
return 1;
}
/* search for right place to insert */
do {
node->t -= q->t; /* make node-> relative to q->t */
p = q;
q = q->next;
} while (q && q->t <= node->t);
/* insert new item */
if (q) {
q->t -= node->t; /* make q->t relative to node->t */
}
node->next = q;
p->next = node;
return 1;
}
int coap_delete_node(coap_queue_t *node) {
if ( !node )
return 0;
coap_delete_pdu(node->pdu);
coap_free_node(node);
return 1;
}
void coap_delete_all(coap_queue_t *queue) {
if ( !queue )
return;
coap_delete_all( queue->next );
coap_delete_node( queue );
}
coap_queue_t * coap_new_node(void) {
coap_queue_t *node;
node = coap_malloc_node();
if ( ! node ) {
return NULL;
}
memset(node, 0, sizeof(*node));
return node;
}
coap_queue_t * coap_peek_next( coap_queue_t *queue ) {
if ( !queue )
return NULL;
return queue;
}
coap_queue_t * coap_pop_next( coap_queue_t **queue ) { // this function is called inside timeout callback only.
coap_queue_t *next;
if ( !(*queue) )
return NULL;
next = *queue;
*queue = (*queue)->next;
// if (queue) {
// queue->t += next->t;
// }
next->next = NULL;
return next;
}
int coap_remove_node( coap_queue_t **queue, const coap_tid_t id){
coap_queue_t *p, *q, *node;
if ( !queue )
return 0;
if ( !*queue ) // if empty
return 0;
q = *queue;
if (q->id == id) {
node = q;
*queue = q->next;
node->next = NULL;
if(*queue){
(*queue)->t += node->t;
}
coap_delete_node(node);
return 1;
}
/* search for right node to remove */
while (q && q->id != id) {
p = q;
q = q->next;
}
/* find the node */
if (q) {
node = q; /* save the node */
p->next = q->next; /* remove the node */
q = q->next;
node->next = NULL;
if (q) // add node->t to the node after.
{
q->t += node->t;
}
coap_delete_node(node);
return 1;
}
return 0;
}

View File

@ -1,58 +0,0 @@
#ifndef _NODE_H
#define _NODE_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "hash.h"
#include "pdu.h"
struct coap_queue_t;
typedef uint32_t coap_tick_t;
/*
1. queue(first)->t store when to send PDU for the next time, it's a base(absolute) time
2. queue->next->t store the delta between time and base-time. queue->next->t = timeout + now - basetime
3. node->next->t store the delta between time and previous->t. node->next->t = timeout + now - node->t - basetime
4. time to fire: 10, 15, 18, 25
node->t: 10, 5, 3, 7
*/
typedef struct coap_queue_t {
struct coap_queue_t *next;
coap_tick_t t; /**< when to send PDU for the next time */
unsigned char retransmit_cnt; /**< retransmission counter, will be removed when zero */
unsigned int timeout; /**< the randomized timeout value */
coap_tid_t id; /**< unique transaction id */
// coap_packet_t *pkt;
coap_pdu_t *pdu; /**< the CoAP PDU to send */
struct espconn *pconn;
} coap_queue_t;
void coap_free_node(coap_queue_t *node);
/** Adds node to given queue, ordered by node->t. */
int coap_insert_node(coap_queue_t **queue, coap_queue_t *node);
/** Destroys specified node. */
int coap_delete_node(coap_queue_t *node);
/** Removes all items from given queue and frees the allocated storage. */
void coap_delete_all(coap_queue_t *queue);
/** Creates a new node suitable for adding to the CoAP sendqueue. */
coap_queue_t *coap_new_node(void);
coap_queue_t *coap_pop_next( coap_queue_t **queue );
int coap_remove_node( coap_queue_t **queue, const coap_tid_t id);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,66 +0,0 @@
#include <stdlib.h>
#include "pdu.h"
#include "esp_libc.h"
coap_pdu_t * coap_new_pdu(void) {
coap_pdu_t *pdu = NULL;
pdu = (coap_pdu_t *)zalloc(sizeof(coap_pdu_t));
if(!pdu){
NODE_DBG("coap_new_pdu malloc error.\n");
return NULL;
}
pdu->scratch.p = (uint8_t *)zalloc(MAX_REQ_SCRATCH_SIZE);
if(!pdu->scratch.p){
NODE_DBG("coap_new_pdu malloc error.\n");
free(pdu);
return NULL;
}
pdu->scratch.len = MAX_REQ_SCRATCH_SIZE;
pdu->pkt = (coap_packet_t *)zalloc(sizeof(coap_packet_t));
if(!pdu->pkt){
NODE_DBG("coap_new_pdu malloc error.\n");
free(pdu->scratch.p);
free(pdu);
return NULL;
}
pdu->pkt->content.p = NULL;
pdu->pkt->content.len = 0;
pdu->msg.p = (uint8_t *)zalloc(MAX_REQUEST_SIZE+1); // +1 for string '\0'
if(!pdu->msg.p){
NODE_DBG("coap_new_pdu malloc error.\n");
free(pdu->pkt);
free(pdu->scratch.p);
free(pdu);
return NULL;
}
pdu->msg.len = MAX_REQUEST_SIZE;
return pdu;
}
void coap_delete_pdu(coap_pdu_t *pdu){
if(!pdu)
return;
if(pdu->scratch.p){
free(pdu->scratch.p);
pdu->scratch.p = NULL;
pdu->scratch.len = 0;
}
if(pdu->pkt){
free(pdu->pkt);
pdu->pkt = NULL;
}
if(pdu->msg.p){
free(pdu->msg.p);
pdu->msg.p = NULL;
pdu->msg.len = 0;
}
free(pdu);
pdu = NULL;
}

View File

@ -1,25 +0,0 @@
#ifndef _PDU_H
#define _PDU_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "coap.h"
/** Header structure for CoAP PDUs */
typedef struct {
coap_rw_buffer_t scratch;
coap_packet_t *pkt;
coap_rw_buffer_t msg; /**< the CoAP msg to send */
} coap_pdu_t;
coap_pdu_t *coap_new_pdu(void);
void coap_delete_pdu(coap_pdu_t *pdu);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,28 +0,0 @@
/* str.c -- strings to be used in the CoAP library
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#include <stdlib.h>
#include <ctype.h>
#include "str.h"
str * coap_new_string(size_t size) {
str *s = (str *)malloc(sizeof(str) + size + 1);
if ( !s ) {
return NULL;
}
memset(s, 0, sizeof(str));
s->s = ((unsigned char *)s) + sizeof(str);
return s;
}
void coap_delete_string(str *s) {
free(s);
}

View File

@ -1,30 +0,0 @@
/* str.h -- strings to be used in the CoAP library
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_STR_H_
#define _COAP_STR_H_
#include <string.h>
typedef struct {
size_t length; /* length of string */
unsigned char *s; /* string data */
} str;
#define COAP_SET_STR(st,l,v) { (st)->length = (l), (st)->s = (v); }
/**
* Returns a new string object with at least size bytes storage
* allocated. The string must be released using coap_delete_string();
*/
str *coap_new_string(size_t size);
/** Deletes the given string and releases any memory allocated. */
void coap_delete_string(str *);
#endif /* _COAP_STR_H_ */

View File

@ -1,468 +0,0 @@
/* uri.c -- helper functions for URI treatment
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "coap.h"
#include "uri.h"
#ifndef assert
// #warning "assertions are disabled"
# define assert(x) do { \
if(!x) NODE_ERR("uri.c assert!\n"); \
} while (0)
#endif
/**
* A length-safe version of strchr(). This function returns a pointer
* to the first occurrence of @p c in @p s, or @c NULL if not found.
*
* @param s The string to search for @p c.
* @param len The length of @p s.
* @param c The character to search.
*
* @return A pointer to the first occurence of @p c, or @c NULL
* if not found.
*/
static inline unsigned char *
strnchr(unsigned char *s, size_t len, unsigned char c) {
while (len && *s++ != c)
--len;
return len ? s : NULL;
}
int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) {
unsigned char *p, *q;
int secure = 0, res = 0;
if (!str_var || !uri)
return -1;
memset(uri, 0, sizeof(coap_uri_t));
uri->port = COAP_DEFAULT_PORT;
/* search for scheme */
p = str_var;
if (*p == '/') {
q = p;
goto path;
}
q = (unsigned char *)COAP_DEFAULT_SCHEME;
while (len && *q && tolower(*p) == *q) {
++p; ++q; --len;
}
/* If q does not point to the string end marker '\0', the schema
* identifier is wrong. */
if (*q) {
res = -1;
goto error;
}
/* There might be an additional 's', indicating the secure version: */
if (len && (secure = tolower(*p) == 's')) {
++p; --len;
}
q = (unsigned char *)"://";
while (len && *q && tolower(*p) == *q) {
++p; ++q; --len;
}
if (*q) {
res = -2;
goto error;
}
/* p points to beginning of Uri-Host */
q = p;
if (len && *p == '[') { /* IPv6 address reference */
++p;
while (len && *q != ']') {
++q; --len;
}
if (!len || *q != ']' || p == q) {
res = -3;
goto error;
}
COAP_SET_STR(&uri->host, q - p, p);
++q; --len;
} else { /* IPv4 address or FQDN */
while (len && *q != ':' && *q != '/' && *q != '?') {
*q = tolower(*q);
++q;
--len;
}
if (p == q) {
res = -3;
goto error;
}
COAP_SET_STR(&uri->host, q - p, p);
}
/* check for Uri-Port */
if (len && *q == ':') {
p = ++q;
--len;
while (len && isdigit(*q)) {
++q;
--len;
}
if (p < q) { /* explicit port number given */
int uri_port = 0;
while (p < q)
uri_port = uri_port * 10 + (*p++ - '0');
uri->port = uri_port;
}
}
path: /* at this point, p must point to an absolute path */
if (!len)
goto end;
if (*q == '/') {
p = ++q;
--len;
while (len && *q != '?') {
++q;
--len;
}
if (p < q) {
COAP_SET_STR(&uri->path, q - p, p);
p = q;
}
}
/* Uri_Query */
if (len && *p == '?') {
++p;
--len;
COAP_SET_STR(&uri->query, len, p);
len = 0;
}
end:
return len ? -1 : 0;
error:
return res;
}
/**
* Calculates decimal value from hexadecimal ASCII character given in
* @p c. The caller must ensure that @p c actually represents a valid
* heaxdecimal character, e.g. with isxdigit(3).
*
* @hideinitializer
*/
#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
/**
* Decodes percent-encoded characters while copying the string @p seg
* of size @p length to @p buf. The caller of this function must
* ensure that the percent-encodings are correct (i.e. the character
* '%' is always followed by two hex digits. and that @p buf provides
* sufficient space to hold the result. This function is supposed to
* be called by make_decoded_option() only.
*
* @param seg The segment to decode and copy.
* @param length Length of @p seg.
* @param buf The result buffer.
*/
void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) {
while (length--) {
if (*seg == '%') {
*buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
seg += 2; length -= 2;
} else {
*buf = *seg;
}
++buf; ++seg;
}
}
/**
* Runs through the given path (or query) segment and checks if
* percent-encodings are correct. This function returns @c -1 on error
* or the length of @p s when decoded.
*/
int check_segment(const unsigned char *s, size_t length) {
size_t n = 0;
while (length) {
if (*s == '%') {
if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
return -1;
s += 2;
length -= 2;
}
++s; ++n; --length;
}
return n;
}
/**
* Writes a coap option from given string @p s to @p buf. @p s should
* point to a (percent-encoded) path or query segment of a coap_uri_t
* object. The created option will have type @c 0, and the length
* parameter will be set according to the size of the decoded string.
* On success, this function returns the option's size, or a value
* less than zero on error. This function must be called from
* coap_split_path_impl() only.
*
* @param s The string to decode.
* @param length The size of the percent-encoded string @p s.
* @param buf The buffer to store the new coap option.
* @param buflen The maximum size of @p buf.
*
* @return The option's size, or @c -1 on error.
*
* @bug This function does not split segments that are bigger than 270
* bytes.
*/
int make_decoded_option(const unsigned char *s, size_t length,
unsigned char *buf, size_t buflen) {
int res;
size_t written;
if (!buflen) {
NODE_DBG("make_decoded_option(): buflen is 0!\n");
return -1;
}
res = check_segment(s, length);
if (res < 0)
return -1;
/* write option header using delta 0 and length res */
// written = coap_opt_setheader(buf, buflen, 0, res);
written = coap_buildOptionHeader(0, res, buf, buflen);
assert(written <= buflen);
if (!written) /* encoding error */
return -1;
buf += written; /* advance past option type/length */
buflen -= written;
if (buflen < (size_t)res) {
NODE_DBG("buffer too small for option\n");
return -1;
}
decode_segment(s, length, buf);
return written + res;
}
#ifndef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
/**
* Splits the given string into segments. You should call one of the
* macros coap_split_path() or coap_split_query() instead.
*
* @param parse_iter The iterator used for tokenizing.
* @param h A handler that is called with every token.
* @param data Opaque data that is passed to @p h when called.
*
* @return The number of characters that have been parsed from @p s.
*/
size_t coap_split_path_impl(coap_parse_iterator_t *parse_iter,
segment_handler_t h, void *data) {
unsigned char *seg;
size_t length;
assert(parse_iter);
assert(h);
length = parse_iter->n;
while ( (seg = coap_parse_next(parse_iter)) ) {
/* any valid path segment is handled here: */
h(seg, parse_iter->segment_length, data);
}
return length - (parse_iter->n - parse_iter->segment_length);
}
struct pkt_scr {
coap_packet_t *pkt;
coap_rw_buffer_t *scratch;
int n;
};
void write_option(unsigned char *s, size_t len, void *data) {
struct pkt_scr *state = (struct pkt_scr *)data;
int res;
assert(state);
/* skip empty segments and those that consist of only one or two dots */
if (memcmp(s, "..", min(len,2)) == 0)
return;
res = check_segment(s, len);
if (res < 0){
NODE_DBG("not a valid segment\n");
return;
}
if (state->scratch->len < (size_t)res) {
NODE_DBG("buffer too small for option\n");
return;
}
decode_segment(s, len, state->scratch->p);
if (res > 0) {
state->pkt->opts[state->pkt->numopts].buf.p = state->scratch->p;
state->pkt->opts[state->pkt->numopts].buf.len = res;
state->scratch->p += res;
state->scratch->len -= res;
state->pkt->numopts++;
state->n++;
}
}
int coap_split_path(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const unsigned char *s, size_t length) {
struct pkt_scr tmp = { pkt, scratch, 0 };
coap_parse_iterator_t pi;
coap_parse_iterator_init((unsigned char *)s, length,
'/', (unsigned char *)"?#", 2, &pi);
coap_split_path_impl(&pi, write_option, &tmp);
int i;
for(i=0;i<tmp.n;i++){
pkt->opts[pkt->numopts - i - 1].num = COAP_OPTION_URI_PATH;
}
return tmp.n;
}
int coap_split_query(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const unsigned char *s, size_t length) {
struct pkt_scr tmp = { pkt, scratch, 0 };
coap_parse_iterator_t pi;
coap_parse_iterator_init((unsigned char *)s, length,
'&', (unsigned char *)"#", 1, &pi);
coap_split_path_impl(&pi, write_option, &tmp);
int i;
for(i=0;i<tmp.n;i++){
pkt->opts[pkt->numopts - i - 1].num = COAP_OPTION_URI_QUERY;
}
return tmp.n;
}
#define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
coap_uri_t * coap_new_uri(const unsigned char *uri, unsigned int length) {
unsigned char *result;
result = (unsigned char *)malloc(length + 1 + sizeof(coap_uri_t));
if (!result)
return NULL;
memcpy(URI_DATA(result), uri, length);
URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
free(result);
return NULL;
}
return (coap_uri_t *)result;
}
/* iterator functions */
coap_parse_iterator_t * coap_parse_iterator_init(unsigned char *s, size_t n,
unsigned char separator,
unsigned char *delim, size_t dlen,
coap_parse_iterator_t *pi) {
assert(pi);
assert(separator);
pi->separator = separator;
pi->delim = delim;
pi->dlen = dlen;
pi->pos = s;
pi->n = n;
pi->segment_length = 0;
return pi;
}
unsigned char * coap_parse_next(coap_parse_iterator_t *pi) {
unsigned char *p;
if (!pi)
return NULL;
/* proceed to the next segment */
pi->n -= pi->segment_length;
pi->pos += pi->segment_length;
pi->segment_length = 0;
/* last segment? */
if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos)) {
pi->pos = NULL;
return NULL;
}
/* skip following separator (the first segment might not have one) */
if (*pi->pos == pi->separator) {
++pi->pos;
--pi->n;
}
p = pi->pos;
while (pi->segment_length < pi->n && *p != pi->separator &&
!strnchr(pi->delim, pi->dlen, *p)) {
++p;
++pi->segment_length;
}
if (!pi->n) {
pi->pos = NULL;
pi->segment_length = 0;
}
return pi->pos;
}

View File

@ -1,166 +0,0 @@
/* uri.h -- helper functions for URI treatment
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_URI_H_
#define _COAP_URI_H_
#define COAP_DEFAULT_SCHEME "coap" /* the default scheme for CoAP URIs */
#define COAP_DEFAULT_PORT 5683
#include "str.h"
/** Representation of parsed URI. Components may be filled from a
* string with coap_split_uri() and can be used as input for
* option-creation functions. */
typedef struct {
str host; /**< host part of the URI */
unsigned short port; /**< The port in host byte order */
str path; /**< Beginning of the first path segment.
Use coap_split_path() to create Uri-Path options */
str query; /**< The query part if present */
} coap_uri_t;
/**
* Creates a new coap_uri_t object from the specified URI. Returns the new
* object or NULL on error. The memory allocated by the new coap_uri_t
* must be released using coap_free().
* @param uri The URI path to copy.
* @para length The length of uri.
*
* @return New URI object or NULL on error.
*/
coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
/**
* @defgroup uri_parse URI Parsing Functions
*
* CoAP PDUs contain normalized URIs with their path and query split into
* multiple segments. The functions in this module help splitting strings.
* @{
*/
/**
* Iterator to for tokenizing a URI path or query. This structure must
* be initialized with coap_parse_iterator_init(). Call
* coap_parse_next() to walk through the tokens.
*
* @code
* unsigned char *token;
* coap_parse_iterator_t pi;
* coap_parse_iterator_init(uri.path.s, uri.path.length, '/', "?#", 2, &pi);
*
* while ((token = coap_parse_next(&pi))) {
* ... do something with token ...
* }
* @endcode
*/
typedef struct {
size_t n; /**< number of remaining characters in buffer */
unsigned char separator; /**< segment separators */
unsigned char *delim; /**< delimiters where to split the string */
size_t dlen; /**< length of separator */
unsigned char *pos; /**< current position in buffer */
size_t segment_length; /**< length of current segment */
} coap_parse_iterator_t;
/**
* Initializes the given iterator @p pi.
*
* @param s The string to tokenize.
* @param n The length of @p s.
* @param separator The separator character that delimits tokens.
* @param delim A set of characters that delimit @s.
* @param dlen The length of @p delim.
* @param pi The iterator object to initialize.
*
* @return The initialized iterator object @p pi.
*/
coap_parse_iterator_t *
coap_parse_iterator_init(unsigned char *s, size_t n,
unsigned char separator,
unsigned char *delim, size_t dlen,
coap_parse_iterator_t *pi);
/**
* Updates the iterator @p pi to point to the next token. This
* function returns a pointer to that token or @c NULL if no more
* tokens exist. The contents of @p pi will be updated. In particular,
* @c pi->segment_length specifies the length of the current token, @c
* pi->pos points to its beginning.
*
* @param pi The iterator to update.
*
* @return The next token or @c NULL if no more tokens exist.
*/
unsigned char *coap_parse_next(coap_parse_iterator_t *pi);
/**
* Parses a given string into URI components. The identified syntactic
* components are stored in the result parameter @p uri. Optional URI
* components that are not specified will be set to { 0, 0 }, except
* for the port which is set to @c COAP_DEFAULT_PORT. This function
* returns @p 0 if parsing succeeded, a value less than zero
* otherwise.
*
* @param str_var The string to split up.
* @param len The actual length of @p str_var
* @param uri The coap_uri_t object to store the result.
* @return @c 0 on success, or < 0 on error.
*
* @note The host name part will be converted to lower case by this
* function.
*/
int
coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri);
/**
* Splits the given URI path into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective segment after percent-decoding.
*
* @param s The path string to split.
* @param length The actual length of @p s.
* @param buf Result buffer for parsed segments.
* @param buflen Maximum length of @p buf. Will be set to the actual number
* of bytes written into buf on success.
*
* @return The number of segments created or @c -1 on error.
*/
#if 0
int coap_split_path(const unsigned char *s, size_t length,
unsigned char *buf, size_t *buflen);
#else
int
coap_split_path(coap_rw_buffer_t *scratch, coap_packet_t *pkt,
const unsigned char *s, size_t length);
#endif
/**
* Splits the given URI query into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective query term.
*
* @param s The query string to split.
* @param length The actual length of @p s.
* @param buf Result buffer for parsed segments.
* @param buflen Maximum length of @p buf. Will be set to the actual number
* of bytes written into buf on success.
*
* @return The number of segments created or @c -1 on error.
*
* @bug This function does not reserve additional space for delta > 12.
*/
#if 0
int coap_split_query(const unsigned char *s, size_t length,
unsigned char *buf, size_t *buflen);
#else
int coap_split_query(coap_rw_buffer_t *scratch, coap_packet_t *pkt,
const unsigned char *s, size_t length);
#endif
/** @} */
#endif /* _COAP_URI_H_ */

View File

@ -1,46 +0,0 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libcrypto.a
endif
STD_CFLAGS=-std=gnu11 -Wimplicit
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../libc
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -1,206 +0,0 @@
/*
* Copyright (c) 2015, DiUS Computing Pty Ltd (jmattsson@dius.com.au)
* All rights reserved.
*
* 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. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 OR CONTRIBUTOR(S) 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 "digests.h"
#include "user_config.h"
#include "rom.h"
#include "osapi.h"
#include "mem.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#ifdef MD2_ENABLE
#include "ssl/ssl_crypto.h"
#endif
#ifdef SHA2_ENABLE
#include "sha2.h"
#endif
typedef char ensure_int_and_size_t_same[(sizeof(int)==sizeof(size_t)) ? 0 : -1];
/* None of the functions match the prototype fully due to the void *, and in
some cases also the int vs size_t len, so wrap declarations in a macro. */
#define MECH(pfx, u, ds, bs) \
{ #pfx, \
(create_ctx_fn)pfx ## u ## Init, \
(update_ctx_fn)pfx ## u ## Update, \
(finalize_ctx_fn)pfx ## u ## Final, \
sizeof(pfx ## _CTX), \
ds, \
bs }
static const digest_mech_info_t hash_mechs[] ICACHE_RODATA_ATTR =
{
#ifdef MD2_ENABLE
MECH(MD2, _ , MD2_SIZE, 16),
#endif
MECH(MD5, , MD5_DIGEST_LENGTH, 64)
,MECH(SHA1, , SHA1_DIGEST_LENGTH, 64)
#ifdef SHA2_ENABLE
,MECH(SHA256, _ , SHA256_DIGEST_LENGTH, SHA256_BLOCK_LENGTH)
,MECH(SHA384, _ , SHA384_DIGEST_LENGTH, SHA384_BLOCK_LENGTH)
,MECH(SHA512, _ , SHA512_DIGEST_LENGTH, SHA512_BLOCK_LENGTH)
#endif
};
#undef MECH
const digest_mech_info_t *ICACHE_FLASH_ATTR crypto_digest_mech (const char *mech)
{
if (!mech)
return 0;
size_t i;
for (i = 0; i < (sizeof (hash_mechs) / sizeof (digest_mech_info_t)); ++i)
{
const digest_mech_info_t *mi = hash_mechs + i;
if (strcasecmp (mech, mi->name) == 0)
return mi;
}
return 0;
}
const char crypto_hexbytes[] = "0123456789abcdef";
// note: supports in-place encoding
void ICACHE_FLASH_ATTR crypto_encode_asciihex (const char *bin, size_t binlen, char *outbuf)
{
size_t aidx = binlen * 2 -1;
int i;
for (i = binlen -1; i >= 0; --i)
{
outbuf[aidx--] = crypto_hexbytes[bin[i] & 0xf];
outbuf[aidx--] = crypto_hexbytes[bin[i] >> 4];
}
}
int ICACHE_FLASH_ATTR crypto_hash (const digest_mech_info_t *mi,
const char *data, size_t data_len,
uint8_t *digest)
{
if (!mi)
return EINVAL;
void *ctx = (void *)malloc (mi->ctx_size);
if (!ctx)
return ENOMEM;
mi->create (ctx);
mi->update (ctx, data, data_len);
mi->finalize (digest, ctx);
free (ctx);
return 0;
}
int ICACHE_FLASH_ATTR crypto_fhash (const digest_mech_info_t *mi,
read_fn read, int readarg,
uint8_t *digest)
{
if (!mi)
return EINVAL;
// Initialise
void *ctx = (void *)malloc (mi->ctx_size);
if (!ctx)
return ENOMEM;
mi->create (ctx);
// Hash bytes from file in blocks
uint8_t* buffer = (uint8_t*)malloc (mi->block_size);
if (!buffer)
return ENOMEM;
int read_len = 0;
do {
read_len = read(readarg, buffer, mi->block_size);
mi->update (ctx, buffer, read_len);
} while (read_len == mi->block_size);
// Finish up
mi->finalize (digest, ctx);
free (buffer);
free (ctx);
return 0;
}
int ICACHE_FLASH_ATTR crypto_hmac (const digest_mech_info_t *mi,
const char *data, size_t data_len,
const char *key, size_t key_len,
uint8_t *digest)
{
if (!mi)
return EINVAL;
void *ctx = (void *)malloc (mi->ctx_size);
if (!ctx)
return ENOMEM;
// If key too long, it needs to be hashed before use
if (key_len > mi->block_size)
{
mi->create (ctx);
mi->update (ctx, key, key_len);
mi->finalize (digest, ctx);
key = digest;
key_len = mi->digest_size;
}
const size_t bs = mi->block_size;
uint8_t k_ipad[bs];
uint8_t k_opad[bs];
os_memset (k_ipad, 0x36, bs);
os_memset (k_opad, 0x5c, bs);
size_t i;
for (i = 0; i < key_len; ++i)
{
k_ipad[i] ^= key[i];
k_opad[i] ^= key[i];
}
mi->create (ctx);
mi->update (ctx, k_ipad, bs);
mi->update (ctx, data, data_len);
mi->finalize (digest, ctx);
mi->create (ctx);
mi->update (ctx, k_opad, bs);
mi->update (ctx, digest, mi->digest_size);
mi->finalize (digest, ctx);
free (ctx);
return 0;
}

View File

@ -1,96 +0,0 @@
#ifndef _CRYPTO_DIGESTS_H_
#define _CRYPTO_DIGESTS_H_
#include <c_types.h>
typedef void (*create_ctx_fn)(void *ctx);
typedef void (*update_ctx_fn)(void *ctx, const uint8_t *msg, int len);
typedef void (*finalize_ctx_fn)(uint8_t *digest, void *ctx);
typedef size_t ( *read_fn )(int fd, void *ptr, size_t len);
/**
* Description of a message digest mechanism.
*
* Typical usage (if not using the crypto_xxxx() functions below):
* digest_mech_info_t *mi = crypto_digest_mech (chosen_algorithm);
* void *ctx = malloc (mi->ctx_size);
* mi->create (ctx);
* mi->update (ctx, data, len);
* ...
* uint8_t *digest = malloc (mi->digest_size);
* mi->finalize (digest, ctx);
* ...
* free (ctx);
* free (digest);
*/
typedef struct
{
/* Note: All entries are 32bit to enable placement using ICACHE_RODATA_ATTR.*/
const char * name;
create_ctx_fn create;
update_ctx_fn update;
finalize_ctx_fn finalize;
uint32_t ctx_size;
uint32_t digest_size;
uint32_t block_size;
} digest_mech_info_t;
/**
* Looks up the mech data for a specified digest algorithm.
* @param mech The name of the algorithm, e.g. "MD5", "SHA256"
* @returns The mech data, or null if the mech is unknown.
*/
const digest_mech_info_t *crypto_digest_mech (const char *mech);
/**
* Wrapper function for performing a one-in-all hashing operation.
* @param mi A mech from @c crypto_digest_mech(). A null pointer @c mi
* is harmless, but will of course result in an error return.
* @param data The data to create a digest for.
* @param data_len Number of bytes at @c data to digest.
* @param digest Output buffer, must be at least @c mi->digest_size in size.
* @return 0 on success, non-zero on error.
*/
int crypto_hash (const digest_mech_info_t *mi, const char *data, size_t data_len, uint8_t *digest);
/**
* Wrapper function for performing a one-in-all hashing operation of a file.
* @param mi A mech from @c crypto_digest_mech(). A null pointer @c mi
* is harmless, but will of course result in an error return.
* @param read Pointer to the read function (e.g. fs_read)
* @param readarg Argument to pass to the read function (e.g. file descriptor)
* @param digest Output buffer, must be at least @c mi->digest_size in size.
* @return 0 on success, non-zero on error.
*/
int crypto_fhash (const digest_mech_info_t *mi, read_fn read, int readarg, uint8_t *digest);
/**
* Generate a HMAC signature.
* @param mi A mech from @c crypto_digest_mech(). A null pointer @c mi
* is harmless, but will of course result in an error return.
* @param data The data to generate a signature for.
* @param data_len Number of bytes at @c data to process.
* @param key The key to use.
* @param key_len Number of bytes the @c key comprises.
* @param digest Output buffer, must be at least @c mi->digest_size in size.
* @return 0 on success, non-zero on error.
*/
int crypto_hmac (const digest_mech_info_t *mi, const char *data, size_t data_len, const char *key, size_t key_len, uint8_t *digest);
/**
* Perform ASCII Hex encoding. Does not null-terminate the buffer.
*
* @param bin The buffer to ascii-hex encode.
* @param bin_len Number of bytes in @c bin to encode.
* @param outbuf Output buffer, must be at least @c bin_len*2 bytes in size.
* Note that in-place encoding is supported, and as such
* bin==outbuf is safe, provided the buffer is large enough.
*/
void crypto_encode_asciihex (const char *bin, size_t bin_len, char *outbuf);
/** Text string "0123456789abcdef" */
const char crypto_hexbytes[17];
#endif

View File

@ -1,131 +0,0 @@
/*
* Copyright 2016 Dius Computing Pty Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the copyright holders 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Johny Mattsson <jmattsson@dius.com.au>
*/
#include "mech.h"
#include "sdk-aes.h"
#include <string.h>
/* ----- AES ---------------------------------------------------------- */
static const struct aes_funcs
{
void *(*init) (const char *key, size_t keylen);
void (*crypt) (void *ctx, const char *in, char *out);
void (*deinit) (void *ctx);
} aes_funcs[] =
{
{ aes_encrypt_init, aes_encrypt, aes_encrypt_deinit },
{ aes_decrypt_init, aes_decrypt, aes_decrypt_deinit }
};
static bool do_aes (crypto_op_t *co, bool with_cbc)
{
const struct aes_funcs *funcs = &aes_funcs[co->op];
void *ctx = funcs->init (co->key, co->keylen);
if (!ctx)
return false;
char iv[AES_BLOCKSIZE] = { 0 };
if (with_cbc && co->ivlen)
memcpy (iv, co->iv, co->ivlen < AES_BLOCKSIZE ? co->ivlen : AES_BLOCKSIZE);
const char *src = co->data;
char *dst = co->out;
size_t left = co->datalen;
while (left)
{
char block[AES_BLOCKSIZE] = { 0 };
size_t n = left > AES_BLOCKSIZE ? AES_BLOCKSIZE : left;
memcpy (block, src, n);
if (with_cbc && co->op == OP_ENCRYPT)
{
const char *xor = (src == co->data) ? iv : dst - AES_BLOCKSIZE;
int i;
for (i = 0; i < AES_BLOCKSIZE; ++i)
block[i] ^= xor[i];
}
funcs->crypt (ctx, block, dst);
if (with_cbc && co->op == OP_DECRYPT)
{
const char *xor = (src == co->data) ? iv : src - AES_BLOCKSIZE;
int i;
for (i = 0; i < AES_BLOCKSIZE; ++i)
dst[i] ^= xor[i];
}
left -= n;
src += n;
dst += n;
}
funcs->deinit (ctx);
return true;
}
static bool do_aes_ecb (crypto_op_t *co)
{
return do_aes (co, false);
}
static bool do_aes_cbc (crypto_op_t *co)
{
return do_aes (co, true);
}
/* ----- mechs -------------------------------------------------------- */
static const crypto_mech_t mechs[] =
{
{ "AES-ECB", do_aes_ecb, AES_BLOCKSIZE },
{ "AES-CBC", do_aes_cbc, AES_BLOCKSIZE }
};
const crypto_mech_t *crypto_encryption_mech (const char *name)
{
size_t i;
for (i = 0; i < sizeof (mechs) / sizeof (mechs[0]); ++i)
{
const crypto_mech_t *mech = mechs + i;
if (strcasecmp (name, mech->name) == 0)
return mech;
}
return 0;
}

View File

@ -1,30 +0,0 @@
#ifndef _MECH_H_
#define _MECH_H_
#include "c_types.h"
typedef struct
{
const char *key;
size_t keylen;
const char *iv;
size_t ivlen;
const char *data;
size_t datalen;
char *out;
size_t outlen;
enum { OP_ENCRYPT, OP_DECRYPT } op;
} crypto_op_t;
typedef struct
{
const char *name;
bool (*run) (crypto_op_t *op);
uint16_t block_size;
} crypto_mech_t;
const crypto_mech_t *crypto_encryption_mech (const char *name);
#endif

View File

@ -1,14 +0,0 @@
#ifndef _SDK_AES_H_
#define _SDK_AES_H_
#define AES_BLOCKSIZE 16
void *aes_encrypt_init (const char *key, size_t len);
void aes_encrypt (void *ctx, const char *plain, char *crypt);
void aes_encrypt_deinit (void *ctx);
void *aes_decrypt_init (const char *key, size_t len);
void aes_decrypt (void *ctx, const char *crypt, char *plain);
void aes_decrypt_deinit (void *ctx);
#endif

View File

@ -1,913 +0,0 @@
/*
* FILE: sha2.c
* AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
*
* Copyright (c) 2000-2001, Aaron D. Gifford
* Copyright (c) 2015, DiUS Computing Pty Ltd (jmattsson@dius.com.au)
* All rights reserved.
*
* 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. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 OR CONTRIBUTOR(S) 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 "user_config.h"
#ifdef SHA2_ENABLE
#include "sha2.h"
#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */
#define assert(x) do {} while (0)
/*
* ASSERT NOTE:
* Some sanity checking code is included using assert(). On my FreeBSD
* system, this additional code can be removed by compiling with NDEBUG
* defined. Check your own systems manpage on assert() to see how to
* compile WITHOUT the sanity checking code on your system.
*
* UNROLLED TRANSFORM LOOP NOTE:
* You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
* loop version for the hash transform rounds (defined using macros
* later in this file). Either define on the command line, for example:
*
* cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
*
* or define below:
*
* #define SHA2_UNROLL_TRANSFORM
*
*/
typedef uint8_t sha2_byte; /* Exactly 1 byte */
typedef uint32_t sha2_word32; /* Exactly 4 bytes */
typedef uint64_t sha2_word64; /* Exactly 8 bytes */
/*** SHA-256/384/512 Various Length Definitions ***********************/
#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16)
#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16)
/*** ENDIAN REVERSAL MACROS *******************************************/
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define REVERSE32(w,x) { \
sha2_word32 tmp = (w); \
tmp = (tmp >> 16) | (tmp << 16); \
(x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
}
#define REVERSE64(w,x) { \
sha2_word64 tmp = (w); \
tmp = (tmp >> 32) | (tmp << 32); \
tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
((tmp & 0x00ff00ff00ff00ffULL) << 8); \
(x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
((tmp & 0x0000ffff0000ffffULL) << 16); \
}
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
/*
* Macro for incrementally adding the unsigned 64-bit integer n to the
* unsigned 128-bit integer (represented using a two-element array of
* 64-bit words):
*/
#define ADDINC128(w,n) { \
(w)[0] += (sha2_word64)(n); \
if ((w)[0] < (n)) { \
(w)[1]++; \
} \
}
/*
* Macros for copying blocks of memory and for zeroing out ranges
* of memory. Using these macros makes it easy to switch from
* using memset()/memcpy() and using bzero()/bcopy().
*
* Please define either SHA2_USE_MEMSET_MEMCPY or define
* SHA2_USE_BZERO_BCOPY depending on which function set you
* choose to use:
*/
#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
/* Default to memset()/memcpy() if no option is specified */
#define SHA2_USE_MEMSET_MEMCPY 1
#endif
#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
/* Abort with an error if BOTH options are defined */
#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
#endif
#ifdef SHA2_USE_MEMSET_MEMCPY
#define MEMSET_BZERO(p,l) memset((p), 0, (l))
#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l))
#endif
#ifdef SHA2_USE_BZERO_BCOPY
#define MEMSET_BZERO(p,l) bzero((p), (l))
#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l))
#endif
/*** THE SIX LOGICAL FUNCTIONS ****************************************/
/*
* Bit shifting and rotation (used by the six SHA-XYZ logical functions:
*
* NOTE: The naming of R and S appears backwards here (R is a SHIFT and
* S is a ROTATION) because the SHA-256/384/512 description document
* (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
* same "backwards" definition.
*/
/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
#define R(b,x) ((x) >> (b))
/* 32-bit Rotate-right (used in SHA-256): */
#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
/* Four of six logical functions used in SHA-256: */
#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
/* Four of six logical functions used in SHA-384 and SHA-512: */
#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
/*** INTERNAL FUNCTION PROTOTYPES *************************************/
/* NOTE: These should not be accessed directly from outside this
* library -- they are intended for private internal visibility/use
* only.
*/
void SHA512_Last(SHA512_CTX*);
void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
void SHA512_Transform(SHA512_CTX*, const sha2_word64*);
/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
/* Hash constant words K for SHA-256: */
const static sha2_word32 K256[64] ICACHE_RODATA_ATTR = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
};
/* Initial hash value H for SHA-256: */
const static sha2_word32 sha256_initial_hash_value[8] ICACHE_RODATA_ATTR = {
0x6a09e667UL,
0xbb67ae85UL,
0x3c6ef372UL,
0xa54ff53aUL,
0x510e527fUL,
0x9b05688cUL,
0x1f83d9abUL,
0x5be0cd19UL
};
/* Hash constant words K for SHA-384 and SHA-512: */
const static sha2_word64 K512[80] ICACHE_RODATA_ATTR = {
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
};
/* Initial hash value H for SHA-384 */
const static sha2_word64 sha384_initial_hash_value[8] ICACHE_RODATA_ATTR = {
0xcbbb9d5dc1059ed8ULL,
0x629a292a367cd507ULL,
0x9159015a3070dd17ULL,
0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL,
0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL,
0x47b5481dbefa4fa4ULL
};
/* Initial hash value H for SHA-512 */
const static sha2_word64 sha512_initial_hash_value[8] ICACHE_RODATA_ATTR = {
0x6a09e667f3bcc908ULL,
0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL,
0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL,
0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL,
0x5be0cd19137e2179ULL
};
/*** SHA-256: *********************************************************/
void ICACHE_FLASH_ATTR SHA256_Init(SHA256_CTX* context) {
if (context == (SHA256_CTX*)0) {
return;
}
MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);
MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH);
context->bitcount = 0;
}
#ifdef SHA2_UNROLL_TRANSFORM
/* Unrolled SHA-256 round macros: */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_
#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
REVERSE32(*data++, W256[j]); \
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
K256[j] + W256[j]; \
(d) += T1; \
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
j++
#else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
K256[j] + (W256[j] = *data++); \
(d) += T1; \
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
j++
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
#define ROUND256(a,b,c,d,e,f,g,h) \
s0 = W256[(j+1)&0x0f]; \
s0 = sigma0_256(s0); \
s1 = W256[(j+14)&0x0f]; \
s1 = sigma1_256(s1); \
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
(d) += T1; \
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
j++
void ICACHE_FLASH_ATTR SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
sha2_word32 T1, *W256;
int j;
W256 = (sha2_word32*)context->buffer;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
/* Rounds 0 to 15 (unrolled): */
ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
} while (j < 16);
/* Now for the remaining rounds to 64: */
do {
ROUND256(a,b,c,d,e,f,g,h);
ROUND256(h,a,b,c,d,e,f,g);
ROUND256(g,h,a,b,c,d,e,f);
ROUND256(f,g,h,a,b,c,d,e);
ROUND256(e,f,g,h,a,b,c,d);
ROUND256(d,e,f,g,h,a,b,c);
ROUND256(c,d,e,f,g,h,a,b);
ROUND256(b,c,d,e,f,g,h,a);
} while (j < 64);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = 0;
}
#else /* SHA2_UNROLL_TRANSFORM */
void ICACHE_FLASH_ATTR SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
sha2_word32 T1, T2, *W256;
int j;
W256 = (sha2_word32*)context->buffer;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Copy data while converting to host byte order */
REVERSE32(*data++,W256[j]);
/* Apply the SHA-256 compression function to update a..h */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
#else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
/* Apply the SHA-256 compression function to update a..h with copy */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
T2 = Sigma0_256(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 16);
do {
/* Part of the message block expansion: */
s0 = W256[(j+1)&0x0f];
s0 = sigma0_256(s0);
s1 = W256[(j+14)&0x0f];
s1 = sigma1_256(s1);
/* Apply the SHA-256 compression function to update a..h */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
T2 = Sigma0_256(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 64);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = T2 = 0;
}
#endif /* SHA2_UNROLL_TRANSFORM */
void ICACHE_FLASH_ATTR SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
unsigned int freespace, usedspace;
if (len == 0) {
/* Calling with no data is valid - we do nothing */
return;
}
/* Sanity check: */
assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0);
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
if (usedspace > 0) {
/* Calculate how much free space is available in the buffer */
freespace = SHA256_BLOCK_LENGTH - usedspace;
if (len >= freespace) {
/* Fill the buffer completely and process it */
MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
context->bitcount += freespace << 3;
len -= freespace;
data += freespace;
SHA256_Transform(context, (sha2_word32*)context->buffer);
} else {
/* The buffer is not yet full */
MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
context->bitcount += len << 3;
/* Clean up: */
usedspace = freespace = 0;
return;
}
}
while (len >= SHA256_BLOCK_LENGTH) {
/* Process as many complete blocks as we can */
SHA256_Transform(context, (sha2_word32*)data);
context->bitcount += SHA256_BLOCK_LENGTH << 3;
len -= SHA256_BLOCK_LENGTH;
data += SHA256_BLOCK_LENGTH;
}
if (len > 0) {
/* There's left-overs, so save 'em */
MEMCPY_BCOPY(context->buffer, data, len);
context->bitcount += len << 3;
}
/* Clean up: */
usedspace = freespace = 0;
}
void ICACHE_FLASH_ATTR SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
sha2_word32 *d = (sha2_word32*)digest;
unsigned int usedspace;
/* Sanity check: */
assert(context != (SHA256_CTX*)0);
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != (sha2_byte*)0) {
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Convert FROM host byte order */
REVERSE64(context->bitcount,context->bitcount);
#endif
if (usedspace > 0) {
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
/* Set-up for the last transform: */
MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace);
} else {
if (usedspace < SHA256_BLOCK_LENGTH) {
MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA256_Transform(context, (sha2_word32*)context->buffer);
/* And set-up for the last transform: */
MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
}
} else {
/* Set-up for the last transform: */
MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Set the bit count: */
*(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
/* Final transform: */
SHA256_Transform(context, (sha2_word32*)context->buffer);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{
/* Convert TO host byte order */
int j;
for (j = 0; j < 8; j++) {
REVERSE32(context->state[j],context->state[j]);
*d++ = context->state[j];
}
}
#else
MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH);
#endif
}
/* Clean up state data: */
MEMSET_BZERO(context, sizeof(SHA256_CTX));
usedspace = 0;
}
/*** SHA-512: *********************************************************/
void ICACHE_FLASH_ATTR SHA512_Init(SHA512_CTX* context) {
if (context == (SHA512_CTX*)0) {
return;
}
MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH);
context->bitcount[0] = context->bitcount[1] = 0;
}
#ifdef SHA2_UNROLL_TRANSFORM
/* Unrolled SHA-512 round macros: */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_
#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
REVERSE64(*data++, W512[j]); \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
K512[j] + W512[j]; \
(d) += T1, \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
j++
#else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
K512[j] + (W512[j] = *data++); \
(d) += T1; \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
j++
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
#define ROUND512(a,b,c,d,e,f,g,h) \
s0 = W512[(j+1)&0x0f]; \
s0 = sigma0_512(s0); \
s1 = W512[(j+14)&0x0f]; \
s1 = sigma1_512(s1); \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
(W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
(d) += T1; \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
j++
void ICACHE_FLASH_ATTR SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
sha2_word64 T1, *W512 = (sha2_word64*)context->buffer;
int j;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
} while (j < 16);
/* Now for the remaining rounds up to 79: */
do {
ROUND512(a,b,c,d,e,f,g,h);
ROUND512(h,a,b,c,d,e,f,g);
ROUND512(g,h,a,b,c,d,e,f);
ROUND512(f,g,h,a,b,c,d,e);
ROUND512(e,f,g,h,a,b,c,d);
ROUND512(d,e,f,g,h,a,b,c);
ROUND512(c,d,e,f,g,h,a,b);
ROUND512(b,c,d,e,f,g,h,a);
} while (j < 80);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = 0;
}
#else /* SHA2_UNROLL_TRANSFORM */
void ICACHE_FLASH_ATTR SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer;
int j;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Convert TO host byte order */
REVERSE64(*data++, W512[j]);
/* Apply the SHA-512 compression function to update a..h */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
#else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
/* Apply the SHA-512 compression function to update a..h with copy */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
T2 = Sigma0_512(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 16);
do {
/* Part of the message block expansion: */
s0 = W512[(j+1)&0x0f];
s0 = sigma0_512(s0);
s1 = W512[(j+14)&0x0f];
s1 = sigma1_512(s1);
/* Apply the SHA-512 compression function to update a..h */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
(W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
T2 = Sigma0_512(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 80);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = T2 = 0;
}
#endif /* SHA2_UNROLL_TRANSFORM */
void ICACHE_FLASH_ATTR SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {
unsigned int freespace, usedspace;
if (len == 0) {
/* Calling with no data is valid - we do nothing */
return;
}
/* Sanity check: */
assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0);
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
if (usedspace > 0) {
/* Calculate how much free space is available in the buffer */
freespace = SHA512_BLOCK_LENGTH - usedspace;
if (len >= freespace) {
/* Fill the buffer completely and process it */
MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
ADDINC128(context->bitcount, freespace << 3);
len -= freespace;
data += freespace;
SHA512_Transform(context, (sha2_word64*)context->buffer);
} else {
/* The buffer is not yet full */
MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
ADDINC128(context->bitcount, len << 3);
/* Clean up: */
usedspace = freespace = 0;
return;
}
}
while (len >= SHA512_BLOCK_LENGTH) {
/* Process as many complete blocks as we can */
SHA512_Transform(context, (sha2_word64*)data);
ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
len -= SHA512_BLOCK_LENGTH;
data += SHA512_BLOCK_LENGTH;
}
if (len > 0) {
/* There's left-overs, so save 'em */
MEMCPY_BCOPY(context->buffer, data, len);
ADDINC128(context->bitcount, len << 3);
}
/* Clean up: */
usedspace = freespace = 0;
}
void ICACHE_FLASH_ATTR SHA512_Last(SHA512_CTX* context) {
unsigned int usedspace;
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Convert FROM host byte order */
REVERSE64(context->bitcount[0],context->bitcount[0]);
REVERSE64(context->bitcount[1],context->bitcount[1]);
#endif
if (usedspace > 0) {
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
/* Set-up for the last transform: */
MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
} else {
if (usedspace < SHA512_BLOCK_LENGTH) {
MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA512_Transform(context, (sha2_word64*)context->buffer);
/* And set-up for the last transform: */
MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2);
}
} else {
/* Prepare for final transform: */
MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Store the length of input data (in bits): */
*(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
*(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
/* Final transform: */
SHA512_Transform(context, (sha2_word64*)context->buffer);
}
void ICACHE_FLASH_ATTR SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
assert(context != (SHA512_CTX*)0);
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != (sha2_byte*)0) {
SHA512_Last(context);
/* Save the hash data for output: */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{
/* Convert TO host byte order */
int j;
for (j = 0; j < 8; j++) {
REVERSE64(context->state[j],context->state[j]);
*d++ = context->state[j];
}
}
#else
MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH);
#endif
}
/* Zero out state data */
MEMSET_BZERO(context, sizeof(SHA512_CTX));
}
/*** SHA-384: *********************************************************/
void ICACHE_FLASH_ATTR SHA384_Init(SHA384_CTX* context) {
if (context == (SHA384_CTX*)0) {
return;
}
MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH);
MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH);
context->bitcount[0] = context->bitcount[1] = 0;
}
void ICACHE_FLASH_ATTR SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {
SHA512_Update((SHA512_CTX*)context, data, len);
}
void ICACHE_FLASH_ATTR SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
assert(context != (SHA384_CTX*)0);
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != (sha2_byte*)0) {
SHA512_Last((SHA512_CTX*)context);
/* Save the hash data for output: */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{
/* Convert TO host byte order */
int j;
for (j = 0; j < 6; j++) {
REVERSE64(context->state[j],context->state[j]);
*d++ = context->state[j];
}
}
#else
MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH);
#endif
}
/* Zero out state data */
MEMSET_BZERO(context, sizeof(SHA384_CTX));
}
#endif // SHA2_ENABLE

View File

@ -1,47 +0,0 @@
#ifndef __SHA2_H__
#define __SHA2_H__
#include <c_types.h>
/**************************************************************************
* SHA256/384/512 declarations
**************************************************************************/
#define SHA256_BLOCK_LENGTH 64
#define SHA256_DIGEST_LENGTH 32
typedef struct
{
uint32_t state[8];
uint64_t bitcount;
uint8_t buffer[SHA256_BLOCK_LENGTH];
} SHA256_CTX;
void SHA256_Init(SHA256_CTX *);
void SHA256_Update(SHA256_CTX *, const uint8_t *msg, size_t len);
void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);
#define SHA384_BLOCK_LENGTH 128
#define SHA384_DIGEST_LENGTH 48
typedef struct
{
uint64_t state[8];
uint64_t bitcount[2];
uint8_t buffer[SHA384_BLOCK_LENGTH];
} SHA384_CTX;
void SHA384_Init(SHA384_CTX*);
void SHA384_Update(SHA384_CTX*, const uint8_t *msg, size_t len);
void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);
#define SHA512_BLOCK_LENGTH 128
#define SHA512_DIGEST_LENGTH 64
typedef SHA384_CTX SHA512_CTX;
void SHA512_Init(SHA512_CTX*);
void SHA512_Update(SHA512_CTX*, const uint8_t *msg, size_t len);
void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
#endif

View File

@ -1,49 +0,0 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libdhtlib.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ./include
INCLUDES += -I ../include
INCLUDES += -I ../../include
INCLUDES += -I ../libc
INCLUDES += -I ../platform
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -1,319 +0,0 @@
//
// FILE: dht.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.14
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
// URL: http://arduino.cc/playground/Main/DHTLib
//
// HISTORY:
// 0.1.14 replace digital read with faster (~3x) code => more robust low MHz machines.
// 0.1.13 fix negative dht_temperature
// 0.1.12 support DHT33 and DHT44 initial version
// 0.1.11 renamed DHTLIB_TIMEOUT
// 0.1.10 optimized faster WAKEUP + TIMEOUT
// 0.1.09 optimize size: timeout check + use of mask
// 0.1.08 added formula for timeout based upon clockspeed
// 0.1.07 added support for DHT21
// 0.1.06 minimize footprint (2012-12-27)
// 0.1.05 fixed negative dht_temperature bug (thanks to Roseman)
// 0.1.04 improved readability of code using DHTLIB_OK in code
// 0.1.03 added error values for temp and dht_humidity when read failed
// 0.1.02 added error codes
// 0.1.01 added support for Arduino 1.0, fixed typos (31/12/2011)
// 0.1.00 by Rob Tillaart (01/04/2011)
//
// inspired by DHT11 library
//
// Released to the public domain
//
#include "user_interface.h"
#include "platform.h"
#include <stdio.h>
#include "dht.h"
#ifndef LOW
#define LOW 0
#endif /* ifndef LOW */
#ifndef HIGH
#define HIGH 1
#endif /* ifndef HIGH */
#define COMBINE_HIGH_AND_LOW_BYTE(byte_high, byte_low) (((byte_high) << 8) | (byte_low))
static double dht_humidity;
static double dht_temperature;
static uint8_t dht_bytes[5]; // buffer to receive data
static int dht_readSensor(uint8_t pin, uint8_t wakeupDelay);
/////////////////////////////////////////////////////
//
// PUBLIC
//
// return values:
// Humidity
double dht_getHumidity(void)
{
return dht_humidity;
}
// return values:
// Temperature
double dht_getTemperature(void)
{
return dht_temperature;
}
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht_read_universal(uint8_t pin)
{
// READ VALUES
int rv = dht_readSensor(pin, DHTLIB_DHT_UNI_WAKEUP);
if (rv != DHTLIB_OK)
{
dht_humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered?
dht_temperature = DHTLIB_INVALID_VALUE; // invalid value
return rv; // propagate error value
}
#if defined(DHT_DEBUG_BYTES)
int i;
for (i = 0; i < 5; i++)
{
DHT_DEBUG("%02X\n", dht_bytes[i]);
}
#endif // defined(DHT_DEBUG_BYTES)
// Assume it is DHT11
// If it is DHT11, both bit[1] and bit[3] is 0
if ((dht_bytes[1] == 0) && (dht_bytes[3] == 0))
{
// It may DHT11
// CONVERT AND STORE
DHT_DEBUG("DHT11 method\n");
dht_humidity = dht_bytes[0]; // dht_bytes[1] == 0;
dht_temperature = dht_bytes[2]; // dht_bytes[3] == 0;
// TEST CHECKSUM
// dht_bytes[1] && dht_bytes[3] both 0
uint8_t sum = dht_bytes[0] + dht_bytes[2];
if (dht_bytes[4] != sum)
{
// It may not DHT11
dht_humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered?
dht_temperature = DHTLIB_INVALID_VALUE; // invalid value
// Do nothing
}
else
{
return DHTLIB_OK;
}
}
// Assume it is not DHT11
// CONVERT AND STORE
DHT_DEBUG("DHTxx method\n");
dht_humidity = (double)COMBINE_HIGH_AND_LOW_BYTE(dht_bytes[0], dht_bytes[1]) * 0.1;
dht_temperature = (double)COMBINE_HIGH_AND_LOW_BYTE(dht_bytes[2] & 0x7F, dht_bytes[3]) * 0.1;
if (dht_bytes[2] & 0x80) // negative dht_temperature
{
dht_temperature = -dht_temperature;
}
// TEST CHECKSUM
uint8_t sum = dht_bytes[0] + dht_bytes[1] + dht_bytes[2] + dht_bytes[3];
if (dht_bytes[4] != sum)
{
return DHTLIB_ERROR_CHECKSUM;
}
return DHTLIB_OK;
}
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht_read11(uint8_t pin)
{
// READ VALUES
int rv = dht_readSensor(pin, DHTLIB_DHT11_WAKEUP);
if (rv != DHTLIB_OK)
{
dht_humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered?
dht_temperature = DHTLIB_INVALID_VALUE; // invalid value
return rv;
}
// CONVERT AND STORE
dht_humidity = dht_bytes[0]; // dht_bytes[1] == 0;
dht_temperature = dht_bytes[2]; // dht_bytes[3] == 0;
// TEST CHECKSUM
// dht_bytes[1] && dht_bytes[3] both 0
uint8_t sum = dht_bytes[0] + dht_bytes[2];
if (dht_bytes[4] != sum) return DHTLIB_ERROR_CHECKSUM;
return DHTLIB_OK;
}
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht_read(uint8_t pin)
{
// READ VALUES
int rv = dht_readSensor(pin, DHTLIB_DHT_WAKEUP);
if (rv != DHTLIB_OK)
{
dht_humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered?
dht_temperature = DHTLIB_INVALID_VALUE; // invalid value
return rv; // propagate error value
}
// CONVERT AND STORE
dht_humidity = (double)COMBINE_HIGH_AND_LOW_BYTE(dht_bytes[0], dht_bytes[1]) * 0.1;
dht_temperature = (double)COMBINE_HIGH_AND_LOW_BYTE(dht_bytes[2] & 0x7F, dht_bytes[3]) * 0.1;
if (dht_bytes[2] & 0x80) // negative dht_temperature
{
dht_temperature = -dht_temperature;
}
// TEST CHECKSUM
uint8_t sum = dht_bytes[0] + dht_bytes[1] + dht_bytes[2] + dht_bytes[3];
if (dht_bytes[4] != sum)
{
return DHTLIB_ERROR_CHECKSUM;
}
return DHTLIB_OK;
}
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht_read21(uint8_t pin) __attribute__((alias("dht_read")));
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht_read22(uint8_t pin) __attribute__((alias("dht_read")));
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht_read33(uint8_t pin) __attribute__((alias("dht_read")));
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht_read44(uint8_t pin) __attribute__((alias("dht_read")));
/////////////////////////////////////////////////////
//
// PRIVATE
//
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_TIMEOUT
int dht_readSensor(uint8_t pin, uint8_t wakeupDelay)
{
// INIT BUFFERVAR TO RECEIVE DATA
uint8_t mask = 128;
uint8_t idx = 0;
uint8_t i = 0;
// replace digitalRead() with Direct Port Reads.
// reduces footprint ~100 bytes => portability issue?
// direct port read is about 3x faster
// uint8_t bit = digitalPinToBitMask(pin);
// uint8_t port = digitalPinToPort(pin);
// volatile uint8_t *PIR = portInputRegister(port);
// EMPTY BUFFER
for (i = 0; i < 5; i++) dht_bytes[i] = 0;
// REQUEST SAMPLE
// pinMode(pin, OUTPUT);
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
DIRECT_MODE_OUTPUT(pin);
// digitalWrite(pin, LOW); // T-be
DIRECT_WRITE_LOW(pin);
// delay(wakeupDelay);
for (i = 0; i < wakeupDelay; i++) os_delay_us(1000);
// Disable interrupts
ets_intr_lock();
// digitalWrite(pin, HIGH); // T-go
DIRECT_WRITE_HIGH(pin);
os_delay_us(40);
// pinMode(pin, INPUT);
DIRECT_MODE_INPUT(pin);
// GET ACKNOWLEDGE or TIMEOUT
uint16_t loopCntLOW = DHTLIB_TIMEOUT;
while (DIRECT_READ(pin) == LOW ) // T-rel
{
os_delay_us(1);
if (--loopCntLOW == 0) return DHTLIB_ERROR_TIMEOUT;
}
uint16_t loopCntHIGH = DHTLIB_TIMEOUT;
while (DIRECT_READ(pin) != LOW ) // T-reh
{
os_delay_us(1);
if (--loopCntHIGH == 0) return DHTLIB_ERROR_TIMEOUT;
}
// READ THE OUTPUT - 40 BITS => 5 BYTES
for (i = 40; i != 0; i--)
{
loopCntLOW = DHTLIB_TIMEOUT;
while (DIRECT_READ(pin) == LOW )
{
os_delay_us(1);
if (--loopCntLOW == 0) return DHTLIB_ERROR_TIMEOUT;
}
uint32_t t = system_get_time();
loopCntHIGH = DHTLIB_TIMEOUT;
while (DIRECT_READ(pin) != LOW )
{
os_delay_us(1);
if (--loopCntHIGH == 0) return DHTLIB_ERROR_TIMEOUT;
}
if ((system_get_time() - t) > 40)
{
dht_bytes[idx] |= mask;
}
mask >>= 1;
if (mask == 0) // next byte?
{
mask = 128;
idx++;
}
}
// Enable interrupts
ets_intr_unlock();
// pinMode(pin, OUTPUT);
DIRECT_MODE_OUTPUT(pin);
// digitalWrite(pin, HIGH);
DIRECT_WRITE_HIGH(pin);
return DHTLIB_OK;
}
//
// END OF FILE
//

View File

@ -1,70 +0,0 @@
//
// FILE: dht.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.14
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
// URL: http://arduino.cc/playground/Main/DHTLib
//
// HISTORY:
// see dht.cpp file
//
#ifndef dht_h
#define dht_h
// #if ARDUINO < 100
// #include <WProgram.h>
// #else
// #include <Arduino.h>
// #endif
#include "c_types.h"
#define DHT_LIB_VERSION "0.1.14"
#define DHTLIB_OK 0
#define DHTLIB_ERROR_CHECKSUM -1
#define DHTLIB_ERROR_TIMEOUT -2
#define DHTLIB_INVALID_VALUE -999
#define DHTLIB_DHT11_WAKEUP 18
#define DHTLIB_DHT_WAKEUP 1
#define DHTLIB_DHT_UNI_WAKEUP 18
#define DHT_DEBUG
// max timeout is 100 usec.
// For a 16 Mhz proc 100 usec is 1600 clock cycles
// loops using DHTLIB_TIMEOUT use at least 4 clock cycli
// so 100 us takes max 400 loops
// so by dividing F_CPU by 40000 we "fail" as fast as possible
// ESP8266 uses delay_us get 1us time
#define DHTLIB_TIMEOUT (100)
// Platform specific I/O definitions
#define DIRECT_READ(pin) (0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[pin])))
#define DIRECT_MODE_INPUT(pin) GPIO_DIS_OUTPUT(pin_num[pin])
#define DIRECT_MODE_OUTPUT(pin)
#define DIRECT_WRITE_LOW(pin) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 0))
#define DIRECT_WRITE_HIGH(pin) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 1))
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht_read_universal(uint8_t pin);
int dht_read11(uint8_t pin);
int dht_read(uint8_t pin);
int dht_read21(uint8_t pin);
int dht_read22(uint8_t pin);
int dht_read33(uint8_t pin);
int dht_read44(uint8_t pin);
double dht_getHumidity(void);
double dht_getTemperature(void);
#endif
//
// END OF FILE
//

View File

@ -1,46 +0,0 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libdriver.a
endif
STD_CFLAGS=-std=gnu11 -Wimplicit
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include -I ../include/driver
INCLUDES += -I ./
INCLUDES += -I ../platform
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -1,47 +0,0 @@
#ifdef __ESP8266__
#include "ets_sys.h"
#include "osapi.h"
#include "eagle_soc.h"
#include "driver/gpio16.h"
void ICACHE_FLASH_ATTR
gpio16_output_conf(void)
{
WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
(READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC to output rtc_gpio0
WRITE_PERI_REG(RTC_GPIO_CONF,
(READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable
WRITE_PERI_REG(RTC_GPIO_ENABLE,
(READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1); //out enable
}
void ICACHE_FLASH_ATTR
gpio16_output_set(uint8 value)
{
WRITE_PERI_REG(RTC_GPIO_OUT,
(READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)(value & 1));
}
void ICACHE_FLASH_ATTR
gpio16_input_conf(void)
{
WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
(READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC and rtc_gpio0 connection
WRITE_PERI_REG(RTC_GPIO_CONF,
(READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable
WRITE_PERI_REG(RTC_GPIO_ENABLE,
READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe); //out disable
}
uint8 ICACHE_FLASH_ATTR
gpio16_input_get(void)
{
return (uint8)(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1);
}
#endif

View File

@ -1,334 +0,0 @@
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: i2c_master.c
*
* Description: i2c master API
*
* Modification history:
* 2014/3/12, v1.0 create this file.
*******************************************************************************/
#include "ets_sys.h"
#include "osapi.h"
#include "esp_misc.h"
#include "platform.h"
#include "gpio.h"
#include "driver/i2c_master.h"
#include "pin_map.h"
LOCAL uint8 m_nLastSDA;
LOCAL uint8 m_nLastSCL;
LOCAL uint8 pinSDA = 2;
LOCAL uint8 pinSCL = 15;
/******************************************************************************
* FunctionName : i2c_master_setDC
* Description : Internal used function -
* set i2c SDA and SCL bit value for half clk cycle
* Parameters : uint8 SDA
* uint8 SCL
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
i2c_master_setDC(uint8 SDA, uint8 SCL)
{
SDA &= 0x01;
SCL &= 0x01;
m_nLastSDA = SDA;
m_nLastSCL = SCL;
if ((0 == SDA) && (0 == SCL)) {
I2C_MASTER_SDA_LOW_SCL_LOW();
} else if ((0 == SDA) && (1 == SCL)) {
I2C_MASTER_SDA_LOW_SCL_HIGH();
} else if ((1 == SDA) && (0 == SCL)) {
I2C_MASTER_SDA_HIGH_SCL_LOW();
} else {
I2C_MASTER_SDA_HIGH_SCL_HIGH();
}
}
/******************************************************************************
* FunctionName : i2c_master_getDC
* Description : Internal used function -
* get i2c SDA bit value
* Parameters : NONE
* Returns : uint8 - SDA bit value
*******************************************************************************/
LOCAL uint8 ICACHE_FLASH_ATTR
i2c_master_getDC(void)
{
uint8 sda_out;
sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
return sda_out;
}
/******************************************************************************
* FunctionName : i2c_master_init
* Description : initilize I2C bus to enable i2c operations
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
i2c_master_init(void)
{
uint8 i;
i2c_master_setDC(1, 0);
i2c_master_wait(5);
// when SCL = 0, toggle SDA to clear up
i2c_master_setDC(0, 0) ;
i2c_master_wait(5);
i2c_master_setDC(1, 0) ;
i2c_master_wait(5);
// set data_cnt to max value
for (i = 0; i < 28; i++) {
i2c_master_setDC(1, 0);
i2c_master_wait(5); // sda 1, scl 0
i2c_master_setDC(1, 1);
i2c_master_wait(5); // sda 1, scl 1
}
// reset all
i2c_master_stop();
return;
}
uint8 i2c_master_get_pinSDA(){
return pinSDA;
}
uint8 i2c_master_get_pinSCL(){
return pinSCL;
}
/******************************************************************************
* FunctionName : i2c_master_gpio_init
* Description : config SDA and SCL gpio to open-drain output mode,
* mux and gpio num defined in i2c_master.h
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
i2c_master_gpio_init(uint8 sda, uint8 scl)
{
pinSDA = pin_num[sda];
pinSCL = pin_num[scl];
ETS_GPIO_INTR_DISABLE() ;
// ETS_INTR_LOCK();
PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC);
PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC);
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SDA_GPIO));
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO));
I2C_MASTER_SDA_HIGH_SCL_HIGH();
ETS_GPIO_INTR_ENABLE() ;
// ETS_INTR_UNLOCK();
i2c_master_init();
}
/******************************************************************************
* FunctionName : i2c_master_start
* Description : set i2c to send state
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
i2c_master_start(void)
{
i2c_master_setDC(1, m_nLastSCL);
i2c_master_wait(5);
i2c_master_setDC(1, 1);
i2c_master_wait(5); // sda 1, scl 1
i2c_master_setDC(0, 1);
i2c_master_wait(5); // sda 0, scl 1
}
/******************************************************************************
* FunctionName : i2c_master_stop
* Description : set i2c to stop sending state
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
i2c_master_stop(void)
{
i2c_master_wait(5);
i2c_master_setDC(0, m_nLastSCL);
i2c_master_wait(5); // sda 0
i2c_master_setDC(0, 1);
i2c_master_wait(5); // sda 0, scl 1
i2c_master_setDC(1, 1);
i2c_master_wait(5); // sda 1, scl 1
}
/******************************************************************************
* FunctionName : i2c_master_setAck
* Description : set ack to i2c bus as level value
* Parameters : uint8 level - 0 or 1
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
i2c_master_setAck(uint8 level)
{
i2c_master_setDC(m_nLastSDA, 0);
i2c_master_wait(5);
i2c_master_setDC(level, 0);
i2c_master_wait(5); // sda level, scl 0
i2c_master_setDC(level, 1);
i2c_master_wait(8); // sda level, scl 1
i2c_master_setDC(level, 0);
i2c_master_wait(5); // sda level, scl 0
i2c_master_setDC(1, 0);
i2c_master_wait(5);
}
/******************************************************************************
* FunctionName : i2c_master_getAck
* Description : confirm if peer send ack
* Parameters : NONE
* Returns : uint8 - ack value, 0 or 1
*******************************************************************************/
uint8 ICACHE_FLASH_ATTR
i2c_master_getAck(void)
{
uint8 retVal;
i2c_master_setDC(m_nLastSDA, 0);
i2c_master_wait(5);
i2c_master_setDC(1, 0);
i2c_master_wait(5);
i2c_master_setDC(1, 1);
i2c_master_wait(5);
retVal = i2c_master_getDC();
i2c_master_wait(5);
i2c_master_setDC(1, 0);
i2c_master_wait(5);
return retVal;
}
/******************************************************************************
* FunctionName : i2c_master_checkAck
* Description : get dev response
* Parameters : NONE
* Returns : true : get ack ; false : get nack
*******************************************************************************/
bool ICACHE_FLASH_ATTR
i2c_master_checkAck(void)
{
if(i2c_master_getAck()){
return FALSE;
}else{
return TRUE;
}
}
/******************************************************************************
* FunctionName : i2c_master_send_ack
* Description : response ack
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
i2c_master_send_ack(void)
{
i2c_master_setAck(0x0);
}
/******************************************************************************
* FunctionName : i2c_master_send_nack
* Description : response nack
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
i2c_master_send_nack(void)
{
i2c_master_setAck(0x1);
}
/******************************************************************************
* FunctionName : i2c_master_readByte
* Description : read Byte from i2c bus
* Parameters : NONE
* Returns : uint8 - readed value
*******************************************************************************/
uint8 ICACHE_FLASH_ATTR
i2c_master_readByte(void)
{
uint8 retVal = 0;
uint8 k, i;
i2c_master_wait(5);
i2c_master_setDC(m_nLastSDA, 0);
i2c_master_wait(5); // sda 1, scl 0
for (i = 0; i < 8; i++) {
i2c_master_wait(5);
i2c_master_setDC(1, 0);
i2c_master_wait(5); // sda 1, scl 0
i2c_master_setDC(1, 1);
i2c_master_wait(5); // sda 1, scl 1
k = i2c_master_getDC();
i2c_master_wait(5);
if (i == 7) {
i2c_master_wait(3); ////
}
k <<= (7 - i);
retVal |= k;
}
i2c_master_setDC(1, 0);
i2c_master_wait(5); // sda 1, scl 0
return retVal;
}
/******************************************************************************
* FunctionName : i2c_master_writeByte
* Description : write wrdata value(one byte) into i2c
* Parameters : uint8 wrdata - write value
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
i2c_master_writeByte(uint8 wrdata)
{
uint8 dat;
sint8 i;
i2c_master_wait(5);
i2c_master_setDC(m_nLastSDA, 0);
i2c_master_wait(5);
for (i = 7; i >= 0; i--) {
dat = wrdata >> i;
i2c_master_setDC(dat, 0);
i2c_master_wait(5);
i2c_master_setDC(dat, 1);
i2c_master_wait(5);
if (i == 0) {
i2c_master_wait(3); ////
}
i2c_master_setDC(dat, 0);
i2c_master_wait(5);
}
}

View File

@ -1,167 +0,0 @@
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: key.c
*
* Description: key driver, now can use different gpio and install different function
*
* Modification history:
* 2014/5/1, v1.0 create this file.
*******************************************************************************/
#ifdef __ESP8266__
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "mem.h"
#include "platform.h"
#include "gpio.h"
#include "user_interface.h"
#include "driver/key.h"
LOCAL void ICACHE_RAM_ATTR key_intr_handler(void *arg);
/******************************************************************************
* FunctionName : key_init_single
* Description : init single key's gpio and register function
* Parameters : uint8 gpio_id - which gpio to use
* uint32 gpio_name - gpio mux name
* uint32 gpio_func - gpio function
* key_function long_press - long press function, needed to install
* key_function short_press - short press function, needed to install
* Returns : single_key_param - single key parameter, needed by key init
*******************************************************************************/
struct single_key_param *ICACHE_FLASH_ATTR
key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press)
{
struct single_key_param *single_key = (struct single_key_param *)zalloc(sizeof(struct single_key_param));
single_key->gpio_id = gpio_id;
single_key->gpio_name = gpio_name;
single_key->gpio_func = gpio_func;
single_key->long_press = long_press;
single_key->short_press = short_press;
return single_key;
}
/******************************************************************************
* FunctionName : key_init
* Description : init keys
* Parameters : key_param *keys - keys parameter, which inited by key_init_single
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
key_init(struct keys_param *keys)
{
uint8 i;
ETS_GPIO_INTR_ATTACH(key_intr_handler, keys);
ETS_GPIO_INTR_DISABLE();
for (i = 0; i < keys->key_num; i++) {
keys->single_key[i]->key_level = 1;
PIN_FUNC_SELECT(keys->single_key[i]->gpio_name, keys->single_key[i]->gpio_func);
gpio_output_set(0, 0, 0, GPIO_ID_PIN(keys->single_key[i]->gpio_id));
gpio_register_set(GPIO_PIN_ADDR(keys->single_key[i]->gpio_id), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)
| GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE)
| GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));
//clear gpio14 status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(keys->single_key[i]->gpio_id));
//enable interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE);
}
ETS_GPIO_INTR_ENABLE();
}
/******************************************************************************
* FunctionName : key_5s_cb
* Description : long press 5s timer callback
* Parameters : single_key_param *single_key - single key parameter
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
key_5s_cb(struct single_key_param *single_key)
{
os_timer_disarm(&single_key->key_5s);
// low, then restart
if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
if (single_key->long_press) {
single_key->long_press();
}
}
}
/******************************************************************************
* FunctionName : key_50ms_cb
* Description : 50ms timer callback to check it's a real key push
* Parameters : single_key_param *single_key - single key parameter
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
key_50ms_cb(struct single_key_param *single_key)
{
os_timer_disarm(&single_key->key_50ms);
// high, then key is up
if (1 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
os_timer_disarm(&single_key->key_5s);
single_key->key_level = 1;
gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_NEGEDGE);
if (single_key->short_press) {
single_key->short_press();
}
} else {
gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_POSEDGE);
}
}
/******************************************************************************
* FunctionName : key_intr_handler
* Description : key interrupt handler
* Parameters : key_param *keys - keys parameter, which inited by key_init_single
* Returns : none
*******************************************************************************/
LOCAL void
key_intr_handler(void *arg)
{
struct keys_param *keys = arg;
uint8 i;
uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
for (i = 0; i < keys->key_num; i++) {
if (gpio_status & BIT(keys->single_key[i]->gpio_id)) {
//disable interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_DISABLE);
//clear interrupt status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(keys->single_key[i]->gpio_id));
if (keys->single_key[i]->key_level == 1) {
// 5s, restart & enter softap mode
os_timer_disarm(&keys->single_key[i]->key_5s);
os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]);
os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0);
keys->single_key[i]->key_level = 0;
gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE);
} else {
// 50ms, check if this is a real key up
os_timer_disarm(&keys->single_key[i]->key_50ms);
os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]);
os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0);
}
}
}
}
#endif

View File

@ -1,557 +0,0 @@
/*
Adaptation of Paul Stoffregen's One wire library to the NodeMcu
The latest version of this library may be found at:
http://www.pjrc.com/teensy/td_libs_OneWire.html
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Much of the code was inspired by Derek Yerger's code, though I don't
think much of that remains. In any event that was..
(copyleft) 2006 by Derek Yerger - Free to distribute freely.
The CRC code was excerpted and inspired by the Dallas Semiconductor
sample code bearing this copyright.
//---------------------------------------------------------------------------
// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// Except as contained in this notice, the name of Dallas Semiconductor
// shall not be used except as stated in the Dallas Semiconductor
// Branding Policy.
//--------------------------------------------------------------------------
*/
#include "driver/onewire.h"
#include "platform.h"
#include "osapi.h"
#include "esp_misc.h"
#define noInterrupts ets_intr_lock
#define interrupts ets_intr_unlock
#define delayMicroseconds os_delay_us
// 1 for keeping the parasitic power on H
#define owDefaultPower 1
#if ONEWIRE_SEARCH
// global search state
static unsigned char ROM_NO[NUM_OW][8];
static uint8_t LastDiscrepancy[NUM_OW];
static uint8_t LastFamilyDiscrepancy[NUM_OW];
static uint8_t LastDeviceFlag[NUM_OW];
#endif
void onewire_init(uint8_t pin)
{
// pinMode(pin, INPUT);
platform_gpio_mode(pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP);
#if ONEWIRE_SEARCH
onewire_reset_search(pin);
#endif
}
// Perform the onewire reset function. We will wait up to 250uS for
// the bus to come high, if it doesn't then it is broken or shorted
// and we return a 0;
//
// Returns 1 if a device asserted a presence pulse, 0 otherwise.
//
uint8_t onewire_reset(uint8_t pin)
{
uint8_t r;
uint8_t retries = 125;
noInterrupts();
DIRECT_MODE_INPUT(pin);
interrupts();
// wait until the wire is high... just in case
do {
if (--retries == 0) return 0;
delayMicroseconds(2);
} while ( !DIRECT_READ(pin));
noInterrupts();
DIRECT_WRITE_LOW(pin);
DIRECT_MODE_OUTPUT(pin); // drive output low
interrupts();
delayMicroseconds(480);
noInterrupts();
DIRECT_MODE_INPUT(pin); // allow it to float
delayMicroseconds(70);
r = !DIRECT_READ(pin);
interrupts();
delayMicroseconds(410);
return r;
}
//
// Write a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
static void onewire_write_bit(uint8_t pin, uint8_t v)
{
if (v & 1) {
noInterrupts();
DIRECT_WRITE_LOW(pin);
DIRECT_MODE_OUTPUT(pin); // drive output low
delayMicroseconds(10);
DIRECT_WRITE_HIGH(pin); // drive output high
interrupts();
delayMicroseconds(55);
} else {
noInterrupts();
DIRECT_WRITE_LOW(pin);
DIRECT_MODE_OUTPUT(pin); // drive output low
delayMicroseconds(65);
DIRECT_WRITE_HIGH(pin); // drive output high
interrupts();
delayMicroseconds(5);
}
}
//
// Read a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
static uint8_t onewire_read_bit(uint8_t pin)
{
uint8_t r;
noInterrupts();
DIRECT_MODE_OUTPUT(pin);
DIRECT_WRITE_LOW(pin);
delayMicroseconds(3);
DIRECT_MODE_INPUT(pin); // let pin float, pull up will raise
delayMicroseconds(10);
r = DIRECT_READ(pin);
interrupts();
delayMicroseconds(53);
return r;
}
//
// Write a byte. The writing code uses the active drivers to raise the
// pin high, if you need power after the write (e.g. DS18S20 in
// parasite power mode) then set 'power' to 1, otherwise the pin will
// go tri-state at the end of the write to avoid heating in a short or
// other mishap.
//
void onewire_write(uint8_t pin, uint8_t v, uint8_t power /* = 0 */) {
uint8_t bitMask;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
onewire_write_bit(pin, (bitMask & v)?1:0);
}
if ( !power) {
noInterrupts();
DIRECT_MODE_INPUT(pin);
DIRECT_WRITE_LOW(pin);
interrupts();
}
}
void onewire_write_bytes(uint8_t pin, const uint8_t *buf, uint16_t count, bool power /* = 0 */) {
uint16_t i;
for (i = 0 ; i < count ; i++)
onewire_write(pin, buf[i], owDefaultPower);
if (!power) {
noInterrupts();
DIRECT_MODE_INPUT(pin);
DIRECT_WRITE_LOW(pin);
interrupts();
}
}
//
// Read a byte
//
uint8_t onewire_read(uint8_t pin) {
uint8_t bitMask;
uint8_t r = 0;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
if (onewire_read_bit(pin)) r |= bitMask;
}
return r;
}
void onewire_read_bytes(uint8_t pin, uint8_t *buf, uint16_t count) {
uint16_t i;
for (i = 0 ; i < count ; i++)
buf[i] = onewire_read(pin);
}
//
// Do a ROM select
//
void onewire_select(uint8_t pin, const uint8_t rom[8])
{
uint8_t i;
onewire_write(pin, 0x55, owDefaultPower); // Choose ROM
for (i = 0; i < 8; i++) onewire_write(pin, rom[i], owDefaultPower);
}
//
// Do a ROM skip
//
void onewire_skip(uint8_t pin)
{
onewire_write(pin, 0xCC, owDefaultPower); // Skip ROM
}
void onewire_depower(uint8_t pin)
{
noInterrupts();
DIRECT_MODE_INPUT(pin);
interrupts();
}
#if ONEWIRE_SEARCH
//
// You need to use this function to start a search again from the beginning.
// You do not need to do it for the first search, though you could.
//
void onewire_reset_search(uint8_t pin)
{
// reset the search state
LastDiscrepancy[pin] = 0;
LastDeviceFlag[pin] = FALSE;
LastFamilyDiscrepancy[pin] = 0;
int i;
for(i = 7; ; i--) {
ROM_NO[pin][i] = 0;
if ( i == 0) break;
}
}
// Setup the search to find the device type 'family_code' on the next call
// to search(*newAddr) if it is present.
//
void onewire_target_search(uint8_t pin, uint8_t family_code)
{
// set the search state to find SearchFamily type devices
ROM_NO[pin][0] = family_code;
uint8_t i;
for (i = 1; i < 8; i++)
ROM_NO[pin][i] = 0;
LastDiscrepancy[pin] = 64;
LastFamilyDiscrepancy[pin] = 0;
LastDeviceFlag[pin] = FALSE;
}
//
// Perform a search. If this function returns a '1' then it has
// enumerated the next device and you may retrieve the ROM from the
// OneWire::address variable. If there are no devices, no further
// devices, or something horrible happens in the middle of the
// enumeration then a 0 is returned. If a new device is found then
// its address is copied to newAddr. Use OneWire::reset_search() to
// start over.
//
// --- Replaced by the one from the Dallas Semiconductor web site ---
//--------------------------------------------------------------------------
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
// search state.
// Return TRUE : device found, ROM number in ROM_NO buffer
// FALSE : device not found, end of search
//
uint8_t onewire_search(uint8_t pin, uint8_t *newAddr)
{
uint8_t id_bit_number;
uint8_t last_zero, rom_byte_number, search_result;
uint8_t id_bit, cmp_id_bit;
unsigned char rom_byte_mask, search_direction;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = 0;
// if the last call was not the last one
if (!LastDeviceFlag[pin])
{
// 1-Wire reset
if (!onewire_reset(pin))
{
// reset the search
LastDiscrepancy[pin] = 0;
LastDeviceFlag[pin] = FALSE;
LastFamilyDiscrepancy[pin] = 0;
return FALSE;
}
// issue the search command
onewire_write(pin, 0xF0, owDefaultPower);
// loop to do the search
do
{
// read a bit and its complement
id_bit = onewire_read_bit(pin);
cmp_id_bit = onewire_read_bit(pin);
// check for no devices on 1-wire
if ((id_bit == 1) && (cmp_id_bit == 1))
break;
else
{
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit)
search_direction = id_bit; // bit write value for search
else
{
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < LastDiscrepancy[pin])
search_direction = ((ROM_NO[pin][rom_byte_number] & rom_byte_mask) > 0);
else
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == LastDiscrepancy[pin]);
// if 0 was picked then record its position in LastZero
if (search_direction == 0)
{
last_zero = id_bit_number;
// check for Last discrepancy in family
if (last_zero < 9)
LastFamilyDiscrepancy[pin] = last_zero;
}
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction == 1)
ROM_NO[pin][rom_byte_number] |= rom_byte_mask;
else
ROM_NO[pin][rom_byte_number] &= ~rom_byte_mask;
// serial number search direction write bit
onewire_write_bit(pin, search_direction);
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0)
{
rom_byte_number++;
rom_byte_mask = 1;
}
}
}
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!(id_bit_number < 65))
{
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
LastDiscrepancy[pin] = last_zero;
// check for last device
if (LastDiscrepancy[pin] == 0)
LastDeviceFlag[pin] = TRUE;
search_result = TRUE;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !ROM_NO[pin][0])
{
LastDiscrepancy[pin] = 0;
LastDeviceFlag[pin] = FALSE;
LastFamilyDiscrepancy[pin] = 0;
search_result = FALSE;
}
else
{
for (rom_byte_number = 0; rom_byte_number < 8; rom_byte_number++)
{
newAddr[rom_byte_number] = ROM_NO[pin][rom_byte_number];
}
}
return search_result;
}
#endif
#if ONEWIRE_CRC
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
//
#if ONEWIRE_CRC8_TABLE
// This table comes from Dallas sample code where it is freely reusable,
// though Copyright (C) 2000 Dallas Semiconductor Corporation
static const uint8_t dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
#endif
//
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers. (note: this might better be done without to
// table, it would probably be smaller and certainly fast enough
// compared to all those delayMicrosecond() calls. But I got
// confused, so I use this table from the examples.)
//
uint8_t onewire_crc8(const uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
}
return crc;
}
#else
//
// Compute a Dallas Semiconductor 8 bit CRC directly.
// this is much slower, but much smaller, than the lookup table.
//
uint8_t onewire_crc8(const uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *addr++;
uint8_t i;
for (i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
#endif
#if ONEWIRE_CRC16
// Compute the 1-Wire CRC16 and compare it against the received CRC.
// Example usage (reading a DS2408):
// // Put everything in a buffer so we can compute the CRC easily.
// uint8_t buf[13];
// buf[0] = 0xF0; // Read PIO Registers
// buf[1] = 0x88; // LSB address
// buf[2] = 0x00; // MSB address
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
// if (!CheckCRC16(buf, 11, &buf[11])) {
// // Handle error.
// }
//
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param inverted_crc - The two CRC16 bytes in the received data.
// This should just point into the received data,
// *not* at a 16-bit integer.
// @param crc - The crc starting value (optional)
// @return True, iff the CRC matches.
bool onewire_check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc)
{
crc = ~onewire_crc16(input, len, crc);
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
}
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
// the integrity of data received from many 1-Wire devices. Note that the
// CRC computed here is *not* what you'll get from the 1-Wire network,
// for two reasons:
// 1) The CRC is transmitted bitwise inverted.
// 2) Depending on the endian-ness of your processor, the binary
// representation of the two-byte return value may have a different
// byte order than the two bytes you get from 1-Wire.
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param crc - The crc starting value (optional)
// @return The CRC16, as defined by Dallas Semiconductor.
uint16_t onewire_crc16(const uint8_t* input, uint16_t len, uint16_t crc)
{
static const uint8_t oddparity[16] =
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
uint16_t i;
for (i = 0 ; i < len ; i++) {
// Even though we're just copying a byte from the input,
// we'll be doing 16-bit computation with it.
uint16_t cdata = input[i];
cdata = (cdata ^ crc) & 0xff;
crc >>= 8;
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
crc ^= 0xC001;
cdata <<= 6;
crc ^= cdata;
cdata <<= 1;
crc ^= cdata;
}
return crc;
}
#endif
#endif

View File

@ -1,471 +0,0 @@
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: pwm.c
*
* Description: pwm driver
*
* Modification history:
* 2014/5/1, v1.0 create this file.
*******************************************************************************/
// ESP32 has own pwm driver in libdriver.a
#ifdef __ESP8266__
#include "platform.h"
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "gpio.h"
#include "hw_timer.h"
#include "esp_misc.h"
#include "user_interface.h"
#include "driver/pwm.h"
// #define PWM_DBG os_printf
#define PWM_DBG
// Enabling the next line will cause the interrupt handler to toggle
// this output pin during processing so that the timing is obvious
//
// #define PWM_DBG_PIN 13 // GPIO7
#ifdef PWM_DBG_PIN
#define PWM_DBG_PIN_HIGH() GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << PWM_DBG_PIN)
#define PWM_DBG_PIN_LOW() GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << PWM_DBG_PIN)
#else
#define PWM_DBG_PIN_HIGH()
#define PWM_DBG_PIN_LOW()
#endif
LOCAL struct pwm_single_param pwm_single_toggle[2][PWM_CHANNEL + 1];
LOCAL struct pwm_single_param *pwm_single;
LOCAL struct pwm_param pwm;
// LOCAL uint8 pwm_out_io_num[PWM_CHANNEL] = {PWM_0_OUT_IO_NUM, PWM_1_OUT_IO_NUM, PWM_2_OUT_IO_NUM};
LOCAL int8 pwm_out_io_num[PWM_CHANNEL] = {-1, -1, -1, -1, -1, -1};
LOCAL uint8 pwm_channel_toggle[2];
LOCAL uint8 *pwm_channel;
// Toggle flips between 1 and 0 when we make updates so that the interrupt code
// cn switch cleanly between the two states. The cinterrupt handler uses either
// the pwm_single_toggle[0] or pwm_single_toggle[1]
// pwm_toggle indicates which state should be used on the *next* timer interrupt
// freq boundary.
LOCAL uint8 pwm_toggle = 1;
LOCAL volatile uint8 pwm_current_toggle = 1;
LOCAL uint8 pwm_timer_down = 1;
LOCAL uint8 pwm_current_channel = 0;
LOCAL uint16 pwm_gpio = 0;
LOCAL uint8 pwm_channel_num = 0;
LOCAL void ICACHE_RAM_ATTR pwm_tim1_intr_handler(uint32_t p);
#define TIMER_OWNER ((uint32_t) 'P')
LOCAL void ICACHE_FLASH_ATTR
pwm_insert_sort(struct pwm_single_param pwm[], uint8 n)
{
uint8 i;
for (i = 1; i < n; i++) {
if (pwm[i].h_time < pwm[i - 1].h_time) {
int8 j = i - 1;
struct pwm_single_param tmp;
os_memcpy(&tmp, &pwm[i], sizeof(struct pwm_single_param));
while (tmp.h_time < pwm[j].h_time) {
os_memcpy(&pwm[j + 1], &pwm[j], sizeof(struct pwm_single_param));
j--;
if (j < 0) {
break;
}
}
os_memcpy(&pwm[j + 1], &tmp, sizeof(struct pwm_single_param));
}
}
}
// Returns FALSE if we cannot start
bool ICACHE_FLASH_ATTR
pwm_start(void)
{
uint8 i, j;
PWM_DBG("--Function pwm_start() is called\n");
PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num);
PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);
PWM_DBG("pwm.period:%d,pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.period,pwm.duty[0],pwm.duty[1],pwm.duty[2]);
// First we need to make sure that the interrupt handler is running
// out of the same set of params as we expect
while (!pwm_timer_down && pwm_toggle != pwm_current_toggle) {
os_delay_us(100);
}
if (pwm_timer_down) {
pwm_toggle = pwm_current_toggle;
}
uint8_t new_toggle = pwm_toggle ^ 0x01;
struct pwm_single_param *local_single = pwm_single_toggle[new_toggle];
uint8 *local_channel = &pwm_channel_toggle[new_toggle];
// step 1: init PWM_CHANNEL+1 channels param
for (i = 0; i < pwm_channel_num; i++) {
uint32 us = pwm.period * pwm.duty[i] / PWM_DEPTH;
local_single[i].h_time = US_TO_RTC_TIMER_TICKS(us);
PWM_DBG("i:%d us:%d ht:%d\n",i,us,local_single[i].h_time);
local_single[i].gpio_set = 0;
local_single[i].gpio_clear = 1 << pin_num[pwm_out_io_num[i]];
}
local_single[pwm_channel_num].h_time = US_TO_RTC_TIMER_TICKS(pwm.period);
local_single[pwm_channel_num].gpio_set = pwm_gpio;
local_single[pwm_channel_num].gpio_clear = 0;
PWM_DBG("i:%d period:%d ht:%d\n",pwm_channel_num,pwm.period,local_single[pwm_channel_num].h_time);
// step 2: sort, small to big
pwm_insert_sort(local_single, pwm_channel_num + 1);
*local_channel = pwm_channel_num + 1;
PWM_DBG("1channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);
// step 3: combine same duty channels (or nearly the same duty). If there is
// under 2 us between pwm outputs, then treat them as the same.
for (i = pwm_channel_num; i > 0; i--) {
if (local_single[i].h_time <= local_single[i - 1].h_time + US_TO_RTC_TIMER_TICKS(2)) {
local_single[i - 1].gpio_set |= local_single[i].gpio_set;
local_single[i - 1].gpio_clear |= local_single[i].gpio_clear;
for (j = i + 1; j < *local_channel; j++) {
os_memcpy(&local_single[j - 1], &local_single[j], sizeof(struct pwm_single_param));
}
(*local_channel)--;
}
}
PWM_DBG("2channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);
// step 4: cacl delt time
for (i = *local_channel - 1; i > 0; i--) {
local_single[i].h_time -= local_single[i - 1].h_time;
}
// step 5: last channel needs to clean
local_single[*local_channel-1].gpio_clear = 0;
// step 6: if first channel duty is 0, remove it
if (local_single[0].h_time == 0) {
local_single[*local_channel - 1].gpio_set &= ~local_single[0].gpio_clear;
local_single[*local_channel - 1].gpio_clear |= local_single[0].gpio_clear;
for (i = 1; i < *local_channel; i++) {
os_memcpy(&local_single[i - 1], &local_single[i], sizeof(struct pwm_single_param));
}
(*local_channel)--;
}
// Make the new ones active
pwm_toggle = new_toggle;
// if timer is down, need to set gpio and start timer
if (pwm_timer_down == 1) {
pwm_channel = local_channel;
pwm_single = local_single;
pwm_current_toggle = pwm_toggle;
// start
gpio_output_set(local_single[0].gpio_set, local_single[0].gpio_clear, pwm_gpio, 0);
// yeah, if all channels' duty is 0 or 255, don't need to start timer, otherwise start...
if (*local_channel != 1) {
PWM_DBG("Need to setup timer\n");
if (!platform_hw_timer_init(TIMER_OWNER, NMI_SOURCE, FALSE)) {
return FALSE;
}
pwm_timer_down = 0;
platform_hw_timer_set_func(TIMER_OWNER, pwm_tim1_intr_handler, 0);
platform_hw_timer_arm_ticks(TIMER_OWNER, local_single[0].h_time);
} else {
PWM_DBG("Timer left idle\n");
platform_hw_timer_close(TIMER_OWNER);
}
} else {
// ensure that all outputs are outputs
gpio_output_set(0, 0, pwm_gpio, 0);
}
#ifdef PWM_DBG_PIN
// Enable as output
gpio_output_set(0, 0, 1 << PWM_DBG_PIN, 0);
#endif
PWM_DBG("3channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);
return TRUE;
}
/******************************************************************************
* FunctionName : pwm_set_duty
* Description : set each channel's duty params
* Parameters : uint8 duty : 0 ~ PWM_DEPTH
* uint8 channel : channel index
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
pwm_set_duty(uint16 duty, uint8 channel)
{
uint8 i;
for(i=0;i<pwm_channel_num;i++){
if(pwm_out_io_num[i] == channel){
channel = i;
break;
}
}
if(i==pwm_channel_num) // non found
return;
if (duty < 1) {
pwm.duty[channel] = 0;
} else if (duty >= PWM_DEPTH) {
pwm.duty[channel] = PWM_DEPTH;
} else {
pwm.duty[channel] = duty;
}
}
/******************************************************************************
* FunctionName : pwm_set_freq
* Description : set pwm frequency
* Parameters : uint16 freq : 100hz typically
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
pwm_set_freq(uint16 freq, uint8 channel)
{
if (freq > PWM_FREQ_MAX) {
pwm.freq = PWM_FREQ_MAX;
} else if (freq < 1) {
pwm.freq = 1;
} else {
pwm.freq = freq;
}
pwm.period = PWM_1S / pwm.freq;
}
/******************************************************************************
* FunctionName : pwm_set_freq_duty
* Description : set pwm frequency and each channel's duty
* Parameters : uint16 freq : 100hz typically
* uint16 *duty : each channel's duty
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
pwm_set_freq_duty(uint16 freq, uint16 *duty)
{
uint8 i;
pwm_set_freq(freq, 0);
for (i = 0; i < PWM_CHANNEL; i++) {
// pwm_set_duty(duty[i], i);
if(pwm_out_io_num[i] != -1)
pwm_set_duty(duty[i], pwm_out_io_num[i]);
}
}
/******************************************************************************
* FunctionName : pwm_get_duty
* Description : get duty of each channel
* Parameters : uint8 channel : channel index
* Returns : NONE
*******************************************************************************/
uint16 ICACHE_FLASH_ATTR
pwm_get_duty(uint8 channel)
{
uint8 i;
for(i=0;i<pwm_channel_num;i++){
if(pwm_out_io_num[i] == channel){
channel = i;
break;
}
}
if(i==pwm_channel_num) // non found
return 0;
return pwm.duty[channel];
}
/******************************************************************************
* FunctionName : pwm_get_freq
* Description : get pwm frequency
* Parameters : NONE
* Returns : uint16 : pwm frequency
*******************************************************************************/
uint16 ICACHE_FLASH_ATTR
pwm_get_freq(uint8 channel)
{
return pwm.freq;
}
/******************************************************************************
* FunctionName : pwm_period_timer
* Description : pwm period timer function, output high level,
* start each channel's high level timer
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_RAM_ATTR
pwm_tim1_intr_handler(uint32_t p)
{
(void)p;
PWM_DBG_PIN_HIGH();
int offset = 0;
while (1) {
if (pwm_current_channel >= (*pwm_channel - 1)) {
pwm_single = pwm_single_toggle[pwm_toggle];
pwm_channel = &pwm_channel_toggle[pwm_toggle];
pwm_current_toggle = pwm_toggle;
gpio_output_set(pwm_single[*pwm_channel - 1].gpio_set,
pwm_single[*pwm_channel - 1].gpio_clear,
0,
0);
pwm_current_channel = 0;
if (*pwm_channel == 1) {
pwm_timer_down = 1;
break;
}
} else {
gpio_output_set(pwm_single[pwm_current_channel].gpio_set,
pwm_single[pwm_current_channel].gpio_clear,
0, 0);
pwm_current_channel++;
}
int next_time = pwm_single[pwm_current_channel].h_time;
// Delay now holds the time (in ticks) since when the last timer expiry was
PWM_DBG_PIN_LOW();
int delay = platform_hw_timer_get_delay_ticks(TIMER_OWNER) + 4 - offset;
offset += next_time;
next_time = next_time - delay;
if (next_time > US_TO_RTC_TIMER_TICKS(4)) {
PWM_DBG_PIN_HIGH();
platform_hw_timer_arm_ticks(TIMER_OWNER, next_time);
break;
}
PWM_DBG_PIN_HIGH();
}
PWM_DBG_PIN_LOW();
}
/******************************************************************************
* FunctionName : pwm_init
* Description : pwm gpio, params and timer initialization
* Parameters : uint16 freq : pwm freq param
* uint16 *duty : each channel's duty
* Returns : void
*******************************************************************************/
void ICACHE_FLASH_ATTR
pwm_init(uint16 freq, uint16 *duty)
{
uint8 i;
// PIN_FUNC_SELECT(PWM_0_OUT_IO_MUX, PWM_0_OUT_IO_FUNC);
// PIN_FUNC_SELECT(PWM_1_OUT_IO_MUX, PWM_1_OUT_IO_FUNC);
// PIN_FUNC_SELECT(PWM_2_OUT_IO_MUX, PWM_2_OUT_IO_FUNC);
// GPIO_OUTPUT_SET(GPIO_ID_PIN(PWM_0_OUT_IO_NUM), 0);
// GPIO_OUTPUT_SET(GPIO_ID_PIN(PWM_1_OUT_IO_NUM), 0);
// GPIO_OUTPUT_SET(GPIO_ID_PIN(PWM_2_OUT_IO_NUM), 0);
for (i = 0; i < PWM_CHANNEL; i++) {
// pwm_gpio |= (1 << pwm_out_io_num[i]);
pwm_gpio = 0;
pwm.duty[i] = 0;
}
pwm_set_freq(500, 0);
// pwm_set_freq_duty(freq, duty);
pwm_start();
PWM_DBG("pwm_init returning\n");
}
bool ICACHE_FLASH_ATTR
pwm_add(uint8 channel){
PWM_DBG("--Function pwm_add() is called. channel:%d\n", channel);
PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num);
PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);
PWM_DBG("pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.duty[0],pwm.duty[1],pwm.duty[2]);
uint8 i;
for(i=0;i<PWM_CHANNEL;i++){
if(pwm_out_io_num[i]==channel) // already exist
return true;
if(pwm_out_io_num[i] == -1){ // empty exist
pwm_out_io_num[i] = channel;
pwm.duty[i] = 0;
pwm_gpio |= (1 << pin_num[channel]);
PIN_FUNC_SELECT(pin_mux[channel], pin_func[channel]);
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[channel])), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[channel]))) & (~ GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); //disable open drain;
pwm_channel_num++;
return true;
}
}
return false;
}
bool ICACHE_FLASH_ATTR
pwm_delete(uint8 channel){
PWM_DBG("--Function pwm_delete() is called. channel:%d\n", channel);
PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num);
PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);
PWM_DBG("pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.duty[0],pwm.duty[1],pwm.duty[2]);
uint8 i,j;
for(i=0;i<pwm_channel_num;i++){
if(pwm_out_io_num[i]==channel){ // exist
pwm_out_io_num[i] = -1;
pwm_gpio &= ~(1 << pin_num[channel]); //clear the bit
for(j=i;j<pwm_channel_num-1;j++){
pwm_out_io_num[j] = pwm_out_io_num[j+1];
pwm.duty[j] = pwm.duty[j+1];
}
pwm_out_io_num[pwm_channel_num-1] = -1;
pwm.duty[pwm_channel_num-1] = 0;
pwm_channel_num--;
return true;
}
}
// non found
return true;
}
bool ICACHE_FLASH_ATTR
pwm_exist(uint8 channel){
PWM_DBG("--Function pwm_exist() is called. channel:%d\n", channel);
PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num);
PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);
PWM_DBG("pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.duty[0],pwm.duty[1],pwm.duty[2]);
uint8 i;
for(i=0;i<PWM_CHANNEL;i++){
if(pwm_out_io_num[i]==channel) // exist
return true;
}
return false;
}
#endif

View File

@ -1,323 +0,0 @@
/*
* Driver for interfacing to cheap rotary switches that
* have a quadrature output with an optional press button
*
* This sets up the relevant gpio as interrupt and then keeps track of
* the position of the switch in software. Changes are enqueued to task
* level and a task message posted when required. If the queue fills up
* then moves are ignored, but the last press/release will be included.
*
* Philip Gladstone, N1DQ
*/
#ifdef __ESP8266__
#include "platform.h"
#include "c_types.h"
#include <stdlib.h>
#include <stdio.h>
#include "driver/rotary.h"
#include "user_interface.h"
#include "esp_system.h"
#include "task/task.h"
#include "ets_sys.h"
//
// Queue is empty if read == write.
// However, we always want to keep the previous value
// so writing is only allowed if write - read < QUEUE_SIZE - 1
#define QUEUE_SIZE 8
#define GET_LAST_STATUS(d) (d->queue[(d->write_offset-1) & (QUEUE_SIZE - 1)])
#define GET_PREV_STATUS(d) (d->queue[(d->write_offset-2) & (QUEUE_SIZE - 1)])
#define HAS_QUEUED_DATA(d) (d->read_offset < d->write_offset)
#define HAS_QUEUE_SPACE(d) (d->read_offset + QUEUE_SIZE - 1 > d->write_offset)
#define REPLACE_STATUS(d, x) (d->queue[(d->write_offset-1) & (QUEUE_SIZE - 1)] = (rotary_event_t) { (x), system_get_time() })
#define QUEUE_STATUS(d, x) (d->queue[(d->write_offset++) & (QUEUE_SIZE - 1)] = (rotary_event_t) { (x), system_get_time() })
#define GET_READ_STATUS(d) (d->queue[d->read_offset & (QUEUE_SIZE - 1)])
#define ADVANCE_IF_POSSIBLE(d) if (d->read_offset < d->write_offset) { d->read_offset++; }
#define STATUS_IS_PRESSED(x) ((x & 0x80000000) != 0)
typedef struct {
int8_t phase_a_pin;
int8_t phase_b_pin;
int8_t press_pin;
uint32_t read_offset; // Accessed by task
uint32_t write_offset; // Accessed by ISR
uint32_t pin_mask;
uint32_t phase_a;
uint32_t phase_b;
uint32_t press;
uint32_t last_press_change_time;
int tasknumber;
rotary_event_t queue[QUEUE_SIZE];
} DATA;
static DATA *data[ROTARY_CHANNEL_COUNT];
static uint8_t task_queued;
static void set_gpio_bits(void);
static void rotary_clear_pin(int pin)
{
if (pin >= 0) {
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), GPIO_PIN_INTR_DISABLE);
platform_gpio_mode(pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP);
}
}
// Just takes the channel number. Cleans up the resources used.
int rotary_close(uint32_t channel)
{
if (channel >= sizeof(data) / sizeof(data[0])) {
return -1;
}
DATA *d = data[channel];
if (!d) {
return 0;
}
data[channel] = NULL;
rotary_clear_pin(d->phase_a_pin);
rotary_clear_pin(d->phase_b_pin);
rotary_clear_pin(d->press_pin);
free(d);
set_gpio_bits();
return 0;
}
static uint32_t ICACHE_RAM_ATTR rotary_interrupt(uint32_t ret_gpio_status)
{
// This function really is running at interrupt level with everything
// else masked off. It should take as little time as necessary.
//
//
// This gets the set of pins which have changed status
uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
int i;
for (i = 0; i < sizeof(data) / sizeof(data[0]); i++) {
DATA *d = data[i];
if (!d || (gpio_status & d->pin_mask) == 0) {
continue;
}
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & d->pin_mask);
uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS);
uint32_t last_status = GET_LAST_STATUS(d).pos;
uint32_t now = system_get_time();
uint32_t new_status;
new_status = last_status & 0x80000000;
// This is the debounce logic for the press switch. We ignore changes
// for 10ms after a change.
if (now - d->last_press_change_time > 10 * 1000) {
new_status = (bits & d->press) ? 0 : 0x80000000;
if (STATUS_IS_PRESSED(new_status ^ last_status)) {
d->last_press_change_time = now;
}
}
// A B
// 1 1 => 0
// 1 0 => 1
// 0 0 => 2
// 0 1 => 3
int micropos = 2;
if (bits & d->phase_b) {
micropos = 3;
}
if (bits & d->phase_a) {
micropos ^= 3;
}
int32_t rotary_pos = last_status;
switch ((micropos - last_status) & 3) {
case 0:
// No change, nothing to do
break;
case 1:
// Incremented by 1
rotary_pos++;
break;
case 3:
// Decremented by 1
rotary_pos--;
break;
default:
// We missed an interrupt
// We will ignore... but mark it.
rotary_pos += 1000000;
break;
}
new_status |= rotary_pos & 0x7fffffff;
if (last_status != new_status) {
// Either we overwrite the status or we add a new one
if (!HAS_QUEUED_DATA(d)
|| STATUS_IS_PRESSED(last_status ^ new_status)
|| STATUS_IS_PRESSED(last_status ^ GET_PREV_STATUS(d).pos)) {
if (HAS_QUEUE_SPACE(d)) {
QUEUE_STATUS(d, new_status);
if (!task_queued) {
if (task_post_medium(d->tasknumber, (task_param_t) &task_queued)) {
task_queued = 1;
}
}
} else {
REPLACE_STATUS(d, new_status);
}
} else {
REPLACE_STATUS(d, new_status);
}
}
ret_gpio_status &= ~(d->pin_mask);
}
return ret_gpio_status;
}
// The pin numbers are actual platform GPIO numbers
int rotary_setup(uint32_t channel, int phase_a, int phase_b, int press, task_handle_t tasknumber )
{
if (channel >= sizeof(data) / sizeof(data[0])) {
return -1;
}
if (data[channel]) {
if (rotary_close(channel)) {
return -1;
}
}
DATA *d = (DATA *) zalloc(sizeof(DATA));
if (!d) {
return -1;
}
data[channel] = d;
int i;
d->tasknumber = tasknumber;
d->phase_a = 1 << pin_num[phase_a];
platform_gpio_mode(phase_a, PLATFORM_GPIO_INT, PLATFORM_GPIO_PULLUP);
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[phase_a]), GPIO_PIN_INTR_ANYEDGE);
d->phase_a_pin = phase_a;
d->phase_b = 1 << pin_num[phase_b];
platform_gpio_mode(phase_b, PLATFORM_GPIO_INT, PLATFORM_GPIO_PULLUP);
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[phase_b]), GPIO_PIN_INTR_ANYEDGE);
d->phase_b_pin = phase_b;
if (press >= 0) {
d->press = 1 << pin_num[press];
platform_gpio_mode(press, PLATFORM_GPIO_INT, PLATFORM_GPIO_PULLUP);
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[press]), GPIO_PIN_INTR_ANYEDGE);
}
d->press_pin = press;
d->pin_mask = d->phase_a | d->phase_b | d->press;
set_gpio_bits();
return 0;
}
static void set_gpio_bits()
{
uint32_t bits = 0;
for (int i = 0; i < ROTARY_CHANNEL_COUNT; i++) {
DATA *d = data[i];
if (d) {
bits = bits | d->pin_mask;
}
}
platform_gpio_register_intr_hook(bits, rotary_interrupt);
}
bool rotary_has_queued_event(uint32_t channel)
{
if (channel >= sizeof(data) / sizeof(data[0])) {
return FALSE;
}
DATA *d = data[channel];
if (!d) {
return FALSE;
}
return HAS_QUEUED_DATA(d);
}
// Get the oldest event in the queue and remove it (if possible)
bool rotary_getevent(uint32_t channel, rotary_event_t *resultp)
{
rotary_event_t result = { 0 };
if (channel >= sizeof(data) / sizeof(data[0])) {
return FALSE;
}
DATA *d = data[channel];
if (!d) {
return FALSE;
}
ETS_GPIO_INTR_DISABLE();
bool status = FALSE;
if (HAS_QUEUED_DATA(d)) {
result = GET_READ_STATUS(d);
d->read_offset++;
status = TRUE;
} else {
result = GET_LAST_STATUS(d);
}
ETS_GPIO_INTR_ENABLE();
*resultp = result;
return status;
}
int rotary_getpos(uint32_t channel)
{
if (channel >= sizeof(data) / sizeof(data[0])) {
return -1;
}
DATA *d = data[channel];
if (!d) {
return -1;
}
return GET_LAST_STATUS(d).pos;
}
#endif

View File

@ -1,38 +0,0 @@
/* Sigma-delta only on the ESP8266 */
#ifdef __ESP8266__
#include "driver/sigma_delta.h"
#include "esp8266/gpio_register.h"
void sigma_delta_setup( void )
{
GPIO_REG_WRITE(GPIO_SIGMA_DELTA,
GPIO_SIGMA_DELTA_SET(GPIO_SIGMA_DELTA_ENABLE) |
GPIO_SIGMA_DELTA_TARGET_SET(0x00) |
GPIO_SIGMA_DELTA_PRESCALE_SET(0x00));
}
void sigma_delta_stop( void )
{
GPIO_REG_WRITE(GPIO_SIGMA_DELTA,
GPIO_SIGMA_DELTA_SET(GPIO_SIGMA_DELTA_DISABLE) |
GPIO_SIGMA_DELTA_TARGET_SET(0x00) |
GPIO_SIGMA_DELTA_PRESCALE_SET(0x00) );
}
void sigma_delta_set_prescale_target( sint16 prescale, sint16 target )
{
uint32_t prescale_mask, target_mask;
prescale_mask = prescale >= 0 ? GPIO_SIGMA_DELTA_PRESCALE_MASK : 0x00;
target_mask = target >= 0 ? GPIO_SIGMA_DELTA_TARGET_MASK : 0x00;
// set prescale and target with one register access to avoid glitches
GPIO_REG_WRITE(GPIO_SIGMA_DELTA,
(GPIO_REG_READ(GPIO_SIGMA_DELTA) & ~(prescale_mask | target_mask)) |
(GPIO_SIGMA_DELTA_PRESCALE_SET(prescale) & prescale_mask) |
(GPIO_SIGMA_DELTA_TARGET_SET(target) & target_mask));
}
#endif

View File

@ -1,681 +0,0 @@
#ifdef __ESP8266__
#include "driver/spi.h"
#include "platform.h"
/******************************************************************************
* FunctionName : spi_lcd_mode_init
* Description : SPI master initial function for driving LCD TM035PDZV36
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
*******************************************************************************/
void spi_lcd_mode_init(uint8 spi_no)
{
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
//bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock
//bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock
if(spi_no==SPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005); //clear bit9,and bit8
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode
}else if(spi_no==HSPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode
}
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND);
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);
// SPI clock=CPU clock/8
WRITE_PERI_REG(SPI_CLOCK(spi_no),
((1&SPI_CLKDIV_PRE)<<SPI_CLKDIV_PRE_S)|
((3&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
((1&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
}
/******************************************************************************
* FunctionName : spi_lcd_9bit_write
* Description : SPI 9bits transmission function for driving LCD TM035PDZV36
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint8 high_bit - first high bit of the data, 0 is for "0",the other value 1-255 is for "1"
* uint8 low_8bit- the rest 8bits of the data.
*******************************************************************************/
void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit)
{
uint32 regvalue;
uint8 bytetemp;
if(spi_no>1) return; //handle invalid input number
if(high_bit) bytetemp=(low_8bit>>1)|0x80;
else bytetemp=(low_8bit>>1)&0x7f;
regvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp); //configure transmission variable,9bit transmission length and first 8 command bit
if(low_8bit&0x01) regvalue|=BIT15; //write the 9th bit
while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); //waiting for spi module available
WRITE_PERI_REG(SPI_USER2(spi_no), regvalue); //write command and command length into spi reg
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); //transmission start
}
/******************************************************************************
* FunctionName : spi_master_init
* Description : SPI master initial function for common byte units transmission
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
*******************************************************************************/
void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_div)
{
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER|SPI_DOUTDIN);
// set clock polarity (Reference: http://bbs.espressif.com/viewtopic.php?f=49&t=1570)
// phase is dependent on polarity. See Issue #1161
if (cpol == 1) {
SET_PERI_REG_MASK(SPI_PIN(spi_no), SPI_IDLE_EDGE);
} else {
CLEAR_PERI_REG_MASK(SPI_PIN(spi_no), SPI_IDLE_EDGE);
}
//set clock phase
if (cpha == cpol) {
// Mode 3: MOSI is set on falling edge of clock
// Mode 0: MOSI is set on falling edge of clock
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE);
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_I_EDGE);
} else {
// Mode 2: MOSI is set on rising edge of clock
// Mode 1: MOSI is set on rising edge of clock
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE);
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_I_EDGE);
}
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE|SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY);
//clear Dual or Quad lines transmission mode
CLEAR_PERI_REG_MASK(SPI_CTRL(spi_no), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE);
// SPI clock = CPU clock / clock_div
// the divider needs to be a multiple of 2 to get a proper waveform shape
if ((clock_div & 0x01) != 0) {
// bump the divider to the next N*2
clock_div += 0x02;
}
clock_div >>= 1;
// clip to maximum possible CLKDIV_PRE
clock_div = clock_div > SPI_CLKDIV_PRE ? SPI_CLKDIV_PRE : clock_div - 1;
WRITE_PERI_REG(SPI_CLOCK(spi_no),
((clock_div&SPI_CLKDIV_PRE)<<SPI_CLKDIV_PRE_S)|
((1&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
((0&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
((1&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
if(spi_no==SPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode
}
else if(spi_no==HSPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode
}
}
/******************************************************************************
* FunctionName : spi_mast_set_mosi
* Description : Enter provided data into MOSI buffer.
* The data is regarded as a sequence of bits with length 'bitlen'.
* It will be written left-aligned starting from position 'offset'.
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint16 offset - offset into MOSI buffer (number of bits)
* uint8 bitlen - valid number of bits in data
* uint32 data - data to be written into buffer
*******************************************************************************/
void spi_mast_set_mosi(uint8 spi_no, uint16 offset, uint8 bitlen, uint32 data)
{
uint8 wn, wn_offset, wn_bitlen;
uint32 wn_data;
if (spi_no > 1)
return; // handle invalid input number
if (bitlen > 32)
return; // handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// determine which SPI_Wn register is addressed
wn = offset >> 5;
if (wn > 15)
return; // out of range
wn_offset = offset & 0x1f;
if (32 - wn_offset < bitlen)
{
// splitting required
wn_bitlen = 32 - wn_offset;
wn_data = data >> (bitlen - wn_bitlen);
}
else
{
wn_bitlen = bitlen;
wn_data = data;
}
do
{
// write payload data to SPI_Wn
SET_PERI_REG_BITS(REG_SPI_BASE(spi_no) +0x40 + wn*4, BIT(wn_bitlen) - 1, wn_data, 32 - (wn_offset + wn_bitlen));
// prepare writing of dangling data part
wn += 1;
wn_offset = 0;
if (wn <= 15)
bitlen -= wn_bitlen;
else
bitlen = 0; // force abort
wn_bitlen = bitlen;
wn_data = data;
} while (bitlen > 0);
return;
}
/******************************************************************************
* FunctionName : spi_mast_get_miso
* Description : Retrieve data from MISO buffer.
* The data is regarded as a sequence of bits with length 'bitlen'.
* It will be read starting left-aligned from position 'offset'.
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint16 offset - offset into MISO buffer (number of bits)
* uint8 bitlen - requested number of bits in data
*******************************************************************************/
uint32 spi_mast_get_miso(uint8 spi_no, uint16 offset, uint8 bitlen)
{
uint8 wn, wn_offset, wn_bitlen;
uint32 wn_data = 0;
if (spi_no > 1)
return 0; // handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// determine which SPI_Wn register is addressed
wn = offset >> 5;
if (wn > 15)
return 0; // out of range
wn_offset = offset & 0x1f;
if (bitlen > (32 - wn_offset))
{
// splitting required
wn_bitlen = 32 - wn_offset;
}
else
{
wn_bitlen = bitlen;
}
do
{
wn_data |= (READ_PERI_REG(REG_SPI_BASE(spi_no) +0x40 + wn*4) >> (32 - (wn_offset + wn_bitlen))) & (BIT(wn_bitlen) - 1);
// prepare reading of dangling data part
wn_data <<= bitlen - wn_bitlen;
wn += 1;
wn_offset = 0;
if (wn <= 15)
bitlen -= wn_bitlen;
else
bitlen = 0; // force abort
wn_bitlen = bitlen;
} while (bitlen > 0);
return wn_data;
}
/******************************************************************************
* FunctionName : spi_mast_transaction
* Description : Start a transaction and wait for completion.
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint8 cmd_bitlen - Valid number of bits in cmd_data.
* uint16 cmd_data - Command data.
* uint8 addr_bitlen - Valid number of bits in addr_data.
* uint32 addr_data - Address data.
* uint16 mosi_bitlen - Valid number of bits in MOSI buffer.
* uint8 dummy_bitlen - Number of dummy cycles.
* sint16 miso_bitlen - number of bits to be captured in MISO buffer.
* negative value activates full-duplex mode.
*******************************************************************************/
void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8 addr_bitlen, uint32 addr_data,
uint16 mosi_bitlen, uint8 dummy_bitlen, sint16 miso_bitlen)
{
if (spi_no > 1)
return; // handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// default disable COMMAND, ADDR, MOSI, DUMMY, MISO, and DOUTDIN (aka full-duplex)
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND|SPI_USR_ADDR|SPI_USR_MOSI|SPI_USR_DUMMY|SPI_USR_MISO|SPI_DOUTDIN);
// default set bit lengths
WRITE_PERI_REG(SPI_USER1(spi_no),
((addr_bitlen - 1) & SPI_USR_ADDR_BITLEN) << SPI_USR_ADDR_BITLEN_S |
((mosi_bitlen - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S |
((dummy_bitlen - 1) & SPI_USR_DUMMY_CYCLELEN) << SPI_USR_DUMMY_CYCLELEN_S |
((miso_bitlen - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S);
// handle the transaction components
if (cmd_bitlen > 0)
{
uint16 cmd = cmd_data << (16 - cmd_bitlen); // align to MSB
cmd = (cmd >> 8) | (cmd << 8); // swap byte order
WRITE_PERI_REG(SPI_USER2(spi_no),
((cmd_bitlen - 1 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) |
(cmd & SPI_USR_COMMAND_VALUE));
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND);
}
if (addr_bitlen > 0)
{
WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data << (32 - addr_bitlen));
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR);
}
if (mosi_bitlen > 0)
{
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
}
if (dummy_bitlen > 0)
{
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY);
}
if (miso_bitlen > 0)
{
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);
}
else if (miso_bitlen < 0)
{
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN);
}
// start transaction
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
}
/******************************************************************************
* FunctionName : spi_byte_write_espslave
* Description : SPI master 1 byte transmission function for esp8266 slave,
* transmit 1byte data to esp8266 slave buffer needs 16bit transmission ,
* first byte is command 0x04 to write slave buffer, second byte is data
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint8 data- transmitted data
*******************************************************************************/
void spi_byte_write_espslave(uint8 spi_no,uint8 data)
{
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_DUMMY);
//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
// bit15-0 is cmd value.
//0x70000000 is for 8bits cmd, 0x04 is eps8266 slave write cmd value
WRITE_PERI_REG(SPI_USER2(spi_no),
((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|4);
WRITE_PERI_REG(SPI_W0(spi_no), (uint32)(data));
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
}
/******************************************************************************
* FunctionName : spi_byte_read_espslave
* Description : SPI master 1 byte read function for esp8266 slave,
* read 1byte data from esp8266 slave buffer needs 16bit transmission ,
* first byte is command 0x06 to read slave buffer, second byte is recieved data
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint8* data- recieved data address
*******************************************************************************/
void spi_byte_read_espslave(uint8 spi_no,uint8 *data)
{
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_ADDR|SPI_USR_DUMMY);
//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
// bit15-0 is cmd value.
//0x70000000 is for 8bits cmd, 0x06 is eps8266 slave read cmd value
WRITE_PERI_REG(SPI_USER2(spi_no),
((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|6);
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
*data=(uint8)(READ_PERI_REG(SPI_W0(spi_no))&0xff);
}
/******************************************************************************
* FunctionName : spi_slave_init
* Description : SPI slave mode initial funtion, including mode setting,
* IO setting, transmission interrupt opening, interrupt function registration
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
*******************************************************************************/
void spi_slave_init(uint8 spi_no)
{
uint32 regvalue;
if(spi_no>1)
return; //handle invalid input number
//clear bit9,bit8 of reg PERIPHS_IO_MUX
//bit9 should be cleared when HSPI clock doesn't equal CPU clock
//bit8 should be cleared when SPI clock doesn't equal CPU clock
////WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9//TEST
if(spi_no==SPI){
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode
}else if(spi_no==HSPI){
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode
}
//regvalue=READ_PERI_REG(SPI_FLASH_SLAVE(spi_no));
//slave mode,slave use buffers which are register "SPI_FLASH_C0~C15", enable trans done isr
//set bit 30 bit 29 bit9,bit9 is trans done isr mask
SET_PERI_REG_MASK( SPI_SLAVE(spi_no),
SPI_SLAVE_MODE|SPI_SLV_WR_RD_BUF_EN|
SPI_SLV_WR_BUF_DONE_EN|SPI_SLV_RD_BUF_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|SPI_SLV_RD_STA_DONE_EN|
SPI_TRANS_DONE_EN);
//disable general trans intr
//CLEAR_PERI_REG_MASK(SPI_SLAVE(spi_no),SPI_TRANS_DONE_EN);
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);//disable flash operation mode
SET_PERI_REG_MASK(SPI_USER(spi_no),SPI_USR_MISO_HIGHPART);//SLAVE SEND DATA BUFFER IN C8-C15
//////**************RUN WHEN SLAVE RECIEVE*******************///////
//tow lines below is to configure spi timing.
SET_PERI_REG_MASK(SPI_CTRL2(spi_no),(0x2&SPI_MOSI_DELAY_NUM)<<SPI_MOSI_DELAY_NUM_S) ;//delay num
os_printf("SPI_CTRL2 is %08x\n",READ_PERI_REG(SPI_CTRL2(spi_no)));
WRITE_PERI_REG(SPI_CLOCK(spi_no), 0);
/////***************************************************//////
//set 8 bit slave command length, because slave must have at least one bit addr,
//8 bit slave+8bit addr, so master device first 2 bytes can be regarded as a command
//and the following bytes are datas,
//32 bytes input wil be stored in SPI_FLASH_C0-C7
//32 bytes output data should be set to SPI_FLASH_C8-C15
WRITE_PERI_REG(SPI_USER2(spi_no), (0x7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S); //0x70000000
//set 8 bit slave recieve buffer length, the buffer is SPI_FLASH_C0-C7
//set 8 bit slave status register, which is the low 8 bit of register "SPI_FLASH_STATUS"
SET_PERI_REG_MASK(SPI_SLAVE1(spi_no), ((0xff&SPI_SLV_BUF_BITLEN)<< SPI_SLV_BUF_BITLEN_S)|
((0x7&SPI_SLV_STATUS_BITLEN)<<SPI_SLV_STATUS_BITLEN_S)|
((0x7&SPI_SLV_WR_ADDR_BITLEN)<<SPI_SLV_WR_ADDR_BITLEN_S)|
((0x7&SPI_SLV_RD_ADDR_BITLEN)<<SPI_SLV_RD_ADDR_BITLEN_S));
SET_PERI_REG_MASK(SPI_PIN(spi_no),BIT19);//BIT19
//maybe enable slave transmission liston
SET_PERI_REG_MASK(SPI_CMD(spi_no),SPI_USR);
//register level2 isr function, which contains spi, hspi and i2s events
ETS_SPI_INTR_ATTACH(spi_slave_isr_handler,NULL);
//enable level2 isr, which contains spi, hspi and i2s events
ETS_SPI_INTR_ENABLE();
}
/* =============================================================================================
* code below is for spi slave r/w testcase with 2 r/w state lines connected to the spi master mcu
* replace with your own process functions
* find "add system_os_post here" in spi_slave_isr_handler.
* =============================================================================================
*/
#ifdef SPI_SLAVE_DEBUG
/******************************************************************************
* FunctionName : hspi_master_readwrite_repeat
* Description : SPI master test function for reading and writing esp8266 slave buffer,
the function uses HSPI module
*******************************************************************************/
os_timer_t timer2;
void hspi_master_readwrite_repeat(void)
{
static uint8 data=0;
uint8 temp;
os_timer_disarm(&timer2);
spi_byte_read_espslave(HSPI,&temp);
temp++;
spi_byte_write_espslave(HSPI,temp);
os_timer_setfn(&timer2, (os_timer_func_t *)hspi_master_readwrite_repeat, NULL);
os_timer_arm(&timer2, 500, 0);
}
#endif
/******************************************************************************
* FunctionName : spi_slave_isr_handler
* Description : SPI interrupt function, SPI HSPI and I2S interrupt can trig this function
some basic operation like clear isr flag has been done,
and it is availible for adding user coder in the funtion
* Parameters : void *para- function parameter address, which has been registered in function spi_slave_init
*******************************************************************************/
#include "gpio.h"
#include "user_interface.h"
#include "mem.h"
static uint8 spi_data[32] = {0};
static uint8 idx = 0;
static uint8 spi_flg = 0;
#define SPI_MISO
#define SPI_QUEUE_LEN 8
#define MOSI 0
#define MISO 1
#define STATUS_R_IN_WR 2
#define STATUS_W 3
#define TR_DONE_ALONE 4
#define WR_RD 5
#define DATA_ERROR 6
#define STATUS_R_IN_RD 7
//init the two intr line of slave
//gpio0: wr_ready ,and
//gpio2: rd_ready , controlled by slave
void ICACHE_FLASH_ATTR
gpio_init()
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
//PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
GPIO_OUTPUT_SET(0, 1);
GPIO_OUTPUT_SET(2, 0);
//GPIO_OUTPUT_SET(4, 1);
}
void spi_slave_isr_handler(void *para)
{
uint32 regvalue,calvalue;
static uint8 state =0;
uint32 recv_data,send_data;
if(READ_PERI_REG(0x3ff00020)&BIT4){
//following 3 lines is to clear isr signal
CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI), 0x3ff);
}else if(READ_PERI_REG(0x3ff00020)&BIT7){ //bit7 is for hspi isr,
regvalue=READ_PERI_REG(SPI_SLAVE(HSPI));
CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),
SPI_TRANS_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|
SPI_SLV_RD_STA_DONE_EN|
SPI_SLV_WR_BUF_DONE_EN|
SPI_SLV_RD_BUF_DONE_EN);
SET_PERI_REG_MASK(SPI_SLAVE(HSPI), SPI_SYNC_RESET);
CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),
SPI_TRANS_DONE|
SPI_SLV_WR_STA_DONE|
SPI_SLV_RD_STA_DONE|
SPI_SLV_WR_BUF_DONE|
SPI_SLV_RD_BUF_DONE);
SET_PERI_REG_MASK(SPI_SLAVE(HSPI),
SPI_TRANS_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|
SPI_SLV_RD_STA_DONE_EN|
SPI_SLV_WR_BUF_DONE_EN|
SPI_SLV_RD_BUF_DONE_EN);
if(regvalue&SPI_SLV_WR_BUF_DONE){
GPIO_OUTPUT_SET(0, 0);
idx=0;
while(idx<8){
recv_data=READ_PERI_REG(SPI_W0(HSPI)+(idx<<2));
spi_data[idx<<2] = recv_data&0xff;
spi_data[(idx<<2)+1] = (recv_data>>8)&0xff;
spi_data[(idx<<2)+2] = (recv_data>>16)&0xff;
spi_data[(idx<<2)+3] = (recv_data>>24)&0xff;
idx++;
}
//add system_os_post here
GPIO_OUTPUT_SET(0, 1);
}
if(regvalue&SPI_SLV_RD_BUF_DONE){
//it is necessary to call GPIO_OUTPUT_SET(2, 1), when new data is preped in SPI_W8-15 and needs to be sended.
GPIO_OUTPUT_SET(2, 0);
//add system_os_post here
//system_os_post(USER_TASK_PRIO_1,WR_RD,regvalue);
}
}else if(READ_PERI_REG(0x3ff00020)&BIT9){ //bit7 is for i2s isr,
}
}
#ifdef SPI_SLAVE_DEBUG
os_event_t * spiQueue;
void ICACHE_FLASH_ATTR
set_miso_data()
{
if(GPIO_INPUT_GET(2)==0){
WRITE_PERI_REG(SPI_W8(HSPI),0x05040302);
WRITE_PERI_REG(SPI_W9(HSPI),0x09080706);
WRITE_PERI_REG(SPI_W10(HSPI),0x0d0c0b0a);
WRITE_PERI_REG(SPI_W11(HSPI),0x11100f0e);
WRITE_PERI_REG(SPI_W12(HSPI),0x15141312);
WRITE_PERI_REG(SPI_W13(HSPI),0x19181716);
WRITE_PERI_REG(SPI_W14(HSPI),0x1d1c1b1a);
WRITE_PERI_REG(SPI_W15(HSPI),0x21201f1e);
GPIO_OUTPUT_SET(2, 1);
}
}
void ICACHE_FLASH_ATTR
disp_spi_data()
{
uint8 i = 0;
for(i=0;i<32;i++){
os_printf("data %d : 0x%02x\n\r",i,spi_data[i]);
}
//os_printf("d31:0x%02x\n\r",spi_data[31]);
}
void ICACHE_FLASH_ATTR
spi_task(os_event_t *e)
{
uint8 data;
switch(e->sig){
case MOSI:
disp_spi_data();
break;
case STATUS_R_IN_WR :
os_printf("SR ERR in WRPR,Reg:%08x \n",e->par);
break;
case STATUS_W:
os_printf("SW ERR,Reg:%08x\n",e->par);
break;
case TR_DONE_ALONE:
os_printf("TD ALO ERR,Reg:%08x\n",e->par);
break;
case WR_RD:
os_printf("WR&RD ERR,Reg:%08x\n",e->par);
break;
case DATA_ERROR:
os_printf("Data ERR,Reg:%08x\n",e->par);
break;
case STATUS_R_IN_RD :
os_printf("SR ERR in RDPR,Reg:%08x\n",e->par);
break;
default:
break;
}
}
void ICACHE_FLASH_ATTR
spi_task_init(void)
{
spiQueue = (os_event_t*)malloc(sizeof(os_event_t)*SPI_QUEUE_LEN);
system_os_task(spi_task,USER_TASK_PRIO_1,spiQueue,SPI_QUEUE_LEN);
}
os_timer_t spi_timer_test;
void ICACHE_FLASH_ATTR
spi_test_init()
{
os_printf("spi init\n\r");
spi_slave_init(HSPI);
os_printf("gpio init\n\r");
gpio_init();
os_printf("spi task init \n\r");
spi_task_init();
#ifdef SPI_MISO
os_printf("spi miso init\n\r");
set_miso_data();
#endif
//os_timer_disarm(&spi_timer_test);
//os_timer_setfn(&spi_timer_test, (os_timer_func_t *)set_miso_data, NULL);//wjl
//os_timer_arm(&spi_timer_test,50,1);
}
#endif
#endif

View File

@ -1,378 +0,0 @@
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
* 2016 DiUS Computing Pty Ltd <jmattsson@dius.com.au>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266/ESP32 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#if defined(__ESP32__)
# include "freertos/xtensa_api.h"
# define ETS_UART_INTR_ENABLE() xt_ints_on(1 << ETS_UART_INUM)
# define ETS_UART_INTR_DISABLE() xt_ints_off(1 << ETS_UART_INUM)
#endif
#if defined(__ESP8266__)
# include "rom.h"
# include "ioswap.h"
# define FUNC_U0RXD 0
# define FUNC_U0CTS 4
# define os_printf_isr(...) do {} while (0)
# define ETS_UART_INTR_ENABLE() _xt_isr_unmask(1 << ETS_UART_INUM)
# define ETS_UART_INTR_DISABLE() _xt_isr_mask(1 << ETS_UART_INUM)
#endif
#include "esp_common.h"
#include "uart.h"
#include "gpio.h"
#include "task/task.h"
#include <stdio.h>
#define UART_INTR_MASK 0x1ff
#define UART_LINE_INV_MASK (0x3f << 19)
static xQueueHandle uartQ[2];
static task_handle_t input_task = 0;
void uart_tx_one_char(uint32_t uart, uint8_t TxChar)
{
while (true) {
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
break;
}
}
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
}
static void uart1_write_char(char c)
{
if (c == '\n') {
uart_tx_one_char(UART1, '\r');
uart_tx_one_char(UART1, '\n');
} else if (c == '\r') {
} else {
uart_tx_one_char(UART1, c);
}
}
static void uart0_write_char(char c)
{
if (c == '\n') {
uart_tx_one_char(UART0, '\r');
uart_tx_one_char(UART0, '\n');
} else if (c == '\r') {
} else {
uart_tx_one_char(UART0, c);
}
}
//=================================================================
void UART_SetWordLength(UART_Port uart_no, UART_WordLength len)
{
SET_PERI_REG_BITS(UART_CONF0(uart_no), UART_BIT_NUM, len, UART_BIT_NUM_S);
}
void
UART_SetStopBits(UART_Port uart_no, UART_StopBits bit_num)
{
SET_PERI_REG_BITS(UART_CONF0(uart_no), UART_STOP_BIT_NUM, bit_num, UART_STOP_BIT_NUM_S);
}
void UART_SetLineInverse(UART_Port uart_no, UART_LineLevelInverse inverse_mask)
{
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_LINE_INV_MASK);
SET_PERI_REG_MASK(UART_CONF0(uart_no), inverse_mask);
}
void UART_SetParity(UART_Port uart_no, UART_ParityMode Parity_mode)
{
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_PARITY | UART_PARITY_EN);
if (Parity_mode == USART_Parity_None) {
} else {
SET_PERI_REG_MASK(UART_CONF0(uart_no), Parity_mode | UART_PARITY_EN);
}
}
void UART_SetBaudrate(UART_Port uart_no, uint32 baud_rate)
{
uart_div_modify(uart_no, UART_CLK_FREQ / baud_rate);
}
//only when USART_HardwareFlowControl_RTS is set , will the rx_thresh value be set.
void UART_SetFlowCtrl(UART_Port uart_no, UART_HwFlowCtrl flow_ctrl, uint8 rx_thresh)
{
if (flow_ctrl & USART_HardwareFlowControl_RTS) {
#if defined(__ESP8266__)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
#elif defined(__ESP32__)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_MTDO_U0RTS);
#endif
SET_PERI_REG_BITS(UART_CONF1(uart_no), UART_RX_FLOW_THRHD, rx_thresh, UART_RX_FLOW_THRHD_S);
SET_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
} else {
CLEAR_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
}
if (flow_ctrl & USART_HardwareFlowControl_CTS) {
#if defined(__ESP8266__)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS);
#elif defined(__ESP32__)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_MTCK_U0CTS);
#endif
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
} else {
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
}
}
void UART_WaitTxFifoEmpty(UART_Port uart_no) //do not use if tx flow control enabled
{
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S));
}
void UART_ResetFifo(UART_Port uart_no)
{
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
}
void UART_ClearIntrStatus(UART_Port uart_no, uint32 clr_mask)
{
WRITE_PERI_REG(UART_INT_CLR(uart_no), clr_mask);
}
void UART_SetIntrEna(UART_Port uart_no, uint32 ena_mask)
{
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), ena_mask);
}
void UART_intr_handler_register(void *fn, void *arg)
{
#if defined(__ESP8266__)
_xt_isr_attach(ETS_UART_INUM, fn, arg);
#elif defined(__ESP32__)
xt_set_interrupt_handler(ETS_UART_INUM, fn, arg);
#endif
}
void UART_SetPrintPort(UART_Port uart_no)
{
if (uart_no == 1) {
os_install_putc1(uart1_write_char);
} else {
os_install_putc1(uart0_write_char);
}
}
void UART_ParamConfig(UART_Port uart_no, const UART_ConfigTypeDef *pUARTConfig)
{
if (uart_no == UART1) {
#if defined(__ESP8266__)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
#elif defined(__ESP32__)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, FUNC_SD_DATA3_U1TXD);
#endif
} else {
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
#if defined(__ESP8266__)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
#elif defined(__ESP32__)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
#endif
}
UART_SetFlowCtrl(uart_no, pUARTConfig->flow_ctrl, pUARTConfig->UART_RxFlowThresh);
UART_SetBaudrate(uart_no, pUARTConfig->baud_rate);
WRITE_PERI_REG(UART_CONF0(uart_no),
((pUARTConfig->parity == USART_Parity_None) ? 0x0 : (UART_PARITY_EN | pUARTConfig->parity))
| (pUARTConfig->stop_bits << UART_STOP_BIT_NUM_S)
| (pUARTConfig->data_bits << UART_BIT_NUM_S)
| ((pUARTConfig->flow_ctrl & USART_HardwareFlowControl_CTS) ? UART_TX_FLOW_EN : 0x0)
| pUARTConfig->UART_InverseMask
#if defined(__ESP32__)
| UART_TICK_REF_ALWAYS_ON
#endif
);
UART_ResetFifo(uart_no);
}
void UART_IntrConfig(UART_Port uart_no, const UART_IntrConfTypeDef *pUARTIntrConf)
{
uint32 reg_val = 0;
UART_ClearIntrStatus(uart_no, UART_INTR_MASK);
reg_val = READ_PERI_REG(UART_CONF1(uart_no));
reg_val |= ((pUARTIntrConf->UART_IntrEnMask & UART_RXFIFO_TOUT_INT_ENA) ?
((((pUARTIntrConf->UART_RX_TimeOutIntrThresh)&UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S) | UART_RX_TOUT_EN) : 0);
reg_val |= ((pUARTIntrConf->UART_IntrEnMask & UART_RXFIFO_FULL_INT_ENA) ?
(((pUARTIntrConf->UART_RX_FifoFullIntrThresh)&UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) : 0);
reg_val |= ((pUARTIntrConf->UART_IntrEnMask & UART_TXFIFO_EMPTY_INT_ENA) ?
(((pUARTIntrConf->UART_TX_FifoEmptyIntrThresh)&UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S) : 0);
WRITE_PERI_REG(UART_CONF1(uart_no), reg_val);
CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_INTR_MASK);
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), pUARTIntrConf->UART_IntrEnMask);
}
static void uart0_rx_intr_handler(void *para)
{
/* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
* uart1 and uart0 respectively
*/
uint8 uart_no = UART0; // TODO: support UART1 as well
uint8 fifo_len = 0;
uint32 uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no)) ;
while (uart_intr_status != 0x0) {
if (UART_FRM_ERR_INT_ST == (uart_intr_status & UART_FRM_ERR_INT_ST)) {
//os_printf_isr("FRM_ERR\r\n");
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
} else if (UART_RXFIFO_FULL_INT_ST == (uart_intr_status & UART_RXFIFO_FULL_INT_ST)) {
//os_printf_isr("full\r\n");
fifo_len = (READ_PERI_REG(UART_STATUS(uart_no)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
for (int i = 0; i < fifo_len; ++i)
{
char c = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
if (uartQ[uart_no])
xQueueSendToBackFromISR (uartQ[uart_no], &c, NULL);
}
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
//CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
} else if (UART_RXFIFO_TOUT_INT_ST == (uart_intr_status & UART_RXFIFO_TOUT_INT_ST)) {
//os_printf_isr("timeout\r\n");
fifo_len = (READ_PERI_REG(UART_STATUS(uart_no)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
for (int i = 0; i < fifo_len; ++i)
{
char c = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
if (uartQ[uart_no])
xQueueSendToBackFromISR (uartQ[uart_no], &c, NULL);
}
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_TOUT_INT_CLR);
} else if (UART_TXFIFO_EMPTY_INT_ST == (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST)) {
//os_printf_isr("empty\n\r");
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_TXFIFO_EMPTY_INT_ENA);
} else if (UART_RXFIFO_OVF_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST)) {
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR);
//os_printf_isr("RX OVF!!\r\n");
} else {
//skip
}
uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no)) ;
}
if (fifo_len && input_task)
task_post_low (input_task, false);
}
void uart_init_uart0_console (const UART_ConfigTypeDef *config, task_handle_t tsk)
{
input_task = tsk;
uartQ[0] = xQueueCreate (0x100, sizeof (char));
UART_WaitTxFifoEmpty(UART0);
UART_ParamConfig(UART0, config);
UART_IntrConfTypeDef uart_intr;
uart_intr.UART_IntrEnMask =
UART_RXFIFO_TOUT_INT_ENA |
UART_FRM_ERR_INT_ENA |
UART_RXFIFO_FULL_INT_ENA |
UART_TXFIFO_EMPTY_INT_ENA;
uart_intr.UART_RX_FifoFullIntrThresh = 10;
uart_intr.UART_RX_TimeOutIntrThresh = 2;
uart_intr.UART_TX_FifoEmptyIntrThresh = 20;
UART_IntrConfig(UART0, &uart_intr);
UART_SetPrintPort(UART0);
UART_intr_handler_register(uart0_rx_intr_handler, NULL);
ETS_UART_INTR_ENABLE();
}
bool uart0_getc (char *c)
{
return (uartQ[UART0] && (xQueueReceive (uartQ[UART0], c, 0) == pdTRUE));
}
void uart0_alt (bool on)
{
#if defined(__ESP8266__)
if (on)
{
PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTDO_U);
PIN_PULLUP_EN(PERIPHS_IO_MUX_MTCK_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS);
// now make RTS/CTS behave as TX/RX
IOSWAP |= (1 << IOSWAPU0);
}
else
{
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
PIN_PULLUP_EN(PERIPHS_IO_MUX_U0RXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
// now make RX/TX behave as TX/RX
IOSWAP &= ~(1 << IOSWAPU0);
}
#else
printf("Alternate UART0 pins not supported on this chip\n");
#endif
}

View File

@ -1,48 +0,0 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libhttp.a
endif
STD_CFLAGS=-std=gnu11 -Wimplicit
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ./include
INCLUDES += -I ../include
INCLUDES += -I ../../include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -1,559 +0,0 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* Martin d'Allens <martin.dallens@gmail.com> wrote this file. As long as you retain
* this notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/
/*
* FIXME: sprintf->snprintf everywhere.
* FIXME: support null characters in responses.
*/
// No espconn on ESP32
#ifdef __ESP8266__
#include "osapi.h"
#include "user_interface.h"
#include "espconn.h"
#include "mem.h"
#include "limits.h"
#include "httpclient.h"
#include "stdlib.h"
/* Internal state. */
typedef struct request_args_t {
char * hostname;
int port;
bool secure;
char * method;
char * path;
char * headers;
char * post_data;
char * buffer;
int buffer_size;
int timeout;
os_timer_t timeout_timer;
http_callback_t callback_handle;
} request_args_t;
static char * ICACHE_FLASH_ATTR esp_strdup( const char * str )
{
if ( str == NULL )
{
return(NULL);
}
char * new_str = (char *) malloc( os_strlen( str ) + 1 ); /* 1 for null character */
if ( new_str == NULL )
{
HTTPCLIENT_DEBUG( "esp_strdup: malloc error" );
return(NULL);
}
os_strcpy( new_str, str );
return(new_str);
}
static int ICACHE_FLASH_ATTR
esp_isupper( char c )
{
return(c >= 'A' && c <= 'Z');
}
static int ICACHE_FLASH_ATTR
esp_isalpha( char c )
{
return( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') );
}
static int ICACHE_FLASH_ATTR
esp_isspace( char c )
{
return(c == ' ' || c == '\t' || c == '\n' || c == '\12');
}
static int ICACHE_FLASH_ATTR
esp_isdigit( char c )
{
return(c >= '0' && c <= '9');
}
static int ICACHE_FLASH_ATTR http_chunked_decode( const char * chunked, char * decode )
{
int i = 0, j = 0;
int decode_size = 0;
char *str = (char *) chunked;
do
{
char * endstr;
/* [chunk-size] */
i = strtoul( str + j, NULL, 16 );
HTTPCLIENT_DEBUG( "Chunk Size:%d\r\n", i );
if ( i <= 0 )
break;
/* [chunk-size-end-ptr] */
endstr = (char *) os_strstr( str + j, "\r\n" );
/* [chunk-ext] */
j += endstr - (str + j);
/* [CRLF] */
j += 2;
/* [chunk-data] */
decode_size += i;
os_memcpy( (char *) &decode[decode_size - i], (char *) str + j, i );
j += i;
/* [CRLF] */
j += 2;
}
while ( true );
/*
*
* footer CRLF
*
*/
return(j);
}
static void ICACHE_FLASH_ATTR http_receive_callback( void * arg, char * buf, unsigned short len )
{
struct espconn * conn = (struct espconn *) arg;
request_args_t * req = (request_args_t *) conn->reverse;
if ( req->buffer == NULL )
{
return;
}
/* Let's do the equivalent of a realloc(). */
const int new_size = req->buffer_size + len;
char * new_buffer;
if ( new_size > BUFFER_SIZE_MAX || NULL == (new_buffer = (char *) malloc( new_size ) ) )
{
HTTPCLIENT_DEBUG( "Response too long (%d)\n", new_size );
req->buffer[0] = '\0'; /* Discard the buffer to avoid using an incomplete response. */
#if 0
if ( req->secure )
espconn_secure_disconnect( conn );
else
#endif
espconn_disconnect( conn );
return; /* The disconnect callback will be called. */
}
os_memcpy( new_buffer, req->buffer, req->buffer_size );
os_memcpy( new_buffer + req->buffer_size - 1 /*overwrite the null character*/, buf, len ); /* Append new data. */
new_buffer[new_size - 1] = '\0'; /* Make sure there is an end of string. */
free( req->buffer );
req->buffer = new_buffer;
req->buffer_size = new_size;
}
static void ICACHE_FLASH_ATTR http_send_callback( void * arg )
{
struct espconn * conn = (struct espconn *) arg;
request_args_t * req = (request_args_t *) conn->reverse;
if ( req->post_data == NULL )
{
HTTPCLIENT_DEBUG( "All sent\n" );
}
else
{
/* The headers were sent, now send the contents. */
HTTPCLIENT_DEBUG( "Sending request body\n" );
#if 0
if ( req->secure )
espconn_secure_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
else
#endif
espconn_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
free( req->post_data );
req->post_data = NULL;
}
}
static void ICACHE_FLASH_ATTR http_connect_callback( void * arg )
{
HTTPCLIENT_DEBUG( "Connected\n" );
struct espconn * conn = (struct espconn *) arg;
request_args_t * req = (request_args_t *) conn->reverse;
espconn_regist_recvcb( conn, http_receive_callback );
espconn_regist_sentcb( conn, http_send_callback );
char post_headers[32] = "";
if ( req->post_data != NULL ) /* If there is data then add Content-Length header. */
{
os_sprintf( post_headers, "Content-Length: %d\r\n", strlen( req->post_data ) );
}
if(req->headers == NULL) /* Avoid NULL pointer, it may cause exception */
{
req->headers = (char *)malloc(sizeof(char));
req->headers[0] = '\0';
}
char buf[69 + strlen( req->method ) + strlen( req->path ) + strlen( req->hostname ) +
strlen( req->headers ) + strlen( post_headers )];
int len = os_sprintf( buf,
"%s %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Connection: close\r\n"
"User-Agent: ESP8266\r\n"
"%s"
"%s"
"\r\n",
req->method, req->path, req->hostname, req->port, req->headers, post_headers );
#if 0
if ( req->secure )
espconn_secure_send( conn, (uint8_t *) buf, len );
else
#endif
espconn_send( conn, (uint8_t *) buf, len );
if(req->headers != NULL)
free( req->headers );
req->headers = NULL;
HTTPCLIENT_DEBUG( "Sending request header\n" );
}
static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
{
HTTPCLIENT_DEBUG( "Disconnected\n" );
struct espconn *conn = (struct espconn *) arg;
if ( conn == NULL )
{
return;
}
if ( conn->proto.tcp != NULL )
{
free( conn->proto.tcp );
}
if ( conn->reverse != NULL )
{
request_args_t * req = (request_args_t *) conn->reverse;
int http_status = -1;
char * body = "";
// Turn off timeout timer
os_timer_disarm( &(req->timeout_timer) );
if ( req->buffer == NULL )
{
HTTPCLIENT_DEBUG( "Buffer probably shouldn't be NULL\n" );
}
else if ( req->buffer[0] != '\0' )
{
/* FIXME: make sure this is not a partial response, using the Content-Length header. */
const char * version_1_0 = "HTTP/1.0 ";
const char * version_1_1 = "HTTP/1.1 ";
if (( os_strncmp( req->buffer, version_1_0, strlen( version_1_0 ) ) != 0 ) &&
( os_strncmp( req->buffer, version_1_1, strlen( version_1_1 ) ) != 0 ))
{
HTTPCLIENT_DEBUG( "Invalid version in %s\n", req->buffer );
}
else
{
http_status = atoi( req->buffer + strlen( version_1_0 ) );
body = (char *) os_strstr(req->buffer, "\r\n\r\n");
if (NULL == body) {
/* Find missing body */
HTTPCLIENT_DEBUG("Body shouldn't be NULL\n");
/* To avoid NULL body */
body = "";
} else {
/* Skip CR & LF */
body = body + 4;
}
if ( os_strstr( req->buffer, "Transfer-Encoding: chunked" ) )
{
int body_size = req->buffer_size - (body - req->buffer);
char chunked_decode_buffer[body_size];
os_memset( chunked_decode_buffer, 0, body_size );
/* Chuncked data */
http_chunked_decode( body, chunked_decode_buffer );
os_memcpy( body, chunked_decode_buffer, body_size );
}
}
}
if ( req->callback_handle != NULL ) /* Callback is optional. */
{
req->callback_handle( body, http_status, req->buffer );
}
if (req->buffer) {
free( req->buffer );
}
free( req->hostname );
free( req->method );
free( req->path );
free( req );
}
/* Fix memory leak. */
espconn_delete( conn );
free( conn );
}
static void ICACHE_FLASH_ATTR http_error_callback( void *arg, sint8 errType )
{
HTTPCLIENT_DEBUG( "Disconnected with error\n" );
http_disconnect_callback( arg );
}
static void ICACHE_FLASH_ATTR http_timeout_callback( void *arg )
{
HTTPCLIENT_DEBUG( "Connection timeout\n" );
struct espconn * conn = (struct espconn *) arg;
if ( conn == NULL )
{
return;
}
if ( conn->reverse == NULL )
{
return;
}
request_args_t * req = (request_args_t *) conn->reverse;
/* Call disconnect */
#if 0
if ( req->secure )
espconn_secure_disconnect( conn );
else
#endif
espconn_disconnect( conn );
}
static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_t * addr, void * arg )
{
request_args_t * req = (request_args_t *) arg;
if ( addr == NULL )
{
HTTPCLIENT_DEBUG( "DNS failed for %s\n", hostname );
if ( req->callback_handle != NULL )
{
req->callback_handle( "", -1, "" );
}
free( req );
}
else
{
HTTPCLIENT_DEBUG( "DNS found %s " IPSTR "\n", hostname, IP2STR( addr ) );
struct espconn * conn = (struct espconn *) zalloc( sizeof(struct espconn) );
conn->type = ESPCONN_TCP;
conn->state = ESPCONN_NONE;
conn->proto.tcp = (esp_tcp *) zalloc( sizeof(esp_tcp) );
conn->proto.tcp->local_port = espconn_port();
conn->proto.tcp->remote_port = req->port;
conn->reverse = req;
os_memcpy( conn->proto.tcp->remote_ip, addr, 4 );
espconn_regist_connectcb( conn, http_connect_callback );
espconn_regist_disconcb( conn, http_disconnect_callback );
espconn_regist_reconcb( conn, http_error_callback );
/* Set connection timeout timer */
os_timer_disarm( &(req->timeout_timer) );
os_timer_setfn( &(req->timeout_timer), (os_timer_func_t *) http_timeout_callback, conn );
os_timer_arm( &(req->timeout_timer), req->timeout, false );
#if 0
if ( req->secure )
{
espconn_secure_set_size( ESPCONN_CLIENT, 5120 ); /* set SSL buffer size */
espconn_secure_connect( conn );
}
else
#endif
{
espconn_connect( conn );
}
}
}
void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool secure, const char * method, const char * path, const char * headers, const char * post_data, http_callback_t callback_handle )
{
HTTPCLIENT_DEBUG( "DNS request\n" );
request_args_t * req = (request_args_t *) zalloc( sizeof(request_args_t) );
req->hostname = esp_strdup( hostname );
req->port = port;
req->secure = secure;
req->method = esp_strdup( method );
req->path = esp_strdup( path );
req->headers = esp_strdup( headers );
req->post_data = esp_strdup( post_data );
req->buffer_size = 1;
req->buffer = (char *) malloc( 1 );
req->buffer[0] = '\0'; /* Empty string. */
req->callback_handle = callback_handle;
req->timeout = HTTP_REQUEST_TIMEOUT_MS;
ip_addr_t addr;
err_t error = espconn_gethostbyname( (struct espconn *) req, /* It seems we don't need a real espconn pointer here. */
hostname, &addr, http_dns_callback );
if ( error == ESPCONN_INPROGRESS )
{
HTTPCLIENT_DEBUG( "DNS pending\n" );
}
else if ( error == ESPCONN_OK )
{
/* Already in the local names table (or hostname was an IP address), execute the callback ourselves. */
http_dns_callback( hostname, &addr, req );
}
else
{
if ( error == ESPCONN_ARG )
{
HTTPCLIENT_DEBUG( "DNS arg error %s\n", hostname );
}else {
HTTPCLIENT_DEBUG( "DNS error code %d\n", error );
}
http_dns_callback( hostname, NULL, req ); /* Handle all DNS errors the same way. */
}
}
/*
* Parse an URL of the form http://host:port/path
* <host> can be a hostname or an IP address
* <port> is optional
*/
void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, const char * headers, const char * post_data, http_callback_t callback_handle )
{
/*
* FIXME: handle HTTP auth with http://user:pass@host/
* FIXME: get rid of the #anchor part if present.
*/
char hostname[128] = "";
int port = 80;
bool secure = false;
bool is_http = os_strncmp( url, "http://", strlen( "http://" ) ) == 0;
bool is_https = os_strncmp( url, "https://", strlen( "https://" ) ) == 0;
if ( is_http )
url += strlen( "http://" ); /* Get rid of the protocol. */
else if ( is_https )
{
port = 443;
secure = true;
url += strlen( "https://" ); /* Get rid of the protocol. */
}
else
{
HTTPCLIENT_DEBUG( "URL is not HTTP or HTTPS %s\n", url );
return;
}
char * path = os_strchr( url, '/' );
if ( path == NULL )
{
path = os_strchr( url, '\0' ); /* Pointer to end of string. */
}
char * colon = os_strchr( url, ':' );
if ( colon > path )
{
colon = NULL; /* Limit the search to characters before the path. */
}
if (path - url >= sizeof(hostname)) {
HTTPCLIENT_DEBUG( "hostname is too long %s\n", url );
return;
}
if ( colon == NULL ) /* The port is not present. */
{
os_memcpy( hostname, url, path - url );
hostname[path - url] = '\0';
}
else
{
port = atoi( colon + 1 );
if ( port == 0 )
{
HTTPCLIENT_DEBUG( "Port error %s\n", url );
return;
}
os_memcpy( hostname, url, colon - url );
hostname[colon - url] = '\0';
}
if ( path[0] == '\0' ) /* Empty path is not allowed. */
{
path = "/";
}
HTTPCLIENT_DEBUG( "hostname=%s\n", hostname );
HTTPCLIENT_DEBUG( "port=%d\n", port );
HTTPCLIENT_DEBUG( "method=%s\n", method );
HTTPCLIENT_DEBUG( "path=%s\n", path );
http_raw_request( hostname, port, secure, method, path, headers, post_data, callback_handle );
}
/*
* Parse an URL of the form http://host:port/path
* <host> can be a hostname or an IP address
* <port> is optional
*/
void ICACHE_FLASH_ATTR http_post( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
{
http_request( url, "POST", headers, post_data, callback_handle );
}
void ICACHE_FLASH_ATTR http_get( const char * url, const char * headers, http_callback_t callback_handle )
{
http_request( url, "GET", headers, NULL, callback_handle );
}
void ICACHE_FLASH_ATTR http_delete( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
{
http_request( url, "DELETE", headers, post_data, callback_handle );
}
void ICACHE_FLASH_ATTR http_put( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
{
http_request( url, "PUT", headers, post_data, callback_handle );
}
void ICACHE_FLASH_ATTR http_callback_example( char * response, int http_status, char * full_response )
{
os_printf( "http_status=%d\n", http_status );
if ( http_status != HTTP_STATUS_GENERIC_ERROR )
{
os_printf( "strlen(full_response)=%d\n", strlen( full_response ) );
os_printf( "response=%s<EOF>\n", response );
}
}
#endif

View File

@ -1,97 +0,0 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* Martin d'Allens <martin.dallens@gmail.com> wrote this file. As long as you retain
* this notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/
#ifndef __HTTPCLIENT_H__
#define __HTTPCLIENT_H__
#if defined(GLOBAL_DEBUG_ON)
#define HTTPCLIENT_DEBUG_ON
#endif
#if defined(HTTPCLIENT_DEBUG_ON)
#define HTTPCLIENT_DEBUG(format, ...) os_printf(format, ##__VA_ARGS__)
#else
#define HTTPCLIENT_DEBUG(format, ...)
#endif
#if defined(USES_SDK_BEFORE_V140)
#define espconn_send espconn_sent
#define espconn_secure_send espconn_secure_sent
#endif
/*
* In case of TCP or DNS error the callback is called with this status.
*/
#define HTTP_STATUS_GENERIC_ERROR (-1)
/*
* Size of http responses that will cause an error.
*/
#define BUFFER_SIZE_MAX (0x2000)
/*
* Timeout of http request.
*/
#define HTTP_REQUEST_TIMEOUT_MS (10000)
/*
* "full_response" is a string containing all response headers and the response body.
* "response_body and "http_status" are extracted from "full_response" for convenience.
*
* A successful request corresponds to an HTTP status code of 200 (OK).
* More info at http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
*/
typedef void (* http_callback_t)(char * response_body, int http_status, char * full_response);
/*
* Call this function to skip URL parsing if the arguments are already in separate variables.
*/
void ICACHE_FLASH_ATTR http_raw_request(const char * hostname, int port, bool secure, const char * method, const char * path, const char * headers, const char * post_data, http_callback_t callback_handle);
/*
* Request data from URL use custom method.
* The data should be encoded as any format.
* Try:
* http_request("http://httpbin.org/post", "OPTIONS", "Content-type: text/plain", "Hello world", http_callback_example);
*/
void ICACHE_FLASH_ATTR http_request(const char * url, const char * method, const char * headers, const char * post_data, http_callback_t callback_handle);
/*
* Post data to a web form.
* The data should be encoded as any format.
* Try:
* http_post("http://httpbin.org/post", "Content-type: application/json", "{\"hello\": \"world\"}", http_callback_example);
*/
void ICACHE_FLASH_ATTR http_post(const char * url, const char * headers, const char * post_data, http_callback_t callback_handle);
/*
* Download a web page from its URL.
* Try:
* http_get("http://wtfismyip.com/text", NULL, http_callback_example);
*/
void ICACHE_FLASH_ATTR http_get(const char * url, const char * headers, http_callback_t callback_handle);
/*
* Delete a web page from its URL.
* Try:
* http_delete("http://wtfismyip.com/text", NULL, http_callback_example);
*/
void ICACHE_FLASH_ATTR http_delete(const char * url, const char * headers, const char * post_data, http_callback_t callback_handle);
/*
* Update data to a web form.
* The data should be encoded as any format.
* Try:
* http_put("http://httpbin.org/post", "Content-type: application/json", "{\"hello\": \"world\"}", http_callback_example);
*/
void ICACHE_FLASH_ATTR http_put(const char * url, const char * headers, const char * post_data, http_callback_t callback_handle);
/*
* Output on the UART.
*/
void http_callback_example(char * response, int http_status, char * full_response);
#endif // __HTTPCLIENT_H__

View File

@ -1,9 +0,0 @@
#ifndef __GPIO16_H__
#define __GPIO16_H__
void gpio16_output_conf(void);
void gpio16_output_set(uint8 value);
void gpio16_input_conf(void);
uint8 gpio16_input_get(void);
#endif

View File

@ -1,74 +0,0 @@
#ifndef __I2C_MASTER_H__
#define __I2C_MASTER_H__
#define I2C_MASTER_SDA_MUX (pin_mux[sda])
#define I2C_MASTER_SCL_MUX (pin_mux[scl])
#define I2C_MASTER_SDA_GPIO (pinSDA)
#define I2C_MASTER_SCL_GPIO (pinSCL)
#define I2C_MASTER_SDA_FUNC (pin_func[sda])
#define I2C_MASTER_SCL_FUNC (pin_func[scl])
// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTDO_U
// #define I2C_MASTER_SDA_GPIO 2
// #define I2C_MASTER_SCL_GPIO 15
// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2
// #define I2C_MASTER_SCL_FUNC FUNC_GPIO15
// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTMS_U
// #define I2C_MASTER_SDA_GPIO 2
// #define I2C_MASTER_SCL_GPIO 14
// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2
// #define I2C_MASTER_SCL_FUNC FUNC_GPIO14
//#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
//#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO0_U
//#define I2C_MASTER_SDA_GPIO 2
//#define I2C_MASTER_SCL_GPIO 0
//#define I2C_MASTER_SDA_FUNC FUNC_GPIO2
//#define I2C_MASTER_SCL_FUNC FUNC_GPIO0
#if 0
#define I2C_MASTER_GPIO_SET(pin) \
gpio_output_set(1<<pin,0,1<<pin,0)
#define I2C_MASTER_GPIO_CLR(pin) \
gpio_output_set(0,1<<pin,1<<pin,0)
#define I2C_MASTER_GPIO_OUT(pin,val) \
if(val) I2C_MASTER_GPIO_SET(pin);\
else I2C_MASTER_GPIO_CLR(pin)
#endif
#define I2C_MASTER_SDA_HIGH_SCL_HIGH() \
gpio_output_set(1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
#define I2C_MASTER_SDA_HIGH_SCL_LOW() \
gpio_output_set(1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
#define I2C_MASTER_SDA_LOW_SCL_HIGH() \
gpio_output_set(1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
#define I2C_MASTER_SDA_LOW_SCL_LOW() \
gpio_output_set(0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
void i2c_master_gpio_init(uint8 sda, uint8 scl);
void i2c_master_init(void);
#define i2c_master_wait os_delay_us
void i2c_master_stop(void);
void i2c_master_start(void);
void i2c_master_setAck(uint8 level);
uint8 i2c_master_getAck(void);
uint8 i2c_master_readByte(void);
void i2c_master_writeByte(uint8 wrdata);
bool i2c_master_checkAck(void);
void i2c_master_send_ack(void);
void i2c_master_send_nack(void);
uint8 i2c_master_get_pinSDA();
uint8 i2c_master_get_pinSCL();
#endif

View File

@ -1,27 +0,0 @@
#ifndef __KEY_H__
#define __KEY_H__
#include "gpio.h"
typedef void (* key_function)(void);
struct single_key_param {
uint8 key_level;
uint8 gpio_id;
uint8 gpio_func;
uint32 gpio_name;
os_timer_t key_5s;
os_timer_t key_50ms;
key_function short_press;
key_function long_press;
};
struct keys_param {
uint8 key_num;
struct single_key_param **single_key;
};
struct single_key_param *key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press);
void key_init(struct keys_param *key);
#endif

View File

@ -1,150 +0,0 @@
#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__
#include "c_types.h"
// You can exclude certain features from OneWire. In theory, this
// might save some space. In practice, the compiler automatically
// removes unused code (technically, the linker, using -fdata-sections
// and -ffunction-sections when compiling, and Wl,--gc-sections
// when linking), so most of these will not result in any code size
// reduction. Well, unless you try to use the missing features
// and redesign your program to not need them! ONEWIRE_CRC8_TABLE
// is the exception, because it selects a fast but large algorithm
// or a small but slow algorithm.
// you can exclude onewire_search by defining that to 0
#ifndef ONEWIRE_SEARCH
#define ONEWIRE_SEARCH 1
#endif
// You can exclude CRC checks altogether by defining this to 0
#ifndef ONEWIRE_CRC
#define ONEWIRE_CRC 1
#endif
// Select the table-lookup method of computing the 8-bit CRC
// by setting this to 1. The lookup table enlarges code size by
// about 250 bytes. It does NOT consume RAM (but did in very
// old versions of OneWire). If you disable this, a slower
// but very compact algorithm is used.
#ifndef ONEWIRE_CRC8_TABLE
#define ONEWIRE_CRC8_TABLE 0
#endif
// You can allow 16-bit CRC checks by defining this to 1
// (Note that ONEWIRE_CRC must also be 1.)
#ifndef ONEWIRE_CRC16
#define ONEWIRE_CRC16 1
#endif
// Platform specific I/O definitions
#define DIRECT_READ(pin) (0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[pin])))
#define DIRECT_MODE_INPUT(pin) GPIO_DIS_OUTPUT(pin_num[pin])
#define DIRECT_MODE_OUTPUT(pin)
#define DIRECT_WRITE_LOW(pin) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 0))
#define DIRECT_WRITE_HIGH(pin) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 1))
void onewire_init(uint8_t pin);
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
// with a presence pulse. Returns 0 if there is no device or the
// bus is shorted or otherwise held low for more than 250uS
uint8_t onewire_reset(uint8_t pin);
// Issue a 1-Wire rom select command, you do the reset first.
void onewire_select(uint8_t pin, const uint8_t rom[8]);
// Issue a 1-Wire rom skip command, to address all on bus.
void onewire_skip(uint8_t pin);
// Write a byte. If 'power' is one then the wire is held high at
// the end for parasitically powered devices. You are responsible
// for eventually depowering it by calling depower() or doing
// another read or write.
void onewire_write(uint8_t pin, uint8_t v, uint8_t power);
void onewire_write_bytes(uint8_t pin, const uint8_t *buf, uint16_t count, bool power);
// Read a byte.
uint8_t onewire_read(uint8_t pin);
void onewire_read_bytes(uint8_t pin, uint8_t *buf, uint16_t count);
// Write a bit. The bus is always left powered at the end, see
// note in write() about that.
// void onewire_write_bit(uint8_t pin, uint8_t v);
// Read a bit.
// uint8_t onewire_read_bit(uint8_t pin);
// Stop forcing power onto the bus. You only need to do this if
// you used the 'power' flag to write() or used a write_bit() call
// and aren't about to do another read or write. You would rather
// not leave this powered if you don't have to, just in case
// someone shorts your bus.
void onewire_depower(uint8_t pin);
#if ONEWIRE_SEARCH
// Clear the search state so that if will start from the beginning again.
void onewire_reset_search(uint8_t pin);
// Setup the search to find the device type 'family_code' on the next call
// to search(*newAddr) if it is present.
void onewire_target_search(uint8_t pin, uint8_t family_code);
// Look for the next device. Returns 1 if a new address has been
// returned. A zero might mean that the bus is shorted, there are
// no devices, or you have already retrieved all of them. It
// might be a good idea to check the CRC to make sure you didn't
// get garbage. The order is deterministic. You will always get
// the same devices in the same order.
uint8_t onewire_search(uint8_t pin, uint8_t *newAddr);
#endif
#if ONEWIRE_CRC
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
// ROM and scratchpad registers.
uint8_t onewire_crc8(const uint8_t *addr, uint8_t len);
#if ONEWIRE_CRC16
// Compute the 1-Wire CRC16 and compare it against the received CRC.
// Example usage (reading a DS2408):
// // Put everything in a buffer so we can compute the CRC easily.
// uint8_t buf[13];
// buf[0] = 0xF0; // Read PIO Registers
// buf[1] = 0x88; // LSB address
// buf[2] = 0x00; // MSB address
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
// if (!CheckCRC16(buf, 11, &buf[11])) {
// // Handle error.
// }
//
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param inverted_crc - The two CRC16 bytes in the received data.
// This should just point into the received data,
// *not* at a 16-bit integer.
// @param crc - The crc starting value (optional)
// @return True, iff the CRC matches.
bool onewire_check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc);
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
// the integrity of data received from many 1-Wire devices. Note that the
// CRC computed here is *not* what you'll get from the 1-Wire network,
// for two reasons:
// 1) The CRC is transmitted bitwise inverted.
// 2) Depending on the endian-ness of your processor, the binary
// representation of the two-byte return value may have a different
// byte order than the two bytes you get from 1-Wire.
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param crc - The crc starting value (optional)
// @return The CRC16, as defined by Dallas Semiconductor.
uint16_t onewire_crc16(const uint8_t* input, uint16_t len, uint16_t crc);
#endif
#endif
#endif

View File

@ -1,46 +0,0 @@
#ifndef __PWM_H__
#define __PWM_H__
#define PWM_CHANNEL 6
struct pwm_single_param {
uint16 gpio_set;
uint16 gpio_clear;
uint32 h_time;
};
struct pwm_param {
uint32 period;
uint16 freq;
uint16 duty[PWM_CHANNEL];
};
#define PWM_DEPTH 1023
#define PWM_FREQ_MAX 1000
#define PWM_1S 1000000
// #define PWM_0_OUT_IO_MUX PERIPHS_IO_MUX_MTMS_U
// #define PWM_0_OUT_IO_NUM 14
// #define PWM_0_OUT_IO_FUNC FUNC_GPIO14
// #define PWM_1_OUT_IO_MUX PERIPHS_IO_MUX_MTDI_U
// #define PWM_1_OUT_IO_NUM 12
// #define PWM_1_OUT_IO_FUNC FUNC_GPIO12
// #define PWM_2_OUT_IO_MUX PERIPHS_IO_MUX_MTCK_U
// #define PWM_2_OUT_IO_NUM 13
// #define PWM_2_OUT_IO_FUNC FUNC_GPIO13
void pwm_init(uint16 freq, uint16 *duty);
bool pwm_start(void);
void pwm_set_duty(uint16 duty, uint8 channel);
uint16 pwm_get_duty(uint8 channel);
void pwm_set_freq(uint16 freq, uint8 channel);
uint16 pwm_get_freq(uint8 channel);
bool pwm_add(uint8 channel);
bool pwm_delete(uint8 channel);
bool pwm_exist(uint8 channel);
#endif

View File

@ -1,8 +0,0 @@
#ifndef READLINE_APP_H
#define READLINE_APP_H
#include <stdbool.h>
bool uart_getc(char *c);
#endif /* READLINE_APP_H */

View File

@ -1,26 +0,0 @@
/*
* Definitions to access the Rotary driver
*/
#ifndef __ROTARY_H__
#define __ROTARY_H__
#include "c_types.h"
#define ROTARY_CHANNEL_COUNT 3
typedef struct {
uint32_t pos;
uint32_t time_us;
} rotary_event_t;
int rotary_setup(uint32_t channel, int phaseA, int phaseB, int press, task_handle_t tasknumber);
bool rotary_getevent(uint32_t channel, rotary_event_t *result);
bool rotary_has_queued_event(uint32_t channel);
int rotary_getpos(uint32_t channel);
int rotary_close(uint32_t channel);
#endif

View File

@ -1,11 +0,0 @@
#ifndef SIGMA_DELTA_APP_H
#define SIGMA_DELTA_APP_H
#include "eagle_soc.h"
#include "c_types.h"
void sigma_delta_setup( void );
void sigma_delta_stop( void );
void sigma_delta_set_prescale_target( sint16 prescale, sint16 target );
#endif

View File

@ -1,56 +0,0 @@
#ifndef SPI_APP_H
#define SPI_APP_H
#ifdef __ESP8266__
# include "spi_register.h"
#endif
#include "eagle_soc.h"
#include "rom.h"
#include "osapi.h"
#include "uart.h"
#include "os_type.h"
/*SPI number define*/
#define SPI 0
#define HSPI 1
//lcd drive function
void spi_lcd_mode_init(uint8 spi_no);
void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit);
//spi master init funtion
void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_div);
// fill MOSI buffer
void spi_mast_set_mosi(uint8 spi_no, uint16 offset, uint8 bitlen, uint32 data);
// retrieve data from MISO buffer
uint32 spi_mast_get_miso(uint8 spi_no, uint16 offset, uint8 bitlen);
// initiate SPI transaction
void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8 addr_bitlen, uint32 addr_data,
uint16 mosi_bitlen, uint8 dummy_bitlen, sint16 miso_bitlen);
//transmit data to esp8266 slave buffer,which needs 16bit transmission ,
//first byte is master command 0x04, second byte is master data
void spi_byte_write_espslave(uint8 spi_no,uint8 data);
//read data from esp8266 slave buffer,which needs 16bit transmission ,
//first byte is master command 0x06, second byte is to read slave data
void spi_byte_read_espslave(uint8 spi_no,uint8 *data);
//esp8266 slave mode initial
void spi_slave_init(uint8 spi_no);
//esp8266 slave isr handle funtion,tiggered when any transmission is finished.
//the function is registered in spi_slave_init.
void spi_slave_isr_handler(void *para);
//hspi test function, used to test esp8266 spi slave
void hspi_master_readwrite_repeat(void);
void ICACHE_FLASH_ATTR
spi_test_init(void);
#endif

View File

@ -1,189 +0,0 @@
/*
* Copyright (c) 2010 - 2011 Espressif System
*
*/
#ifndef SPI_REGISTER_H_INCLUDED
#define SPI_REGISTER_H_INCLUDED
#define REG_SPI_BASE(i) (0x60000200-i*0x100)
#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0)
#define SPI_USR (BIT(18))
#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4)
#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8)
#define SPI_WR_BIT_ORDER (BIT(26))
#define SPI_RD_BIT_ORDER (BIT(25))
#define SPI_QIO_MODE (BIT(24))
#define SPI_DIO_MODE (BIT(23))
#define SPI_QOUT_MODE (BIT(20))
#define SPI_DOUT_MODE (BIT(14))
#define SPI_FASTRD_MODE (BIT(13))
#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10)
#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14)
#define SPI_CS_DELAY_NUM 0x0000000F
#define SPI_CS_DELAY_NUM_S 28
#define SPI_CS_DELAY_MODE 0x00000003
#define SPI_CS_DELAY_MODE_S 26
#define SPI_MOSI_DELAY_NUM 0x00000007
#define SPI_MOSI_DELAY_NUM_S 23
#define SPI_MOSI_DELAY_MODE 0x00000003
#define SPI_MOSI_DELAY_MODE_S 21
#define SPI_MISO_DELAY_NUM 0x00000007
#define SPI_MISO_DELAY_NUM_S 18
#define SPI_MISO_DELAY_MODE 0x00000003
#define SPI_MISO_DELAY_MODE_S 16
#define SPI_CK_OUT_HIGH_MODE 0x0000000F
#define SPI_CK_OUT_HIGH_MODE_S 12
#define SPI_CK_OUT_LOW_MODE 0x0000000F
#define SPI_CK_OUT_LOW_MODE_S 8
#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18)
#define SPI_CLK_EQU_SYSCLK (BIT(31))
#define SPI_CLKDIV_PRE 0x00001FFF
#define SPI_CLKDIV_PRE_S 18
#define SPI_CLKCNT_N 0x0000003F
#define SPI_CLKCNT_N_S 12
#define SPI_CLKCNT_H 0x0000003F
#define SPI_CLKCNT_H_S 6
#define SPI_CLKCNT_L 0x0000003F
#define SPI_CLKCNT_L_S 0
#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C)
#define SPI_USR_COMMAND (BIT(31))
#define SPI_USR_ADDR (BIT(30))
#define SPI_USR_DUMMY (BIT(29))
#define SPI_USR_MISO (BIT(28))
#define SPI_USR_MOSI (BIT(27))
#define SPI_USR_MOSI_HIGHPART (BIT(25))
#define SPI_USR_MISO_HIGHPART (BIT(24))
#define SPI_SIO (BIT(16))
#define SPI_FWRITE_QIO (BIT(15))
#define SPI_FWRITE_DIO (BIT(14))
#define SPI_FWRITE_QUAD (BIT(13))
#define SPI_FWRITE_DUAL (BIT(12))
#define SPI_WR_BYTE_ORDER (BIT(11))
#define SPI_RD_BYTE_ORDER (BIT(10))
#define SPI_CK_OUT_EDGE (BIT(7))
#define SPI_CK_I_EDGE (BIT(6))
#define SPI_CS_SETUP (BIT(5))
#define SPI_CS_HOLD (BIT(4))
#define SPI_FLASH_MODE (BIT(2))
#define SPI_DOUTDIN (BIT(0))
#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20)
#define SPI_USR_ADDR_BITLEN 0x0000003F
#define SPI_USR_ADDR_BITLEN_S 26
#define SPI_USR_MOSI_BITLEN 0x000001FF
#define SPI_USR_MOSI_BITLEN_S 17
#define SPI_USR_MISO_BITLEN 0x000001FF
#define SPI_USR_MISO_BITLEN_S 8
#define SPI_USR_DUMMY_CYCLELEN 0x000000FF
#define SPI_USR_DUMMY_CYCLELEN_S 0
#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24)
#define SPI_USR_COMMAND_BITLEN 0x0000000F
#define SPI_USR_COMMAND_BITLEN_S 28
#define SPI_USR_COMMAND_VALUE 0x0000FFFF
#define SPI_USR_COMMAND_VALUE_S 0
#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28)
#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C)
#define SPI_CS2_DIS (BIT(2))
#define SPI_CS1_DIS (BIT(1))
#define SPI_CS0_DIS (BIT(0))
#define SPI_IDLE_EDGE (BIT(29))
#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30)
#define SPI_SYNC_RESET (BIT(31))
#define SPI_SLAVE_MODE (BIT(30))
#define SPI_SLV_WR_RD_BUF_EN (BIT(29))
#define SPI_SLV_WR_RD_STA_EN (BIT(28))
#define SPI_SLV_CMD_DEFINE (BIT(27))
#define SPI_TRANS_CNT 0x0000000F
#define SPI_TRANS_CNT_S 23
#define SPI_TRANS_DONE_EN (BIT(9))
#define SPI_SLV_WR_STA_DONE_EN (BIT(8))
#define SPI_SLV_RD_STA_DONE_EN (BIT(7))
#define SPI_SLV_WR_BUF_DONE_EN (BIT(6))
#define SPI_SLV_RD_BUF_DONE_EN (BIT(5))
#define SLV_SPI_INT_EN 0x0000001f
#define SLV_SPI_INT_EN_S 5
#define SPI_TRANS_DONE (BIT(4))
#define SPI_SLV_WR_STA_DONE (BIT(3))
#define SPI_SLV_RD_STA_DONE (BIT(2))
#define SPI_SLV_WR_BUF_DONE (BIT(1))
#define SPI_SLV_RD_BUF_DONE (BIT(0))
#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34)
#define SPI_SLV_STATUS_BITLEN 0x0000001F
#define SPI_SLV_STATUS_BITLEN_S 27
#define SPI_SLV_BUF_BITLEN 0x000001FF
#define SPI_SLV_BUF_BITLEN_S 16
#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F
#define SPI_SLV_RD_ADDR_BITLEN_S 10
#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F
#define SPI_SLV_WR_ADDR_BITLEN_S 4
#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3))
#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2))
#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1))
#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0))
#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38)
#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF
#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24
#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF
#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16
#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF
#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8
#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF
#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0
#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C)
#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF
#define SPI_SLV_WRSTA_CMD_VALUE_S 24
#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF
#define SPI_SLV_RDSTA_CMD_VALUE_S 16
#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF
#define SPI_SLV_WRBUF_CMD_VALUE_S 8
#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF
#define SPI_SLV_RDBUF_CMD_VALUE_S 0
#define SPI_W0(i) (REG_SPI_BASE(i) +0x40)
#define SPI_W1(i) (REG_SPI_BASE(i) +0x44)
#define SPI_W2(i) (REG_SPI_BASE(i) +0x48)
#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C)
#define SPI_W4(i) (REG_SPI_BASE(i) +0x50)
#define SPI_W5(i) (REG_SPI_BASE(i) +0x54)
#define SPI_W6(i) (REG_SPI_BASE(i) +0x58)
#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C)
#define SPI_W8(i) (REG_SPI_BASE(i) +0x60)
#define SPI_W9(i) (REG_SPI_BASE(i) +0x64)
#define SPI_W10(i) (REG_SPI_BASE(i) +0x68)
#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C)
#define SPI_W12(i) (REG_SPI_BASE(i) +0x70)
#define SPI_W13(i) (REG_SPI_BASE(i) +0x74)
#define SPI_W14(i) (REG_SPI_BASE(i) +0x78)
#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C)
#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC)
#define SPI_INT_HOLD_ENA 0x00000003
#define SPI_INT_HOLD_ENA_S 0
#endif // SPI_REGISTER_H_INCLUDED

View File

@ -1,332 +0,0 @@
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __UART_H__
#define __UART_H__
#include "c_types.h" /* for BIT(n) definition */
#include "uart_register.h"
#include "task/task.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
UART_WordLength_5b = 0x0,
UART_WordLength_6b = 0x1,
UART_WordLength_7b = 0x2,
UART_WordLength_8b = 0x3
} UART_WordLength;
typedef enum {
USART_StopBits_1 = 0x1,
USART_StopBits_1_5 = 0x2,
USART_StopBits_2 = 0x3,
} UART_StopBits;
typedef enum {
UART0 = 0x0,
UART1 = 0x1,
} UART_Port;
typedef enum {
USART_Parity_None = 0x2,
USART_Parity_Even = 0x0,
USART_Parity_Odd = 0x1
} UART_ParityMode;
typedef enum {
BIT_RATE_300 = 300,
BIT_RATE_600 = 600,
BIT_RATE_1200 = 1200,
BIT_RATE_2400 = 2400,
BIT_RATE_4800 = 4800,
BIT_RATE_9600 = 9600,
BIT_RATE_19200 = 19200,
BIT_RATE_38400 = 38400,
BIT_RATE_57600 = 57600,
BIT_RATE_74880 = 74880,
BIT_RATE_115200 = 115200,
BIT_RATE_230400 = 230400,
BIT_RATE_460800 = 460800,
BIT_RATE_921600 = 921600,
BIT_RATE_1843200 = 1843200,
BIT_RATE_3686400 = 3686400,
} UART_BautRate; //you can add any rate you need in this range
typedef enum {
USART_HardwareFlowControl_None = 0x0,
USART_HardwareFlowControl_RTS = 0x1,
USART_HardwareFlowControl_CTS = 0x2,
USART_HardwareFlowControl_CTS_RTS = 0x3
} UART_HwFlowCtrl;
typedef enum {
UART_None_Inverse = 0x0,
UART_Rxd_Inverse = UART_RXD_INV,
UART_CTS_Inverse = UART_CTS_INV,
UART_Txd_Inverse = UART_TXD_INV,
UART_RTS_Inverse = UART_RTS_INV,
} UART_LineLevelInverse;
typedef struct {
UART_BautRate baud_rate;
UART_WordLength data_bits;
UART_ParityMode parity; // chip size in byte
UART_StopBits stop_bits;
UART_HwFlowCtrl flow_ctrl;
uint8 UART_RxFlowThresh ;
uint32 UART_InverseMask;
} UART_ConfigTypeDef;
typedef struct {
uint32 UART_IntrEnMask;
uint8 UART_RX_TimeOutIntrThresh;
uint8 UART_TX_FifoEmptyIntrThresh;
uint8 UART_RX_FifoFullIntrThresh;
} UART_IntrConfTypeDef;
//=======================================
/** \defgroup Driver_APIs Driver APIs
* @brief Driver APIs
*/
/** @addtogroup Driver_APIs
* @{
*/
/** \defgroup UART_Driver_APIs UART Driver APIs
* @brief UART driver APIs
*/
/** @addtogroup UART_Driver_APIs
* @{
*/
/**
* @brief Set UART baud rate.
*
* Example : uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
*
* @param UART_Port uart_no : UART0 or UART1
* @param uint16 div : frequency divider
*
* @return null
*/
void uart_div_modify(UART_Port uart_no, uint16 div);
/**
* @brief Wait uart tx fifo empty, do not use it if tx flow control enabled.
*
* @param UART_Port uart_no : UART0 or UART1
*
* @return null
*/
void UART_WaitTxFifoEmpty(UART_Port uart_no); //do not use if tx flow control enabled
/**
* @brief Clear uart tx fifo and rx fifo.
*
* @param UART_Port uart_no : UART0 or UART1
*
* @return null
*/
void UART_ResetFifo(UART_Port uart_no);
/**
* @brief Clear uart interrupt flags.
*
* @param UART_Port uart_no : UART0 or UART1
* @param uint32 clr_mask : To clear the interrupt bits
*
* @return null
*/
void UART_ClearIntrStatus(UART_Port uart_no, uint32 clr_mask);
/**
* @brief Enable uart interrupts .
*
* @param UART_Port uart_no : UART0 or UART1
* @param uint32 ena_mask : To enable the interrupt bits
*
* @return null
*/
void UART_SetIntrEna(UART_Port uart_no, uint32 ena_mask);
/**
* @brief Register an application-specific interrupt handler for Uarts interrupts.
*
* @param void *fn : interrupt handler for Uart interrupts.
* @param void *arg : interrupt handler's arg.
*
* @return null
*/
void UART_intr_handler_register(void *fn, void *arg);
/**
* @brief Config from which serial output printf function.
*
* @param UART_Port uart_no : UART0 or UART1
*
* @return null
*/
void UART_SetPrintPort(UART_Port uart_no);
/**
* @brief Config Common parameters of serial ports.
*
* @param UART_Port uart_no : UART0 or UART1
* @param UART_ConfigTypeDef *pUARTConfig : parameters structure
*
* @return null
*/
void UART_ParamConfig(UART_Port uart_no, const UART_ConfigTypeDef *pUARTConfig);
/**
* @brief Config types of uarts.
*
* @param UART_Port uart_no : UART0 or UART1
* @param UART_IntrConfTypeDef *pUARTIntrConf : parameters structure
*
* @return null
*/
void UART_IntrConfig(UART_Port uart_no, const UART_IntrConfTypeDef *pUARTIntrConf);
/**
* @brief Config the length of the uart communication data bits.
*
* @param UART_Port uart_no : UART0 or UART1
* @param UART_WordLength len : the length of the uart communication data bits
*
* @return null
*/
void UART_SetWordLength(UART_Port uart_no, UART_WordLength len);
/**
* @brief Config the length of the uart communication stop bits.
*
* @param UART_Port uart_no : UART0 or UART1
* @param UART_StopBits bit_num : the length uart communication stop bits
*
* @return null
*/
void UART_SetStopBits(UART_Port uart_no, UART_StopBits bit_num);
/**
* @brief Configure whether to open the parity.
*
* @param UART_Port uart_no : UART0 or UART1
* @param UART_ParityMode Parity_mode : the enum of uart parity configuration
*
* @return null
*/
void UART_SetParity(UART_Port uart_no, UART_ParityMode Parity_mode) ;
/**
* @brief Configure the Baud rate.
*
* @param UART_Port uart_no : UART0 or UART1
* @param uint32 baud_rate : the Baud rate
*
* @return null
*/
void UART_SetBaudrate(UART_Port uart_no, uint32 baud_rate);
/**
* @brief Configure Hardware flow control.
*
* @param UART_Port uart_no : UART0 or UART1
* @param UART_HwFlowCtrl flow_ctrl : Hardware flow control mode
* @param uint8 rx_thresh : threshold of Hardware flow control
*
* @return null
*/
void UART_SetFlowCtrl(UART_Port uart_no, UART_HwFlowCtrl flow_ctrl, uint8 rx_thresh);
/**
* @brief Configure trigging signal of uarts.
*
* @param UART_Port uart_no : UART0 or UART1
* @param UART_LineLevelInverse inverse_mask : Choose need to flip the IO
*
* @return null
*/
void UART_SetLineInverse(UART_Port uart_no, UART_LineLevelInverse inverse_mask) ;
/**
* @}
*/
/**
* @}
*/
/**
* Set up uart0 for NodeMCU console use.
* @param config The UART params to apply.
* @param tsk NodeMCU task to be notified when there is input pending.
*/
void uart_init_uart0_console (const UART_ConfigTypeDef *config, task_handle_t tsk);
/**
* Generic UART send interface.
* @param uart_no Which UART to send on (UART0 or UART1).
* @param c The character to send.
*/
void uart_tx_one_char (uint32_t uart_no, uint8_t c);
/**
* Switch (or unswitch) UART0 to the alternate pins.
* Currently only ESP8266.
* @param on True to use alternate RX/TX pins, false to use default pins.
*/
void uart0_alt (bool on);
/**
* Attempts to pull a character off the UART0 receive queue.
* @param c Where to stash the received character, if any.
* @returns True if a character was stored in @c, false if no char available.
*/
bool uart0_getc (char *c);
/**
* Convenience/consistency wrapper for UART0 output.
* @param c The character to output.
*/
static inline void uart0_putc (char c) { uart_tx_one_char (UART0, c); }
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,74 +0,0 @@
#ifndef __MODULE_H__
#define __MODULE_H__
#include "user_modules.h"
#include "lrodefs.h"
/* Registering a module within NodeMCU is really easy these days!
*
* Most of the work is done by a combination of pre-processor, compiler
* and linker "magic". Gone are the days of needing to update 4+ separate
* files just to register a module!
*
* You will need:
* - to include this header
* - a name for the module
* - a LUA_REG_TYPE module map
* - optionally, an init function
*
* Then simply put a line like this at the bottom of your module file:
*
* NODEMCU_MODULE(MYNAME, "myname", myname_map, luaopen_myname);
*
* or perhaps
*
* NODEMCU_MODULE(MYNAME, "myname", myname_map, NULL);
*
* if you don't need an init function.
*
* When you've done this, the module can be enabled in user_modules.h with:
*
* #define LUA_USE_MODULES_MYNAME
*
* and within NodeMCU you access it with myname.foo(), assuming you have
* a foo function in your module.
*/
#define MODULE_EXPAND_(x) x
#define MODULE_PASTE_(x,y) x##y
#define MODULE_EXPAND_PASTE_(x,y) MODULE_PASTE_(x,y)
#define LOCK_IN_SECTION(s) __attribute__((used,unused,section(s)))
/* For the ROM table, we name the variable according to ( | denotes concat):
* cfgname | _module_selected | LUA_USE_MODULES_##cfgname
* where the LUA_USE_MODULES_XYZ macro is first expanded to yield either
* an empty string (or 1) if the module has been enabled, or the literal
* LUA_USE_MOUDLE_XYZ in the case it hasn't. Thus, the name of the variable
* ends up looking either like XYZ_module_enabled, or if not enabled,
* XYZ_module_enabledLUA_USE_MODULES_XYZ. This forms the basis for
* letting the build system detect automatically (via nm) which modules need
* to be linked in.
*/
#define NODEMCU_MODULE(cfgname, luaname, map, initfunc) \
const LOCK_IN_SECTION(".lua_libs") \
luaL_Reg MODULE_PASTE_(lua_lib_,cfgname) = { luaname, initfunc }; \
const LOCK_IN_SECTION(".lua_rotable") \
luaR_table MODULE_EXPAND_PASTE_(cfgname,MODULE_EXPAND_PASTE_(_module_selected,MODULE_PASTE_(LUA_USE_MODULES_,cfgname))) \
= { luaname, map }
/* System module registration support, not using LUA_USE_MODULES_XYZ. */
#define BUILTIN_LIB_INIT(name, luaname, initfunc) \
const LOCK_IN_SECTION(".lua_libs") \
luaL_Reg MODULE_PASTE_(lua_lib_,name) = { luaname, initfunc }
#define BUILTIN_LIB(name, luaname, map) \
const LOCK_IN_SECTION(".lua_rotable") \
luaR_table MODULE_PASTE_(lua_rotable_,name) = { luaname, map }
#if !defined(LUA_CROSS_COMPILER) && !(MIN_OPT_LEVEL==2 && LUA_OPTIMIZE_MEMORY==2)
# error "NodeMCU modules must be built with LTR enabled (MIN_OPT_LEVEL=2 and LUA_OPTIMIZE_MEMORY=2)"
#endif
#endif

View File

@ -1,254 +0,0 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
* Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* 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. 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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __NETIF_ETHARP_H__
#define __NETIF_ETHARP_H__
#include "lwip/opt.h"
#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ETHARP_HWADDR_LEN
#define ETHARP_HWADDR_LEN 6
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct eth_addr {
PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** Ethernet header */
struct eth_hdr {
#if ETH_PAD_SIZE
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
#endif
PACK_STRUCT_FIELD(struct eth_addr dest);
PACK_STRUCT_FIELD(struct eth_addr src);
PACK_STRUCT_FIELD(u16_t type);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
#if ETHARP_SUPPORT_VLAN
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** VLAN header inserted between ethernet header and payload
* if 'type' in ethernet header is ETHTYPE_VLAN.
* See IEEE802.Q */
struct eth_vlan_hdr {
PACK_STRUCT_FIELD(u16_t tpid);
PACK_STRUCT_FIELD(u16_t prio_vid);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_VLAN_HDR 4
#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF)
#endif /* ETHARP_SUPPORT_VLAN */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** the ARP message, see RFC 826 ("Packet format") */
struct etharp_hdr {
PACK_STRUCT_FIELD(u16_t hwtype);
PACK_STRUCT_FIELD(u16_t proto);
PACK_STRUCT_FIELD(u8_t hwlen);
PACK_STRUCT_FIELD(u8_t protolen);
PACK_STRUCT_FIELD(u16_t opcode);
PACK_STRUCT_FIELD(struct eth_addr shwaddr);
PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_ETHARP_HDR 28
#define SIZEOF_ETHARP_MINSIZE 46
#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR)
#define SIZEOF_ETHARP_WITHPAD (SIZEOF_ETH_HDR + SIZEOF_ETHARP_MINSIZE)
/** 5 seconds period */
#define ARP_TMR_INTERVAL 5000
#define ETHTYPE_ARP 0x0806
#define ETHTYPE_IP 0x0800
#define ETHTYPE_VLAN 0x8100
#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */
#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */
#define ETHTYPE_PAE 0x888e
/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
* or known to be 32-bit aligned within the protocol header. */
#ifndef ETHADDR32_COPY
#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
#endif
/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local
* variables and known to be 16-bit aligned within the protocol header. */
#ifndef ETHADDR16_COPY
#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
#endif
#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
/** ARP message types (opcodes) */
#define ARP_REQUEST 1
#define ARP_REPLY 2
/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type)
* to a filter function that returns the correct netif when using multiple
* netifs on one hardware interface where the netif's low-level receive
* routine cannot decide for the correct netif (e.g. when mapping multiple
* IP addresses to one hardware interface).
*/
#ifndef LWIP_ARP_FILTER_NETIF
#define LWIP_ARP_FILTER_NETIF 0
#endif
#if ARP_QUEUEING
/** struct for queueing outgoing packets for unknown address
* defined here to be accessed by memp.h
*/
struct etharp_q_entry {
struct etharp_q_entry *next;
struct pbuf *p;
};
#endif /* ARP_QUEUEING */
#define etharp_init() /* Compatibility define, not init needed. */
void etharp_tmr(void)ICACHE_FLASH_ATTR;
s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
struct eth_addr **eth_ret, ip_addr_t **ip_ret)ICACHE_FLASH_ATTR;
err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;
err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)ICACHE_FLASH_ATTR;
err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;
/** For Ethernet network interfaces, we might want to send "gratuitous ARP";
* this is an ARP packet sent by a node in order to spontaneously cause other
* nodes to update an entry in their ARP cache.
* From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
void etharp_cleanup_netif(struct netif *netif);
#if ETHARP_SUPPORT_STATIC_ENTRIES
err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)ICACHE_FLASH_ATTR;
err_t etharp_remove_static_entry(ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
#if LWIP_AUTOIP
err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
const struct eth_addr *ethdst_addr,
const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
const u16_t opcode)ICACHE_FLASH_ATTR;
#endif /* LWIP_AUTOIP */
#endif /* LWIP_ARP */
err_t ethernet_input(struct pbuf *p, struct netif *netif)ICACHE_FLASH_ATTR;
#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0)
extern const struct eth_addr ethbroadcast, ethzero;
#endif /* LWIP_ARP || LWIP_ETHERNET */
#if 0
/** Ethernet header */
#ifndef ETHARP_HWADDR_LEN
#define ETHARP_HWADDR_LEN 6
#endif
struct eth_addr {
PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);
} PACK_STRUCT_STRUCT;
struct eth_hdr {
#if ETH_PAD_SIZE
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
#endif
PACK_STRUCT_FIELD(struct eth_addr dest);
PACK_STRUCT_FIELD(struct eth_addr src);
PACK_STRUCT_FIELD(u16_t type);
} PACK_STRUCT_STRUCT;
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
#endif
#ifdef __cplusplus
}
#endif
#endif /* __NETIF_ARP_H__ */

View File

@ -1,173 +0,0 @@
/* $NetBSD: if_llc.h,v 1.12 1999/11/19 20:41:19 thorpej Exp $ */
/*-
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
* 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.
*
* @(#)if_llc.h 8.1 (Berkeley) 6/10/93
* $FreeBSD$
*/
#ifndef _NET_IF_LLC_H_
#define _NET_IF_LLC_H_
/*
* IEEE 802.2 Link Level Control headers, for use in conjunction with
* 802.{3,4,5} media access control methods.
*
* Headers here do not use bit fields due to shortcommings in many
* compilers.
*/
struct llc {
uint8_t llc_dsap;
uint8_t llc_ssap;
union {
struct {
uint8_t control;
uint8_t format_id;
uint8_t class;
uint8_t window_x2;
} __packed type_u;
struct {
uint8_t num_snd_x2;
uint8_t num_rcv_x2;
} __packed type_i;
struct {
uint8_t control;
uint8_t num_rcv_x2;
} __packed type_s;
struct {
uint8_t control;
/*
* We cannot put the following fields in a structure because
* the structure rounding might cause padding.
*/
uint8_t frmr_rej_pdu0;
uint8_t frmr_rej_pdu1;
uint8_t frmr_control;
uint8_t frmr_control_ext;
uint8_t frmr_cause;
} __packed type_frmr;
struct {
uint8_t control;
uint8_t org_code[3];
uint16_t ether_type;
} __packed type_snap;
struct {
uint8_t control;
uint8_t control_ext;
} __packed type_raw;
} __packed llc_un;
} __packed;
struct frmrinfo {
uint8_t frmr_rej_pdu0;
uint8_t frmr_rej_pdu1;
uint8_t frmr_control;
uint8_t frmr_control_ext;
uint8_t frmr_cause;
} __packed;
#define llc_control llc_un.type_u.control
#define llc_control_ext llc_un.type_raw.control_ext
#define llc_fid llc_un.type_u.format_id
#define llc_class llc_un.type_u.class
#define llc_window llc_un.type_u.window_x2
#define llc_frmrinfo llc_un.type_frmr.frmr_rej_pdu0
#define llc_frmr_pdu0 llc_un.type_frmr.frmr_rej_pdu0
#define llc_frmr_pdu1 llc_un.type_frmr.frmr_rej_pdu1
#define llc_frmr_control llc_un.type_frmr.frmr_control
#define llc_frmr_control_ext llc_un.type_frmr.frmr_control_ext
#define llc_frmr_cause llc_un.type_frmr.frmr_cause
#define llc_snap llc_un.type_snap
/*
* Don't use sizeof(struct llc_un) for LLC header sizes
*/
#define LLC_ISFRAMELEN 4
#define LLC_UFRAMELEN 3
#define LLC_FRMRLEN 7
#define LLC_SNAPFRAMELEN 8
#ifdef CTASSERT
CTASSERT(sizeof (struct llc) == LLC_SNAPFRAMELEN);
#endif
/*
* Unnumbered LLC format commands
*/
#define LLC_UI 0x3
#define LLC_UI_P 0x13
#define LLC_DISC 0x43
#define LLC_DISC_P 0x53
#define LLC_UA 0x63
#define LLC_UA_P 0x73
#define LLC_TEST 0xe3
#define LLC_TEST_P 0xf3
#define LLC_FRMR 0x87
#define LLC_FRMR_P 0x97
#define LLC_DM 0x0f
#define LLC_DM_P 0x1f
#define LLC_XID 0xaf
#define LLC_XID_P 0xbf
#define LLC_SABME 0x6f
#define LLC_SABME_P 0x7f
/*
* Supervisory LLC commands
*/
#define LLC_RR 0x01
#define LLC_RNR 0x05
#define LLC_REJ 0x09
/*
* Info format - dummy only
*/
#define LLC_INFO 0x00
/*
* ISO PDTR 10178 contains among others
*/
#define LLC_8021D_LSAP 0x42
#define LLC_X25_LSAP 0x7e
#define LLC_SNAP_LSAP 0xaa
#define LLC_ISO_LSAP 0xfe
#define RFC1042_LEN 6
#define RFC1042 {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}
#define ETHERNET_TUNNEL {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8}
/*
* copied from sys/net/ethernet.h
*/
#define ETHERTYPE_AARP 0x80F3 /* AppleTalk AARP */
#define ETHERTYPE_IPX 0x8137 /* Novell (old) NetWare IPX (ECONFIG E option) */
#endif /* _NET_IF_LLC_H_ */

View File

@ -1,190 +0,0 @@
/*****************************************************************************
* ppp_oe.h - PPP Over Ethernet implementation for lwIP.
*
* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE 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 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.
*
******************************************************************************
* REVISION HISTORY
*
* 06-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
*****************************************************************************/
/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Martin Husemann <martin@NetBSD.org>.
*
* 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 the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifndef PPP_OE_H
#define PPP_OE_H
#include "lwip/opt.h"
#if PPPOE_SUPPORT > 0
#include "netif/etharp.h"
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct pppoehdr {
PACK_STRUCT_FIELD(u8_t vertype);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t session);
PACK_STRUCT_FIELD(u16_t plen);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct pppoetag {
PACK_STRUCT_FIELD(u16_t tag);
PACK_STRUCT_FIELD(u16_t len);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define PPPOE_STATE_INITIAL 0
#define PPPOE_STATE_PADI_SENT 1
#define PPPOE_STATE_PADR_SENT 2
#define PPPOE_STATE_SESSION 3
#define PPPOE_STATE_CLOSING 4
/* passive */
#define PPPOE_STATE_PADO_SENT 1
#define PPPOE_HEADERLEN sizeof(struct pppoehdr)
#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */
#define PPPOE_TAG_EOL 0x0000 /* end of list */
#define PPPOE_TAG_SNAME 0x0101 /* service name */
#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */
#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */
#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */
#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */
#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */
#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */
#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */
#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */
#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */
#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */
#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */
#ifndef ETHERMTU
#define ETHERMTU 1500
#endif
/* two byte PPP protocol discriminator, then IP data */
#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2)
#ifndef PPPOE_MAX_AC_COOKIE_LEN
#define PPPOE_MAX_AC_COOKIE_LEN 64
#endif
struct pppoe_softc {
struct pppoe_softc *next;
struct netif *sc_ethif; /* ethernet interface we are using */
int sc_pd; /* ppp unit number */
void (*sc_linkStatusCB)(int pd, int up);
int sc_state; /* discovery phase or session connected */
struct eth_addr sc_dest; /* hardware address of concentrator */
u16_t sc_session; /* PPPoE session id */
#ifdef PPPOE_TODO
char *sc_service_name; /* if != NULL: requested name of service */
char *sc_concentrator_name; /* if != NULL: requested concentrator id */
#endif /* PPPOE_TODO */
u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */
size_t sc_ac_cookie_len; /* length of cookie data */
#ifdef PPPOE_SERVER
u8_t *sc_hunique; /* content of host unique we must echo back */
size_t sc_hunique_len; /* length of host unique */
#endif
int sc_padi_retried; /* number of PADI retries already done */
int sc_padr_retried; /* number of PADR retries already done */
};
#define pppoe_init() /* compatibility define, no initialization needed */
err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr);
err_t pppoe_destroy(struct netif *ifp);
int pppoe_connect(struct pppoe_softc *sc);
void pppoe_disconnect(struct pppoe_softc *sc);
void pppoe_disc_input(struct netif *netif, struct pbuf *p);
void pppoe_data_input(struct netif *netif, struct pbuf *p);
err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);
/** used in ppp.c */
#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN)
#endif /* PPPOE_SUPPORT */
#endif /* PPP_OE_H */

View File

@ -1,25 +0,0 @@
/*
* Copyright (c) 2010-2011 Espressif System
*
*/
#ifndef _WLAN_LWIP_IF_H_
#define _WLAN_LWIP_IF_H_
#define LWIP_IF0_PRIO 28
#define LWIP_IF1_PRIO 29
enum {
SIG_LWIP_RX = 0,
};
struct netif * eagle_lwip_if_alloc(struct ieee80211_conn *conn, const uint8 *macaddr, struct ip_info *info);
struct netif * eagle_lwip_getif(uint8 index);
#ifndef IOT_SIP_MODE
sint8 ieee80211_output_pbuf(struct netif *ifp, struct pbuf* pb);
#else
sint8 ieee80211_output_pbuf(struct ieee80211_conn *conn, esf_buf *eb);
#endif
#endif /* _WLAN_LWIP_IF_H_ */

Some files were not shown because too many files have changed in this diff Show More