mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'master' into feature/dualcore_spi_flash_api
* master: (130 commits) lwip: Define LWIP_ESP8266 in port lwipopts.h not gcc command line CI: Build the esp-idf-template with the matching branch name, if it exists README: Add Resources section with some links Rename README.buildenv to docs/build_system.rst and ReST-ify it Eclipse docs: Easier to just replace entire PATH, msys32 has everything we need to build/flash test_build_system: Print ESP_IDF_TEMPLATE_GIT for easier debugging Name component makefiles component.mk instead of Makefile Eclipse doc: Add troubleshooting note about Makefile directories eclipse_make.sh: Fix printing of make directory Move bin/eclipse_windows_make.sh to tools/windows_eclipse_make.sh Eclipse docs: Prepend IDF paths to beginning of PATH Set default SPI flash access mode to DIO FreeRTOS: temporary solution for memory canaries and memory debug tcpip_adapter: fix dhcp client work flow event: not post got ip event if static is invalid tcpip_adapter: typedef clean up event: post got ip event when use static ip tcpip_adapter: use dhcp callback to post got ip event dhcp: add dhcp callback lwip: remove netif_reg_addr_change_cb ...
This commit is contained in:
commit
be4dfed822
@ -3,6 +3,9 @@ stages:
|
||||
- test
|
||||
- deploy
|
||||
|
||||
before_script:
|
||||
- git submodule update --init --recursive
|
||||
|
||||
build_template_app:
|
||||
stage: build
|
||||
image: espressif/esp32-ci-env
|
||||
@ -15,6 +18,10 @@ build_template_app:
|
||||
script:
|
||||
- git clone https://github.com/espressif/esp-idf-template.git
|
||||
- cd esp-idf-template
|
||||
# Try to use the same branch name for esp-idf-template that we're
|
||||
# using on esp-idf. If it doesn't exist then just stick to the default
|
||||
# branch
|
||||
- git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..."
|
||||
- make defconfig
|
||||
- make all
|
||||
|
||||
@ -25,6 +32,14 @@ test_nvs_on_host:
|
||||
- cd components/nvs_flash/test
|
||||
- make test
|
||||
|
||||
test_build_system:
|
||||
stage: test
|
||||
image: espressif/esp32-ci-env
|
||||
variables:
|
||||
IDF_PATH: "$CI_PROJECT_DIR"
|
||||
script:
|
||||
- ./make/test_build_system.sh
|
||||
|
||||
push_master_to_github:
|
||||
stage: deploy
|
||||
only:
|
||||
|
265
README.buildenv
265
README.buildenv
@ -1,265 +0,0 @@
|
||||
The build structure of the Espressif IoT Development Framework explained.
|
||||
|
||||
An ESP-IDF project can be seen as an almagation of a number of components.
|
||||
For example, for a webserver that shows the current humidity, we would
|
||||
have:
|
||||
- The ESP32 base libraries (libc, rom bindings etc)
|
||||
- The WiFi drivers
|
||||
- A TCP/IP stack
|
||||
- The FreeRTOS operating system
|
||||
- A webserver
|
||||
- A driver for an humidity sensor
|
||||
- Main code tying it all together
|
||||
|
||||
ESP-IDF makes these components explicit and configurable. To do that, when a project
|
||||
is compiled, the build environment will look up all the components in the
|
||||
ESP-IDF directories, the project directories and optionally custom other component
|
||||
directories. It then allows the user to configure compile-time options using
|
||||
a friendly text-based menu system to customize the ESP-IDF as well as other components
|
||||
to the requirements of the project. After the components are customized, the
|
||||
build process will compile everything into an output file, which can then be uploaded
|
||||
into a board in a way that can also be defined by components.
|
||||
|
||||
A project in this sense is defined as a directory under which all the files required
|
||||
to build it live, excluding the ESP-IDF files and the toolchain. A simple project
|
||||
tree looks like this:
|
||||
|
||||
- myProject/ - build/
|
||||
- components/ - component1/ - Makefile
|
||||
- Kconfig
|
||||
- src1.c
|
||||
- component2/ - Makefile
|
||||
- Kconfig
|
||||
- src1.c
|
||||
- main/ - src1.c
|
||||
- src2.c
|
||||
- Makefile
|
||||
|
||||
|
||||
As we can see, a project consists of a components/ subdirectory containing its
|
||||
components as well as one or more directories containing the project-specific
|
||||
sources; by default a single directory called 'main' is assumed. The project
|
||||
directory will also have a Makefile where the projects name as well as optionally
|
||||
other options are defined. After compilation, the project directory will contain
|
||||
a 'build'-directory containing all of the objects, libraries and other generated
|
||||
files as well as the final binary.
|
||||
|
||||
Components also have a Makefile containing various definititions influencing
|
||||
the build process of the component as well as the project it's used in, as
|
||||
well as a Kconfig file defining the compile-time options that are settable
|
||||
by means of the menu system.
|
||||
|
||||
|
||||
Project makefile variables that can be set by the programmer:
|
||||
PROJECT_NAME: Mandatory. Name for the project
|
||||
BUILD_DIR_BASE: Set the directory where all objects/libraries/binaries end up in.
|
||||
Defaults to $(PROJECT_PATH)/build
|
||||
COMPONENT_DIRS: Search path for components. Defaults to the component/ directories
|
||||
in the ESP-IDF path and the project path.
|
||||
COMPONENTS: A list of component names. Defaults to all the component found in the
|
||||
COMPONENT_DIRS directory
|
||||
EXTRA_COMPONENT_DIRS: Defaults to unset. Use this to add directories to the default
|
||||
COMPONENT_DIRS.
|
||||
SRCDIRS: Directories under the project dir containing project-specific sources.
|
||||
Defaults to 'main'. These are treated as 'lite' components: they do not have
|
||||
include directories that are passed to the compilation pass of all components and
|
||||
they do not have a Kconfig option.
|
||||
|
||||
|
||||
Component makefile variables that can be set by the programmer:
|
||||
COMPONENT_ADD_INCLUDEDIRS: Relative path to include directories to be added to
|
||||
the entire project
|
||||
COMPONENT_PRIV_INCLUDEDIRS: Relative path to include directories that are only used
|
||||
when compiling this specific component
|
||||
COMPONENT_DEPENDS: Names of any components that need to be compiled before this component.
|
||||
COMPONENT_ADD_LDFLAGS: Ld flags to add for this project. Defaults to -l$(COMPONENT_NAME).
|
||||
Add libraries etc in the current directory as $(abspath libwhatever.a)
|
||||
COMPONENT_EXTRA_INCLUDES: Any extra include paths. These will be prefixed with '-I' and
|
||||
passed to the compiler; please put absolute paths here.
|
||||
COMPONENT_SRCDIRS: Relative directories to look in for sources. Defaults to '.', the current
|
||||
directory (the root of the component) only. Use this to specify any subdirectories. Note
|
||||
that specifying this overwrites the default action of compiling everything in the
|
||||
components root dir; to keep this behaviour please also add '.' as a directory in this
|
||||
list.
|
||||
COMPONENT_OBJS: Object files to compile. Defaults to the .o variants of all .c and .S files
|
||||
that are found in COMPONENT_SRCDIRS.
|
||||
COMPONENT_EXTRA_CLEAN: Files that are generated using rules in the components Makefile
|
||||
that also need to be cleaned
|
||||
COMPONENT_BUILDRECIPE: Recipe to build the component. Optional. Defaults to building all
|
||||
COMPONENT_OBJS and linking them into lib(componentname).a
|
||||
COMPONENT_CLEANRECIPE: Recipe to clean the component. Optional. Defaults to removing
|
||||
all built objects and libraries.
|
||||
COMPONENT_BUILD_DIR: Equals the cwd of the component build, which is the build dir
|
||||
of the component (where all the .o etc files should be created).
|
||||
|
||||
|
||||
These variables are already set early on in the Makefile and the values in it will
|
||||
be usable in component or project Makefiles:
|
||||
CC, LD, AR, OBJCOPY: Xtensa gcc tools
|
||||
HOSTCC, HOSTLD etc: Host gcc tools
|
||||
LDFLAGS, CFLAGS: Set to usable values as defined in ESP-IDF Makefile
|
||||
PROJECT_NAME: Name of the project, as set in project makefile
|
||||
PROJECT_PATH: Path to the root of the project folder
|
||||
COMPONENTS: Name of the components to be included
|
||||
CONFIG_*: Values set by 'make menuconfig' also have corresponding Makefile variables.
|
||||
|
||||
For components, there also are these defines:
|
||||
COMPONENT_PATH: Absolute path to the root of the source tree of the component we're
|
||||
compiling
|
||||
COMPONENT_LIBRARY: The full path to the static library the components compilation pass
|
||||
is supposed to generate
|
||||
|
||||
|
||||
How this works:
|
||||
The Make process is always invoked from the project directory by the
|
||||
user; invoking it anywhere else gives an error. This is what happens if
|
||||
we build a binary:
|
||||
|
||||
The Makefile first determines how it was included. It determines it was
|
||||
included as a project file in this case and will continue to figure out
|
||||
various paths as well as the components available to it. It will also
|
||||
collect the ldflags and includes that the components specify they need.
|
||||
It does this by running a dummy Make on the components with a target that
|
||||
will output these values.
|
||||
|
||||
The Makefile will then create targets to build the lib*.a libraries of
|
||||
all components and make the elf target depend on this. The targets
|
||||
invoke Make on the makefiles of the components in a subshell: this way
|
||||
the components have full freedom to do whatever is necessary to build
|
||||
the library without influencing other components. By default, the
|
||||
component includes the utility makefile $(IDF_PATH)/make/component.mk.
|
||||
This provides default targets and configurations that will work
|
||||
out-of-the-box for most projects.
|
||||
|
||||
For components that have parts that need to be run when building of the
|
||||
project is done, you can create a file called Makefile.projbuild in the
|
||||
component root directory. This file will be included in the main
|
||||
Makefile. For the menu, there's an equivalent: if you want to include
|
||||
options not in the 'components' submenu, create a Kconfig.projbuild and
|
||||
it will be included in the main menu of menuconfig. Take good care when
|
||||
(re)defining stuff here: because it's included with all the other
|
||||
.projbuild files, it's possible to overwrite variables or re-declare
|
||||
targets defined in the ESP-IDF makefile/Kconfig and other .projbuild files
|
||||
|
||||
|
||||
WRITING COMPONENT MAKEFILES
|
||||
|
||||
A component consists of a directory which doubles as the name for the
|
||||
component: a component named 'httpd' lives in a directory called 'httpd'
|
||||
Because components usually live under the project directory (although
|
||||
they can also reside in an other folder), the path to this may be
|
||||
something like /home/myuser/projects/myprojects/components/httpd .
|
||||
|
||||
One of the things that most components will have is a Makefile,
|
||||
containing instructions on how to build the component. Because the
|
||||
build environment tries to set reasonable defaults that will work most
|
||||
of the time, a component Makefile can be pretty small. At the absolute
|
||||
minimum, it will just include the ESP-IDF component makefile, which adds
|
||||
component functionality:
|
||||
|
||||
----8<----
|
||||
include $(IDF_PATH)/make/component.mk
|
||||
---->8----
|
||||
|
||||
This will take all the .c and .S files in the component root and compile
|
||||
them into object files, finally linking them into a library.
|
||||
Subdirectories are ignored; if your project has sources in subdirectories
|
||||
instead of in the root of the component, you can tell that to the build
|
||||
system by setting COMPONENT_SRCDIRS:
|
||||
|
||||
----8<----
|
||||
COMPONENT_SRCDIRS := src1 src2
|
||||
include $(IDF_PATH)/make/component.mk
|
||||
---->8----
|
||||
|
||||
This will compile all source files in the src1/ and src2/ subdirectories
|
||||
instead.
|
||||
|
||||
The standard component.mk logic adds all .S and .c files in the source
|
||||
directories as sources to be compiled unconditionally. It is possible
|
||||
to circumvent that logic and hardcode the objects to be compiled by
|
||||
manually setting the COMPONENT_OBJS variable to the name of the
|
||||
objects that need to be generated:
|
||||
|
||||
----8<----
|
||||
COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o
|
||||
include $(IDF_PATH)/make/component.mk
|
||||
---->8----
|
||||
|
||||
This can also be used in order to conditionally compile some files
|
||||
dependent on the options selected in the Makefile:
|
||||
|
||||
Kconfig:
|
||||
----8<----
|
||||
config FOO_ENABLE_BAR
|
||||
bool "Enable the BAR feature."
|
||||
help
|
||||
This enables the BAR feature of the FOO component.
|
||||
---->8----
|
||||
|
||||
Makefile:
|
||||
----8<----
|
||||
COMPONENT_OBJS := foo_a.o foo_b.o $(if $(CONFIG_FOO_ENABLE_BAR),foo_bar.o foo_bar_interface.o)
|
||||
include $(IDF_PATH)/make/component.mk
|
||||
---->8----
|
||||
|
||||
Some components will have a situation where a source file isn't supplied
|
||||
with the component itself but has to be generated from another file. Say
|
||||
our component has a header file that consists of the converted binary
|
||||
data of a BMP file, converted using a hypothetical tool called bmp2h. The
|
||||
header file is then included in as C source file called graphics_lib.c.
|
||||
|
||||
----8<----
|
||||
COMPONENT_EXTRA_CLEAN := logo.h
|
||||
|
||||
graphics_lib.o: logo.h
|
||||
|
||||
logo.h: $(COMPONENT_PATH)/logo.bmp
|
||||
bmp2h -i $^ -o $@
|
||||
|
||||
include $(IDF_PATH)/make/component.mk
|
||||
---->8----
|
||||
|
||||
In this example, graphics_lib.o and logo.h will be generated in the
|
||||
current directory (the build directory) while logo.bmp comes with the
|
||||
component and resides under the component path. Because logo.h is a
|
||||
generated file, it needs to be cleaned when make clean is called which
|
||||
why it is added to the COMPONENT_EXTRA_CLEAN variable.
|
||||
|
||||
|
||||
This will work just fine, but there's one last cosmetic improvement that
|
||||
can be done. The make system tries to make the make process somewhat
|
||||
easier on the eyes by hiding the commands (unless you run make with the
|
||||
V=1 switch) and this does not do that yet. Here's an improved version
|
||||
that will output in the same style as the rest of the make process:
|
||||
|
||||
----8<----
|
||||
COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h
|
||||
|
||||
graphics_lib.o: logo.h
|
||||
|
||||
logo.h: $(COMPONENT_PATH)/logo.bmp
|
||||
$(vecho) BMP2H $@
|
||||
$(Q) bmp2h -i $^ -o $@
|
||||
|
||||
include $(IDF_PATH)/make/component.mk
|
||||
---->8----
|
||||
|
||||
Obviously, there are cases where all these recipes are insufficient for a
|
||||
certain component, for example when the component is basically a wrapper
|
||||
around another third-party component not originally intended to be
|
||||
compiled under this build system. In that case, it's possible to forego
|
||||
the build system entirely by setting COMPONENT_OWNBUILDTARGET and
|
||||
possibly COMPONENT_OWNCLEANTARGET and defining your own build- and clean
|
||||
target. The build target can do anything as long as it creates
|
||||
$(COMPONENT_LIBRARY) for the main file to link into the project binary,
|
||||
and even that is not necessary: if the COMPONENT_ADD_LDFLAGS variable
|
||||
is set, the component can instruct the linker to do anything else as well.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -49,3 +49,11 @@ The simplest way to use the partition table is to `make menuconfig` and choose o
|
||||
In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table.
|
||||
|
||||
For more details about partition tables and how to create custom variations, view the `docs/partition_tables.rst` file.
|
||||
|
||||
# Resources
|
||||
|
||||
* The [docs directory of the esp-idf repository](https://github.com/espressif/esp-idf/tree/master/docs) contains esp-idf documentation.
|
||||
|
||||
* The [esp32.com forum](http://esp32.com/) is a place to ask questions and find community resources.
|
||||
|
||||
* [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one.
|
||||
|
@ -13,7 +13,7 @@ BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||
BOOTLOADER_BUILD_DIR=$(BUILD_DIR_BASE)/bootloader
|
||||
BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin
|
||||
|
||||
.PHONY: bootloader-clean bootloader-flash bootloader
|
||||
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
|
||||
|
||||
$(BOOTLOADER_BIN): $(COMPONENT_PATH)/src/sdkconfig
|
||||
$(Q) PROJECT_PATH= \
|
||||
|
@ -92,23 +92,28 @@ void IRAM_ATTR call_start_cpu0()
|
||||
//Clear bss
|
||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
||||
|
||||
/* completely reset MMU for both CPUs
|
||||
(in case serial bootloader was running) */
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Read_Disable(1);
|
||||
Cache_Flush(0);
|
||||
Cache_Flush(1);
|
||||
mmu_init(0);
|
||||
mmu_init(1);
|
||||
/* (above steps probably unnecessary for most serial bootloader
|
||||
usage, all that's absolutely needed is that we unmask DROM0
|
||||
cache on the following two lines - normal ROM boot exits with
|
||||
DROM0 cache unmasked, but serial bootloader exits with it
|
||||
masked. However can't hurt to be thorough and reset
|
||||
everything.)
|
||||
*/
|
||||
REG_CLR_BIT(PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
|
||||
REG_CLR_BIT(APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
|
||||
/* completely reset MMU for both CPUs
|
||||
(in case serial bootloader was running) */
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Read_Disable(1);
|
||||
Cache_Flush(0);
|
||||
Cache_Flush(1);
|
||||
mmu_init(0);
|
||||
REG_SET_BIT(APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
|
||||
mmu_init(1);
|
||||
REG_CLR_BIT(APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
|
||||
/* (above steps probably unnecessary for most serial bootloader
|
||||
usage, all that's absolutely needed is that we unmask DROM0
|
||||
cache on the following two lines - normal ROM boot exits with
|
||||
DROM0 cache unmasked, but serial bootloader exits with it
|
||||
masked. However can't hurt to be thorough and reset
|
||||
everything.)
|
||||
|
||||
The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are
|
||||
necessary to work around a hardware bug.
|
||||
*/
|
||||
REG_CLR_BIT(PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
|
||||
REG_CLR_BIT(APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
|
||||
|
||||
bootloader_main();
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(IDF_PATH)/make/component.mk. By default,
|
||||
# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default,
|
||||
# this will take the sources in the src/ directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the esp-idf build system document if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T eagle.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/eagle.fpga32.rom.addr.v7.ld
|
||||
COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld
|
||||
COMPONENT_EXTRA_INCLUDES := $(IDF_PATH)/components/esp32/include
|
||||
|
||||
include $(IDF_PATH)/make/component.mk
|
||||
include $(IDF_PATH)/make/component_common.mk
|
@ -6,6 +6,9 @@ config WIFI_ENABLED
|
||||
help
|
||||
This compiles in the low-level WiFi stack.
|
||||
|
||||
Temporarily, this option requires that FreeRTOS runs in single core mode.
|
||||
depends on FREERTOS_UNICORE
|
||||
|
||||
config WIFI_AUTO_STARTUP
|
||||
bool "Start WiFi with system startup"
|
||||
default "y"
|
||||
|
@ -1,23 +1,39 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(IDF_PATH)/make/component.mk. By default,
|
||||
# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default,
|
||||
# this will take the sources in this directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the esp-idf build system document if you need to do this.
|
||||
#
|
||||
-include $(PROJECT_PATH)/build/include/config/auto.conf
|
||||
|
||||
LIBS := crypto core net80211 phy rtc pp wpa wps
|
||||
|
||||
ifeq ($(CONFIG_MEMMAP_BT),y)
|
||||
ifeq ($(CONFIG_MEMMAP_TRACEMEM),y)
|
||||
LINKER_SCRIPTS = -T esp32.bt.trace.ld
|
||||
else
|
||||
LINKER_SCRIPTS = -T esp32.bt.ld
|
||||
endif
|
||||
else
|
||||
ifeq ($(CONFIG_MEMMAP_TRACEMEM),y)
|
||||
LINKER_SCRIPTS = -T esp32.trace.ld
|
||||
else
|
||||
LINKER_SCRIPTS = -T esp32.ld
|
||||
endif
|
||||
endif
|
||||
|
||||
LINKER_SCRIPTS += -T esp32.common.ld -T esp32.rom.ld
|
||||
|
||||
COMPONENT_ADD_LDFLAGS := -lesp32 \
|
||||
$(abspath libhal.a) \
|
||||
-L$(abspath lib) \
|
||||
$(addprefix -l,$(LIBS)) \
|
||||
-L $(abspath ld) \
|
||||
-T eagle.fpga32.v7.ld \
|
||||
-T eagle.fpga32.rom.addr.v7.ld
|
||||
$(LINKER_SCRIPTS)
|
||||
|
||||
include $(IDF_PATH)/make/component.mk
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
||||
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
||||
|
||||
@ -30,8 +46,11 @@ $(ALL_LIB_FILES):
|
||||
@echo "Warning: Missing libraries in components/esp32/lib/ submodule. Going to try running 'git submodule update --init' in esp-idf root directory..."
|
||||
cd ${IDF_PATH} && git submodule update --init
|
||||
|
||||
# adding $(ALL_LIB_FILES) as a build dependency here is a hack to make
|
||||
# sure they get evaluated. Once TW6630 lands and we have library file
|
||||
# dependencies available at the project level, we can probably lose
|
||||
# this.
|
||||
build: $(ALL_LIB_FILES)
|
||||
# this is a hack to make sure the app is re-linked if the binary
|
||||
# libraries change or are updated. If they change, the main esp32
|
||||
# library will be rebuild by AR andthis will trigger a re-linking of
|
||||
# the entire app.
|
||||
#
|
||||
# It would be better for components to be able to expose any of these
|
||||
# non-standard dependencies via get_variable, but this will do for now.
|
||||
$(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
|
@ -64,6 +64,8 @@ void uartAttach();
|
||||
void ets_set_appcpu_boot_addr(uint32_t ent);
|
||||
int ets_getAppEntry();
|
||||
|
||||
static bool app_cpu_started = false;
|
||||
|
||||
void IRAM_ATTR call_user_start_cpu0() {
|
||||
//Kill wdt
|
||||
REG_CLR_BIT(0x3ff4808c, BIT(10)); //RTCCNTL+8C RTC_WDTCONFIG0 RTC_
|
||||
@ -114,53 +116,34 @@ void IRAM_ATTR call_user_start_cpu0() {
|
||||
heap_alloc_caps_init();
|
||||
|
||||
ets_printf("Pro cpu up.\n");
|
||||
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
ets_printf("Running app cpu, entry point is %p\n", call_user_start_cpu1);
|
||||
ets_delay_us(60000);
|
||||
ets_printf("Starting app cpu, entry point is %p\n", call_user_start_cpu1);
|
||||
|
||||
SET_PERI_REG_MASK(APPCPU_CTRL_REG_B, DPORT_APPCPU_CLKGATE_EN);
|
||||
CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_C, DPORT_APPCPU_RUNSTALL);
|
||||
SET_PERI_REG_MASK(APPCPU_CTRL_REG_A, DPORT_APPCPU_RESETTING);
|
||||
CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_A, DPORT_APPCPU_RESETTING);
|
||||
|
||||
|
||||
for (int i=0; i<20; i++) ets_delay_us(40000);
|
||||
ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1);
|
||||
|
||||
ets_delay_us(10000);
|
||||
|
||||
// while (ets_getAppEntry()==(int)call_user_start_cpu1) ;
|
||||
//Because of Reasons (tm), the pro cpu cannot use the SPI flash while the app cpu is booting.
|
||||
// while(((READ_PERI_REG(RTC_STORE7))&BIT(31)) == 0) ; // check APP boot complete flag
|
||||
ets_delay_us(50000);
|
||||
ets_delay_us(50000);
|
||||
ets_printf("\n\nBack to pro cpu.\n");
|
||||
while (!app_cpu_started) {
|
||||
ets_delay_us(100);
|
||||
}
|
||||
#else
|
||||
CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_B, DPORT_APPCPU_CLKGATE_EN);
|
||||
#endif
|
||||
ets_printf("Pro cpu start user code\n");
|
||||
user_start_cpu0();
|
||||
}
|
||||
|
||||
|
||||
extern int xPortGetCoreID();
|
||||
|
||||
extern int _init_start;
|
||||
|
||||
/*
|
||||
We arrive here because the pro CPU pulled us from reset. IRAM is in place, cache is still disabled, we can execute C code.
|
||||
*/
|
||||
void IRAM_ATTR call_user_start_cpu1() {
|
||||
//We need to do this ASAP because otherwise the structure to catch the SYSCALL instruction, which
|
||||
//we abuse to do ROM calls, won't work.
|
||||
|
||||
asm volatile (\
|
||||
"wsr %0, vecbase\n" \
|
||||
::"r"(&_init_start));
|
||||
|
||||
//Enable SPI flash
|
||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, FUNC_SD_DATA3_SPIWP); // swap PIN SDDATA3 from uart1 to spi, because cache need spi
|
||||
|
||||
ets_printf("App cpu up\n");
|
||||
|
||||
//Make page 0 access raise an exception
|
||||
//Also some other unused pages so we can catch weirdness
|
||||
//ToDo: this but nicer.
|
||||
@ -192,16 +175,15 @@ void IRAM_ATTR call_user_start_cpu1() {
|
||||
"isync\n" \
|
||||
:::"a4","a5");
|
||||
|
||||
ets_printf("App cpu up.\n");
|
||||
app_cpu_started = 1;
|
||||
user_start_cpu1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern volatile int port_xSchedulerRunning;
|
||||
extern int xPortStartScheduler();
|
||||
|
||||
void user_start_cpu1(void) {
|
||||
ets_printf("App cpu is running!\n");
|
||||
//Wait for the freertos initialization is finished on CPU0
|
||||
while (port_xSchedulerRunning == 0) ;
|
||||
ets_printf("Core0 started initializing FreeRTOS. Jumping to scheduler.\n");
|
||||
@ -221,20 +203,13 @@ static void do_global_ctors(void) {
|
||||
|
||||
|
||||
void user_start_cpu0(void) {
|
||||
esp_err_t ret;
|
||||
|
||||
ets_setup_syscalls();
|
||||
do_global_ctors();
|
||||
|
||||
#if 1 //workaround
|
||||
for (uint8_t i = 5; i < 8; i++) {
|
||||
ets_printf("erase sector %d\n", i);
|
||||
spi_flash_erase_sector(i);
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_WIFI_ENABLED
|
||||
ets_printf("nvs_flash_init\n");
|
||||
ret = nvs_flash_init(5, 3);
|
||||
if (ESP_OK != ret) {
|
||||
esp_err_t ret = nvs_flash_init(5, 3);
|
||||
if (ret != ESP_OK) {
|
||||
ets_printf("nvs_flash_init fail, ret=%d\n", ret);
|
||||
}
|
||||
|
||||
@ -242,8 +217,6 @@ void user_start_cpu0(void) {
|
||||
|
||||
esp_event_init(NULL);
|
||||
|
||||
// TODO: consider ethernet interface
|
||||
#if CONFIG_WIFI_ENABLED
|
||||
tcpip_adapter_init();
|
||||
#endif
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi.h"
|
||||
@ -28,26 +29,10 @@
|
||||
#define ESP32_WORKAROUND 1
|
||||
|
||||
#if CONFIG_WIFI_ENABLED
|
||||
|
||||
#ifdef ESP32_WORKAROUND
|
||||
|
||||
extern SemaphoreHandle_t stdio_mutex_tx;
|
||||
#define os_printf(fmt, ...) do {\
|
||||
if (!stdio_mutex_tx) {\
|
||||
stdio_mutex_tx = xSemaphoreCreateMutex();\
|
||||
}\
|
||||
\
|
||||
xSemaphoreTake(stdio_mutex_tx, portMAX_DELAY);\
|
||||
ets_printf(fmt, ##__VA_ARGS__);\
|
||||
xSemaphoreGive(stdio_mutex_tx);\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
static xQueueHandle g_event_handler = NULL;
|
||||
static system_event_cb_t g_event_handler_cb;
|
||||
|
||||
#define WIFI_DEBUG os_printf
|
||||
#define WIFI_DEBUG(...)
|
||||
#define WIFI_API_CALL_CHECK(info, api_call, ret) \
|
||||
do{\
|
||||
esp_err_t __err = (api_call);\
|
||||
@ -70,6 +55,7 @@ static esp_err_t system_event_sta_start_handle_default(system_event_t *event);
|
||||
static esp_err_t system_event_sta_stop_handle_default(system_event_t *event);
|
||||
static esp_err_t system_event_sta_connected_handle_default(system_event_t *event);
|
||||
static esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event);
|
||||
static esp_err_t system_event_sta_gotip_default(system_event_t *event);
|
||||
|
||||
static system_event_handle_t g_system_event_handle_table[] = {
|
||||
{SYSTEM_EVENT_WIFI_READY, NULL},
|
||||
@ -79,6 +65,7 @@ static system_event_handle_t g_system_event_handle_table[] = {
|
||||
{SYSTEM_EVENT_STA_CONNECTED, system_event_sta_connected_handle_default},
|
||||
{SYSTEM_EVENT_STA_DISCONNECTED, system_event_sta_disconnected_handle_default},
|
||||
{SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
|
||||
{SYSTEM_EVENT_STA_GOTIP, system_event_sta_gotip_default},
|
||||
{SYSTEM_EVENT_AP_START, system_event_ap_start_handle_default},
|
||||
{SYSTEM_EVENT_AP_STOP, system_event_ap_stop_handle_default},
|
||||
{SYSTEM_EVENT_AP_STACONNECTED, NULL},
|
||||
@ -87,9 +74,22 @@ static system_event_handle_t g_system_event_handle_table[] = {
|
||||
{SYSTEM_EVENT_MAX, NULL},
|
||||
};
|
||||
|
||||
static esp_err_t system_event_sta_gotip_default(system_event_t *event)
|
||||
{
|
||||
extern esp_err_t esp_wifi_set_sta_ip(void);
|
||||
WIFI_API_CALL_CHECK("esp_wifi_set_sta_ip", esp_wifi_set_sta_ip(), ESP_OK);
|
||||
|
||||
printf("ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR "\n",
|
||||
IP2STR(&event->event_info.got_ip.ip_info.ip),
|
||||
IP2STR(&event->event_info.got_ip.ip_info.netmask),
|
||||
IP2STR(&event->event_info.got_ip.ip_info.gw));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t system_event_ap_start_handle_default(system_event_t *event)
|
||||
{
|
||||
struct ip_info ap_ip;
|
||||
tcpip_adapter_ip_info_t ap_ip;
|
||||
uint8_t ap_mac[6];
|
||||
|
||||
WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_AP, (wifi_rxcb_t)tcpip_adapter_ap_input), ESP_OK);
|
||||
@ -112,7 +112,7 @@ esp_err_t system_event_ap_stop_handle_default(system_event_t *event)
|
||||
|
||||
esp_err_t system_event_sta_start_handle_default(system_event_t *event)
|
||||
{
|
||||
struct ip_info sta_ip;
|
||||
tcpip_adapter_ip_info_t sta_ip;
|
||||
uint8_t sta_mac[6];
|
||||
|
||||
WIFI_API_CALL_CHECK("esp_wifi_mac_get", esp_wifi_get_mac(WIFI_IF_STA, sta_mac), ESP_OK);
|
||||
@ -131,10 +131,33 @@ esp_err_t system_event_sta_stop_handle_default(system_event_t *event)
|
||||
|
||||
esp_err_t system_event_sta_connected_handle_default(system_event_t *event)
|
||||
{
|
||||
tcpip_adapter_dhcp_status_t status;
|
||||
|
||||
WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_STA, (wifi_rxcb_t)tcpip_adapter_sta_input), ESP_OK);
|
||||
|
||||
tcpip_adapter_up(TCPIP_ADAPTER_IF_STA);
|
||||
tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
|
||||
|
||||
tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &status);
|
||||
|
||||
if (status == TCPIP_ADAPTER_DHCP_INIT) {
|
||||
tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
|
||||
} else if (status == TCPIP_ADAPTER_DHCP_STOPPED) {
|
||||
tcpip_adapter_ip_info_t sta_ip;
|
||||
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &sta_ip);
|
||||
|
||||
if (!(ip4_addr_isany_val(sta_ip.ip) || ip4_addr_isany_val(sta_ip.netmask) || ip4_addr_isany_val(sta_ip.gw))) {
|
||||
system_event_t evt;
|
||||
|
||||
//notify event
|
||||
evt.event_id = SYSTEM_EVENT_STA_GOTIP;
|
||||
memcpy(&evt.event_info.got_ip.ip_info, &sta_ip, sizeof(tcpip_adapter_ip_info_t));
|
||||
|
||||
esp_event_send(&evt);
|
||||
} else {
|
||||
WIFI_DEBUG("invalid static ip\n");
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -157,78 +180,109 @@ static esp_err_t esp_wifi_post_event_to_user(system_event_t *event)
|
||||
|
||||
static esp_err_t esp_system_event_debug(system_event_t *event)
|
||||
{
|
||||
system_event_sta_scan_done_t *scan_done;
|
||||
system_event_sta_connected_t *connected;
|
||||
system_event_sta_disconnected_t *disconnected;
|
||||
system_event_sta_authmode_change_t *auth_change;
|
||||
system_event_ap_staconnected_t *staconnected;
|
||||
system_event_ap_stadisconnected_t *stadisconnected;
|
||||
system_event_ap_probe_req_rx_t *ap_probereqrecved;
|
||||
|
||||
if (event == NULL) {
|
||||
os_printf("Error: event is null!\n");
|
||||
printf("Error: event is null!\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
os_printf("received event: ");
|
||||
WIFI_DEBUG("received event: ");
|
||||
switch (event->event_id) {
|
||||
case SYSTEM_EVENT_WIFI_READY:
|
||||
os_printf("SYSTEM_EVENT_WIFI_READY\n");
|
||||
{
|
||||
WIFI_DEBUG("SYSTEM_EVENT_WIFI_READY\n");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_SCAN_DONE:
|
||||
{
|
||||
system_event_sta_scan_done_t *scan_done;
|
||||
scan_done = &event->event_info.scan_done;
|
||||
os_printf("SYSTEM_EVENT_SCAN_DONE\nstatus:%d, number:%d\n", \
|
||||
scan_done->status, scan_done->number);
|
||||
WIFI_DEBUG("SYSTEM_EVENT_SCAN_DONE\nstatus:%d, number:%d\n", scan_done->status, scan_done->number);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
os_printf("SYSTEM_EVENT_STA_START\n");
|
||||
{
|
||||
WIFI_DEBUG("SYSTEM_EVENT_STA_START\n");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_STOP:
|
||||
os_printf("SYSTEM_EVENT_STA_STOP\n");
|
||||
{
|
||||
WIFI_DEBUG("SYSTEM_EVENT_STA_STOP\n");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_CONNECTED:
|
||||
{
|
||||
system_event_sta_connected_t *connected;
|
||||
connected = &event->event_info.connected;
|
||||
os_printf("SYSTEM_EVENT_STA_CONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d\n", \
|
||||
WIFI_DEBUG("SYSTEM_EVENT_STA_CONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d\n", \
|
||||
connected->ssid, connected->ssid_len, connected->bssid[0], connected->bssid[0], connected->bssid[1], \
|
||||
connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel);
|
||||
connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel, connected->authmode);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
{
|
||||
system_event_sta_disconnected_t *disconnected;
|
||||
disconnected = &event->event_info.disconnected;
|
||||
os_printf("SYSTEM_EVENT_STA_DISCONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d\n", \
|
||||
WIFI_DEBUG("SYSTEM_EVENT_STA_DISCONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d\n", \
|
||||
disconnected->ssid, disconnected->ssid_len, disconnected->bssid[0], disconnected->bssid[0], disconnected->bssid[1], \
|
||||
disconnected->bssid[3], disconnected->bssid[4], disconnected->bssid[5], disconnected->reason);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
|
||||
{
|
||||
system_event_sta_authmode_change_t *auth_change;
|
||||
auth_change = &event->event_info.auth_change;
|
||||
os_printf("SYSTEM_EVENT_STA_AUTHMODE_CHNAGE\nold_mode:%d, new_mode:%d\n", auth_change->old_mode, auth_change->new_mode);
|
||||
WIFI_DEBUG("SYSTEM_EVENT_STA_AUTHMODE_CHNAGE\nold_mode:%d, new_mode:%d\n", auth_change->old_mode, auth_change->new_mode);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_GOTIP:
|
||||
{
|
||||
system_event_sta_got_ip_t *got_ip;
|
||||
got_ip = &event->event_info.got_ip;
|
||||
WIFI_DEBUG("SYSTEM_EVENT_STA_GOTIP\n");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_AP_START:
|
||||
os_printf("SYSTEM_EVENT_AP_START\n");
|
||||
{
|
||||
WIFI_DEBUG("SYSTEM_EVENT_AP_START\n");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_AP_STOP:
|
||||
os_printf("SYSTEM_EVENT_AP_STOP\n");
|
||||
{
|
||||
WIFI_DEBUG("SYSTEM_EVENT_AP_STOP\n");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_AP_STACONNECTED:
|
||||
{
|
||||
system_event_ap_staconnected_t *staconnected;
|
||||
staconnected = &event->event_info.sta_connected;
|
||||
os_printf("SYSTEM_EVENT_AP_STACONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \
|
||||
WIFI_DEBUG("SYSTEM_EVENT_AP_STACONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \
|
||||
staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \
|
||||
staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_AP_STADISCONNECTED:
|
||||
{
|
||||
system_event_ap_stadisconnected_t *stadisconnected;
|
||||
stadisconnected = &event->event_info.sta_disconnected;
|
||||
os_printf("SYSTEM_EVENT_AP_STADISCONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \
|
||||
WIFI_DEBUG("SYSTEM_EVENT_AP_STADISCONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \
|
||||
stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \
|
||||
stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_AP_PROBEREQRECVED:
|
||||
{
|
||||
system_event_ap_probe_req_rx_t *ap_probereqrecved;
|
||||
ap_probereqrecved = &event->event_info.ap_probereqrecved;
|
||||
os_printf("SYSTEM_EVENT_AP_PROBEREQRECVED\nrssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x\n", \
|
||||
WIFI_DEBUG("SYSTEM_EVENT_AP_PROBEREQRECVED\nrssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x\n", \
|
||||
ap_probereqrecved->rssi, ap_probereqrecved->mac[0], ap_probereqrecved->mac[0], ap_probereqrecved->mac[1], \
|
||||
ap_probereqrecved->mac[3], ap_probereqrecved->mac[4], ap_probereqrecved->mac[5]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
os_printf("Error: no such kind of event!\n");
|
||||
{
|
||||
printf("Error: no such kind of event!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
@ -237,19 +291,19 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
|
||||
static esp_err_t esp_system_event_handler(system_event_t *event)
|
||||
{
|
||||
if (event == NULL) {
|
||||
os_printf("Error: event is null!\n");
|
||||
printf("Error: event is null!\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_system_event_debug(event);
|
||||
if ((event->event_id < SYSTEM_EVENT_MAX) && (event->event_id == g_system_event_handle_table[event->event_id].event_id)){
|
||||
if (g_system_event_handle_table[event->event_id].event_handle){
|
||||
os_printf("enter default callback\n");
|
||||
WIFI_DEBUG("enter default callback\n");
|
||||
g_system_event_handle_table[event->event_id].event_handle(event);
|
||||
os_printf("exit default callback\n");
|
||||
WIFI_DEBUG("exit default callback\n");
|
||||
}
|
||||
} else {
|
||||
os_printf("mismatch or invalid event, id=%d\n", event->event_id);
|
||||
printf("mismatch or invalid event, id=%d\n", event->event_id);
|
||||
}
|
||||
|
||||
return esp_wifi_post_event_to_user(event);
|
||||
@ -264,7 +318,7 @@ static void esp_system_event_task(void *pvParameters)
|
||||
if (xQueueReceive(g_event_handler, &evt, portMAX_DELAY) == pdPASS) {
|
||||
ret = esp_system_event_handler(&evt);
|
||||
if (ret == ESP_FAIL)
|
||||
os_printf("esp wifi post event to user fail!\n");
|
||||
printf("esp wifi post event to user fail!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -282,8 +336,8 @@ esp_err_t esp_event_send(system_event_t *event)
|
||||
|
||||
ret = xQueueSendToBack((xQueueHandle)g_event_handler, event, 0);
|
||||
if (pdPASS != ret){
|
||||
if (event) ets_printf("e=%d f\n", event->event_id);
|
||||
else ets_printf("e null\n");
|
||||
if (event) printf("e=%d f\n", event->event_id);
|
||||
else printf("e null\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
@ -77,9 +77,9 @@ This array is *NOT* const because it gets modified depending on what pools are/a
|
||||
*/
|
||||
static HeapRegionTagged_t regions[]={
|
||||
{ (uint8_t *)0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available
|
||||
// { (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- can be used for BT <- THIS POOL DOESN'T WORK for some reason! Hw seems fine. ToDo: Figure out.
|
||||
{ (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code
|
||||
{ (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- can be used for BT
|
||||
{ (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14
|
||||
{ (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- can be used for BT
|
||||
{ (uint8_t *)0x3FFC0000, 0x2000, 0, 0}, //pool 10-13, mmu page 0
|
||||
{ (uint8_t *)0x3FFC2000, 0x2000, 0, 0}, //pool 10-13, mmu page 1
|
||||
{ (uint8_t *)0x3FFC4000, 0x2000, 0, 0}, //pool 10-13, mmu page 2
|
||||
@ -158,7 +158,6 @@ static void disable_mem_region(void *from, void *to) {
|
||||
ToDo: These are very dependent on the linker script, and the logic involving this works only
|
||||
because we're not using the SPI flash yet! If we enable that, this will break. ToDo: Rewrite by then.
|
||||
*/
|
||||
extern int _init_start, _text_end;
|
||||
extern int _bss_start, _heap_start;
|
||||
|
||||
/*
|
||||
@ -170,12 +169,23 @@ Same with loading of apps. Same with using SPI RAM.
|
||||
void heap_alloc_caps_init() {
|
||||
int i;
|
||||
//Disable the bits of memory where this code is loaded.
|
||||
disable_mem_region(&_init_start, &_text_end);
|
||||
disable_mem_region(&_bss_start, &_heap_start);
|
||||
disable_mem_region((void*)0x3ffae000, (void*)0x3ffb0000); //knock out ROM data region
|
||||
disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region
|
||||
disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region
|
||||
disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region
|
||||
disable_mem_region((void*)0x40080000, (void*)0x400a0000); //pool 2-5
|
||||
|
||||
// TODO: this region should be checked, since we don't need to knock out all region finally
|
||||
disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region
|
||||
|
||||
#if CONFIG_MEMMAP_BT
|
||||
disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT data region
|
||||
#endif
|
||||
|
||||
#if CONFIG_MEMMAP_TRACEMEM
|
||||
disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
enable_spi_sram();
|
||||
#else
|
||||
|
@ -20,16 +20,10 @@
|
||||
//and all variables in shared RAM. This can be redirected to IRAM if
|
||||
//needed using these macros.
|
||||
|
||||
//Forces data and flash into IRAM instead of flash / shared RAM
|
||||
// Forces code into IRAM instead of flash
|
||||
#define IRAM_ATTR __attribute__((section(".iram1")))
|
||||
|
||||
// Forces data into DRAM instead of flash
|
||||
#define DRAM_ATTR __attribute__((section(".dram1")))
|
||||
|
||||
//Forces data and flash into the IRAM section of a specific core.
|
||||
//Normally, you shouldn't have to use this: the linker will take care of
|
||||
//only linking in the functions for that specific core.
|
||||
#define IRAM_C0_ATTR __attribute__((section(".iram1pro")))
|
||||
#define DRAM_C0_ATTR __attribute__((section(".iram1pro")))
|
||||
#define IRAM_C1_ATTR __attribute__((section(".dram1app")))
|
||||
#define DRAM_C1_ATTR __attribute__((section(".dram1app")))
|
||||
|
||||
#endif /* __ESP_ATTR_H__ */
|
||||
|
@ -19,6 +19,9 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi.h"
|
||||
|
||||
#include "tcpip_adapter.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -32,6 +35,7 @@ typedef enum {
|
||||
SYSTEM_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */
|
||||
SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected to AP */
|
||||
SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
|
||||
SYSTEM_EVENT_STA_GOTIP, /**< ESP32 station received IP address */
|
||||
SYSTEM_EVENT_AP_START, /**< ESP32 softap start */
|
||||
SYSTEM_EVENT_AP_STOP, /**< ESP32 softap start */
|
||||
SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
|
||||
@ -43,6 +47,7 @@ typedef enum {
|
||||
typedef struct {
|
||||
uint32_t status; /**< status of scanning APs*/
|
||||
uint8_t number;
|
||||
uint8_t scan_id;
|
||||
} system_event_sta_scan_done_t;
|
||||
|
||||
typedef struct {
|
||||
@ -50,6 +55,7 @@ typedef struct {
|
||||
uint8_t ssid_len; /**< SSID length of connected AP */
|
||||
uint8_t bssid[6]; /**< BSSID of connected AP*/
|
||||
uint8_t channel; /**< channel of connected AP*/
|
||||
wifi_auth_mode_t authmode;
|
||||
} system_event_sta_connected_t;
|
||||
|
||||
typedef struct {
|
||||
@ -60,10 +66,14 @@ typedef struct {
|
||||
} system_event_sta_disconnected_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t old_mode; /**< the old auth mode of AP */
|
||||
uint8_t new_mode; /**< the new auth mode of AP */
|
||||
wifi_auth_mode_t old_mode; /**< the old auth mode of AP */
|
||||
wifi_auth_mode_t new_mode; /**< the new auth mode of AP */
|
||||
} system_event_sta_authmode_change_t;
|
||||
|
||||
typedef struct {
|
||||
tcpip_adapter_ip_info_t ip_info;
|
||||
} system_event_sta_got_ip_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */
|
||||
uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */
|
||||
@ -84,6 +94,7 @@ typedef union {
|
||||
system_event_sta_disconnected_t disconnected; /**< ESP32 station disconnected to AP */
|
||||
system_event_sta_scan_done_t scan_done; /**< ESP32 station scan (APs) done */
|
||||
system_event_sta_authmode_change_t auth_change; /**< the auth mode of AP ESP32 station connected to changed */
|
||||
system_event_sta_got_ip_t got_ip;
|
||||
system_event_ap_staconnected_t sta_connected; /**< a station connected to ESP32 soft-AP */
|
||||
system_event_ap_stadisconnected_t sta_disconnected; /**< a station disconnected to ESP32 soft-AP */
|
||||
system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP32 softAP receive probe request packet */
|
||||
|
209
components/esp32/include/esp_intr.h
Normal file
209
components/esp32/include/esp_intr.h
Normal file
@ -0,0 +1,209 @@
|
||||
// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __ESP_INTR_H__
|
||||
#define __ESP_INTR_H__
|
||||
|
||||
#include "rom/ets_sys.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_CCOMPARE_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_CCOMPARE_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_EPWM_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_EPWM_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_MPWM_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_MPWM_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_SPI1_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_SPI1_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_SPI2_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_SPI2_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_SPI3_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_SPI3_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_I2S0_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_I2S0_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_PCNT_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_PCNT_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_LEDC_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_LEDC_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_WMAC_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_WMAC_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_FRC_TIMER1_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_FRC_TIMER1_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_FRC_TIMER2_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_FRC_TIMER2_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_GPIO_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_GPIO_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_UART_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_UART_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_WDT_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_WDT_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_RTC_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_RTC_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_SLC_INTR_ATTACH(func, arg) \
|
||||
xt_set_interrupt_handler(ETS_SLC_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_RMT_CTRL_INTRL(func,arg)\
|
||||
xt_set_interrupt_handler(ETS_RMT_CTRL_INUM, (func), (void *)(arg))
|
||||
|
||||
#define ESP_INTR_ENABLE(inum) \
|
||||
xt_ints_on((1<<inum))
|
||||
|
||||
#define ESP_INTR_DISABLE(inum) \
|
||||
xt_ints_off((1<<inum))
|
||||
|
||||
#define ESP_CCOMPARE_INTR_ENBALE() \
|
||||
ESP_INTR_ENABLE(ETS_CCOMPARE_INUM)
|
||||
|
||||
#define ESP_CCOMPARE_INTR_DISBALE() \
|
||||
ESP_INTR_DISABLE(ETS_CCOMPARE_INUM)
|
||||
|
||||
#define ESP_SPI1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI1_INUM)
|
||||
|
||||
#define ESP_SPI1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI1_INUM)
|
||||
|
||||
#define ESP_SPI2_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI2_INUM)
|
||||
|
||||
#define ESP_PWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_PWM_INUM)
|
||||
|
||||
#define ESP_PWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_PWM_INUM)
|
||||
|
||||
#define ESP_SPI2_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI2_INUM)
|
||||
|
||||
#define ESP_SPI3_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI3_INUM)
|
||||
|
||||
#define ESP_SPI3_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI3_INUM)
|
||||
|
||||
#define ESP_I2S0_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_I2S0_INUM)
|
||||
|
||||
#define ESP_I2S0_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_I2S0_INUM)
|
||||
|
||||
#define ESP_I2S1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_I2S1_INUM)
|
||||
|
||||
#define ESP_I2S1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_I2S1_INUM)
|
||||
|
||||
#define ESP_MPWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_MPWM_INUM)
|
||||
|
||||
#define ESP_EPWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_EPWM_INUM)
|
||||
|
||||
#define ESP_MPWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_MPWM_INUM)
|
||||
|
||||
#define ESP_EPWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_EPWM_INUM)
|
||||
|
||||
#define ESP_BB_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_BB_INUM)
|
||||
|
||||
#define ESP_BB_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_BB_INUM)
|
||||
|
||||
#define ESP_UART_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_UART_INUM)
|
||||
|
||||
#define ESP_UART_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_UART_INUM)
|
||||
|
||||
#define ESP_LEDC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_LEDC_INUM)
|
||||
|
||||
#define ESP_LEDC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_LEDC_INUM)
|
||||
|
||||
#define ESP_GPIO_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_GPIO_INUM)
|
||||
|
||||
#define ESP_GPIO_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_GPIO_INUM)
|
||||
|
||||
#define ESP_WDT_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_WDT_INUM)
|
||||
|
||||
#define ESP_WDT_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_WDT_INUM)
|
||||
|
||||
#define ESP_FRC1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_FRC_TIMER1_INUM)
|
||||
|
||||
#define ESP_FRC1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_FRC_TIMER1_INUM)
|
||||
|
||||
#define ESP_FRC2_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_FRC_TIMER2_INUM)
|
||||
|
||||
#define ESP_FRC2_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_FRC_TIMER2_INUM)
|
||||
|
||||
#define ESP_RTC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_RTC_INUM)
|
||||
|
||||
#define ESP_RTC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_RTC_INUM)
|
||||
|
||||
#define ESP_SLC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SLC_INUM)
|
||||
|
||||
#define ESP_SLC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SLC_INUM)
|
||||
|
||||
#define ESP_PCNT_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_PCNT_INUM)
|
||||
|
||||
#define ESP_PCNT_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_PCNT_INUM)
|
||||
|
||||
#define ESP_RMT_CTRL_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_RMT_CTRL_INUM)
|
||||
|
||||
#define ESP_RMT_CTRL_DIABLE() \
|
||||
ESP_INTR_DISABLE(ETS_RMT_CTRL_INUM)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ESP_INTR_H__ */
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -84,15 +86,6 @@ void system_deep_sleep(uint64_t time_in_us);
|
||||
*/
|
||||
uint32_t system_get_time(void);
|
||||
|
||||
/**
|
||||
* @brief Print the system memory distribution, including data/rodata/bss/heap.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
void system_print_meminfo(void);
|
||||
|
||||
/**
|
||||
* @brief Get the size of available heap.
|
||||
*
|
||||
@ -102,22 +95,6 @@ void system_print_meminfo(void);
|
||||
*/
|
||||
uint32_t system_get_free_heap_size(void);
|
||||
|
||||
/**
|
||||
* @brief Get the chip ID.
|
||||
*
|
||||
* Example:
|
||||
* <pre>
|
||||
* uint8 chip_id[6];
|
||||
* system_get_chip_id(chip_id);
|
||||
* </pre>
|
||||
*
|
||||
* @param uint8 *chip_id : the chip ID
|
||||
*
|
||||
* @return true : succeed
|
||||
* @return false : fail
|
||||
*/
|
||||
bool system_get_chip_id(uint8_t *chip_id);
|
||||
|
||||
/**
|
||||
* @brief Get RTC time, unit: RTC clock cycle.
|
||||
*
|
||||
@ -171,98 +148,6 @@ bool system_rtc_mem_read(uint16_t src, void *dst, uint16_t n);
|
||||
*/
|
||||
bool system_rtc_mem_write(uint16_t dst, const void *src, uint16_t n);
|
||||
|
||||
typedef enum {
|
||||
ADC1_PAD_GPIO36 = 0,
|
||||
ADC1_PAD_GPIO37,
|
||||
ADC1_PAD_GPIO38,
|
||||
ADC1_PAD_GPIO39,
|
||||
ADC1_PAD_GPIO32,
|
||||
ADC1_PAD_GPIO33,
|
||||
ADC1_PAD_GPIO34,
|
||||
ADC1_PAD_GPIO35
|
||||
} adc1_read_pad_t;
|
||||
|
||||
typedef enum {
|
||||
ADC1_ATTEN_0DB = 0,
|
||||
ADC1_ATTEN_3DB,
|
||||
ADC1_ATTEN_6DB,
|
||||
ADC1_ATTEN_12DB
|
||||
} adc1_read_atten_t;
|
||||
|
||||
/**
|
||||
* @brief Read ADC1.
|
||||
*
|
||||
* @param adc1_read_pad pad : the corresponding GPIO
|
||||
* @param adc1_read_atten atten : value of attenuation
|
||||
*
|
||||
* @return range of the return value is [0, 4096].
|
||||
* - If atten == 0, the range of voltage can be measured is [0, 1] V.
|
||||
* - If atten == 1, the range of voltage can be measured is [0, 1.4] V.
|
||||
* - If atten == 2, the range of voltage can be measured is [0, 2] V.
|
||||
* - If atten == 3, the range of voltage can be measured is [0, 4] V.
|
||||
*/
|
||||
uint16_t system_adc1_read(adc1_read_pad_t pad, adc1_read_atten_t atten);
|
||||
|
||||
/**
|
||||
* @brief Measure the power voltage of VDD3P3 pin 3 and 4, unit : 1/1024 V.
|
||||
*
|
||||
* @attention system_get_vdd33 depends on RF, please do not use it if RF is disabled.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return Power voltage of VDD33, unit : 1/1024 V
|
||||
*/
|
||||
uint16_t system_get_vdd33(void);
|
||||
|
||||
/**
|
||||
* @brief Write data into flash with protection.
|
||||
*
|
||||
* Flash read/write has to be 4-bytes aligned.
|
||||
*
|
||||
* Protection of flash read/write :
|
||||
* use 3 sectors (4KBytes per sector) to save 4KB data with protect,
|
||||
* sector 0 and sector 1 are data sectors, back up each other,
|
||||
* save data alternately, sector 2 is flag sector, point out which sector
|
||||
* is keeping the latest data, sector 0 or sector 1.
|
||||
*
|
||||
* @param uint16 start_sec : start sector (sector 0) of the 3 sectors which are
|
||||
* used for flash read/write protection.
|
||||
* - For example, in IOT_Demo we can use the 3 sectors (3 * 4KB) starting from flash
|
||||
* 0x3D000 for flash read/write protection, so the parameter start_sec should be 0x3D
|
||||
* @param void *param : pointer of the data to be written
|
||||
* @param uint16 len : data length, should be less than a sector, which is 4 * 1024
|
||||
*
|
||||
* @return true : succeed
|
||||
* @return false : fail
|
||||
*/
|
||||
bool system_param_save_with_protect(uint16_t start_sec, void *param, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Read the data saved into flash with the read/write protection.
|
||||
*
|
||||
* Flash read/write has to be 4-bytes aligned.
|
||||
*
|
||||
* Read/write protection of flash:
|
||||
* use 3 sectors (4KB per sector) to save 4KB data with protect, sector
|
||||
* 0 and sector 1 are data sectors, back up each other, save data alternately,
|
||||
* sector 2 is flag sector, point out which sector is keeping the latest data,
|
||||
* sector 0 or sector 1.
|
||||
*
|
||||
* @param uint16 start_sec : start sector (sector 0) of the 3 sectors used for
|
||||
* flash read/write protection. It cannot be sector 1 or sector 2.
|
||||
* - For example, in IOT_Demo, the 3 sectors (3 * 4KB) starting from flash 0x3D000
|
||||
* can be used for flash read/write protection.
|
||||
* The parameter start_sec is 0x3D, and it cannot be 0x3E or 0x3F.
|
||||
* @param uint16 offset : offset of data saved in sector
|
||||
* @param void *param : data pointer
|
||||
* @param uint16 len : data length, offset + len =< 4 * 1024
|
||||
*
|
||||
* @return true : succeed
|
||||
* @return false : fail
|
||||
*/
|
||||
bool system_param_load(uint16_t start_sec, uint16_t offset, void *param, uint16_t len);
|
||||
|
||||
|
||||
/** \defgroup System_boot_APIs Boot APIs
|
||||
* @brief boot APIs
|
||||
*/
|
||||
@ -288,63 +173,15 @@ bool system_param_load(uint16_t start_sec, uint16_t offset, void *param, uint16_
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
DEFAULT_MAC = 0, /**< Default hardware MAC provided by Espressif Systems */
|
||||
USER_MAC, /**< User-define hardware MAC */
|
||||
} mac_group_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_MAC = 0, /**< Hardware MAC address of ESP32 WiFi */
|
||||
BT_MAC, /**< Hardware MAC address of ESP32 bluetooth */
|
||||
} mac_type_t;
|
||||
|
||||
/**
|
||||
* @brief Set user-define hardware MAC address.
|
||||
*
|
||||
* @attention Hardware MAC address can only be set ONCE for each ESP32 chip.
|
||||
*
|
||||
* @param mac_type type : type of hardware MAC address.
|
||||
* @param uint8 *mac : user-define hardware MAC address, length: 6 bytes.
|
||||
*
|
||||
* @return 0 : succeed to set.
|
||||
* @return 1 : the hardware MAC has been set once, users can not set it any more.
|
||||
* @return 2 : fail to set.
|
||||
* @return 3 : invalid parameter.
|
||||
*/
|
||||
int system_efuse_program_user_mac(mac_type_t type, uint8_t *mac);
|
||||
|
||||
/**
|
||||
* @brief Read hardware MAC address.
|
||||
*
|
||||
* @param mac_group group : default MAC or user-defined MAC.
|
||||
* @param mac_type type : type of hardware MAC address.
|
||||
* @param uint8 *mac : the hardware MAC address, length: 6 bytes.
|
||||
* @param uint8 mac[6] : the hardware MAC address, length: 6 bytes.
|
||||
*
|
||||
* @return true : succeed
|
||||
* @return false : fail
|
||||
* @return esp_err_t
|
||||
*/
|
||||
bool system_efuse_read_mac(mac_group_t group, mac_type_t type, uint8_t *mac);
|
||||
esp_err_t system_efuse_read_mac(uint8_t mac[6]);
|
||||
|
||||
/**
|
||||
* @brief Set hardware MAC group, default MAC or user-defined MAC.
|
||||
*
|
||||
* @attention This API needs system_restart to take effect.
|
||||
*
|
||||
* @param mac_group group : default MAC or user-defined MAC.
|
||||
*
|
||||
* @return true : succeed
|
||||
* @return false : fail
|
||||
*/
|
||||
bool system_efuse_set_mac_group(mac_group_t group);
|
||||
|
||||
/**
|
||||
* @brief Get hardware MAC group, default MAC or user-defined MAC.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return mac_group, the hardware MAC group.
|
||||
*/
|
||||
mac_group_t system_efuse_get_mac_group(void);
|
||||
|
||||
void system_init(void);
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "rom/queue.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -121,6 +122,10 @@ esp_err_t esp_wifi_connect(void);
|
||||
|
||||
esp_err_t esp_wifi_disconnect(void);
|
||||
|
||||
esp_err_t esp_wifi_clear_fast_connect(void);
|
||||
|
||||
esp_err_t esp_wifi_kick_station(uint16_t aid);
|
||||
|
||||
typedef struct {
|
||||
char *ssid; /**< SSID of AP */
|
||||
uint8_t *bssid; /**< MAC address of AP */
|
||||
@ -128,7 +133,7 @@ typedef struct {
|
||||
bool show_hidden; /**< enable to scan AP whose SSID is hidden */
|
||||
} wifi_scan_config_t;
|
||||
|
||||
esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf);
|
||||
esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf, bool block);
|
||||
|
||||
esp_err_t esp_wifi_scan_stop(void);
|
||||
|
||||
@ -139,7 +144,7 @@ typedef struct {
|
||||
uint8_t ssid[32]; /**< SSID of AP */
|
||||
uint8_t primary; /**< channel of AP */
|
||||
wifi_second_chan_t second; /**< second channel of AP */
|
||||
char rssi; /**< single strength of AP */
|
||||
signed char rssi; /**< signal strength of AP */
|
||||
wifi_auth_mode_t authmode; /**< authmode of AP */
|
||||
}wifi_ap_list_t;
|
||||
|
||||
@ -187,7 +192,7 @@ esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);
|
||||
|
||||
typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len);
|
||||
|
||||
wifi_promiscuous_cb_t wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
|
||||
esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
|
||||
|
||||
esp_err_t esp_wifi_set_promiscuous(uint8_t enable);
|
||||
|
||||
@ -220,10 +225,30 @@ esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf);
|
||||
|
||||
esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
|
||||
|
||||
struct station_info {
|
||||
STAILQ_ENTRY(station_info) next;
|
||||
uint8_t bssid[6];
|
||||
};
|
||||
|
||||
esp_err_t esp_wifi_get_station_list(struct station_info **station);
|
||||
|
||||
esp_err_t esp_wifi_free_station_list(void);
|
||||
|
||||
typedef enum {
|
||||
WIFI_STORAGE_RAM,
|
||||
WIFI_STORAGE_FLASH,
|
||||
} wifi_storage_t;
|
||||
|
||||
esp_err_t esp_wifi_set_storage(wifi_storage_t storage);
|
||||
|
||||
typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void* eb);
|
||||
|
||||
esp_err_t esp_wifi_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn);
|
||||
|
||||
esp_err_t esp_wifi_set_auto_connect(bool en);
|
||||
|
||||
esp_err_t esp_wifi_get_auto_connect(bool *en);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -31,7 +31,7 @@ void ets_aes_enable(void);
|
||||
|
||||
void ets_aes_disable(void);
|
||||
|
||||
void ets_set_endian(bool key_word_swap, bool key_byte_swap,
|
||||
void ets_aes_set_endian(bool key_word_swap, bool key_byte_swap,
|
||||
bool in_word_swap, bool in_byte_swap,
|
||||
bool out_word_swap, bool out_byte_swap);
|
||||
|
||||
|
@ -232,10 +232,10 @@ void intr_matrix_set(int cpu_no, uint32_t model_num, uint32_t intr_num);
|
||||
|
||||
|
||||
#define ETS_INTR_ENABLE(inum) \
|
||||
ets_isr_unmask((1<<inum))
|
||||
xt_ints_on((1<<inum))
|
||||
|
||||
#define ETS_INTR_DISABLE(inum) \
|
||||
ets_isr_mask((1<<inum))
|
||||
xt_ints_off((1<<inum))
|
||||
|
||||
#define ETS_CCOMPARE_INTR_ENBALE() \
|
||||
ETS_INTR_ENABLE(ETS_CCOMPARE_INUM)
|
||||
|
@ -15,14 +15,16 @@
|
||||
#ifndef _ROM_MD5_HASH_H_
|
||||
#define _ROM_MD5_HASH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct MD5Context {
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
uint8 in[64];
|
||||
uint32_t buf[4];
|
||||
uint32_t bits[2];
|
||||
uint8_t in[64];
|
||||
};
|
||||
|
||||
void MD5Init(struct MD5Context *context);
|
||||
|
36
components/esp32/include/soc/cpu.h
Normal file
36
components/esp32/include/soc/cpu.h
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SOC_CPU_H
|
||||
#define _SOC_CPU_H
|
||||
|
||||
#include "xtensa/corebits.h"
|
||||
|
||||
/* C macros for xtensa special register read/write/exchange */
|
||||
|
||||
#define RSR(reg, curval) asm volatile ("rsr %0, " #reg : "=r" (curval));
|
||||
#define WSR(reg, newval) asm volatile ("wsr %0, " #reg : : "r" (newval));
|
||||
#define XSR(reg, swapval) asm volatile ("xsr %0, " #reg : "+r" (swapval));
|
||||
|
||||
/* Return true if the CPU is in an interrupt context
|
||||
(PS.UM == 0)
|
||||
*/
|
||||
static inline bool cpu_in_interrupt_context(void)
|
||||
{
|
||||
uint32_t ps;
|
||||
RSR(PS, ps);
|
||||
return (ps & PS_UM) == 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -89,7 +89,7 @@
|
||||
#define APB_CLK_FREQ_ROM 13*1000000
|
||||
#define CPU_CLK_FREQ_ROM APB_CLK_FREQ_ROM
|
||||
#define CPU_CLK_FREQ APB_CLK_FREQ
|
||||
#define APB_CLK_FREQ 40*1000000 //unit: Hz
|
||||
#define APB_CLK_FREQ 80*1000000 //unit: Hz
|
||||
#define UART_CLK_FREQ APB_CLK_FREQ
|
||||
//#define WDT_CLK_FREQ APB_CLK_FREQ
|
||||
#define TIMER_CLK_FREQ (80000000>>4) //80MHz divided by 16
|
||||
|
14
components/esp32/ld/esp32.bt.ld
Normal file
14
components/esp32/ld/esp32.bt.ld
Normal file
@ -0,0 +1,14 @@
|
||||
/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES */
|
||||
/* The load addresses are defined later using the AT statements. */
|
||||
MEMORY
|
||||
{
|
||||
/* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
|
||||
of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
|
||||
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||
iram0_0_seg (RX) : org = 0x40080000, len = 0x20000 /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
|
||||
iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000 /* Even though the segment name is iram, it is actually mapped to flash */
|
||||
dram0_0_seg (RW) : org = 0x3FFC0000, len = 0x40000 /* Shared RAM, minus rom bss/data/stack.*/
|
||||
drom0_0_seg (R) : org = 0x3F400010, len = 0x800000
|
||||
}
|
||||
|
||||
_heap_end = 0x40000000;
|
14
components/esp32/ld/esp32.bt.trace.ld
Normal file
14
components/esp32/ld/esp32.bt.trace.ld
Normal file
@ -0,0 +1,14 @@
|
||||
/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES */
|
||||
/* The load addresses are defined later using the AT statements. */
|
||||
MEMORY
|
||||
{
|
||||
/* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
|
||||
of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
|
||||
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||
iram0_0_seg (RX) : org = 0x40080000, len = 0x20000 /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
|
||||
iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000 /* Even though the segment name is iram, it is actually mapped to flash */
|
||||
dram0_0_seg (RW) : org = 0x3FFC0000, len = 0x38000 /* Shared RAM, minus rom bss/data/stack.*/
|
||||
drom0_0_seg (R) : org = 0x3F400010, len = 0x800000
|
||||
}
|
||||
|
||||
_heap_end = 0x3FFF8000;
|
@ -1,18 +1,3 @@
|
||||
/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES */
|
||||
/* The load addresses are defined later using the AT statements. */
|
||||
MEMORY
|
||||
{
|
||||
/* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
|
||||
of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
|
||||
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||
iram0_0_seg (RX) : org = 0x40080000, len = 0x18000 /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
|
||||
iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000 /* Even though the segment name is iram, it is actually mapped to flash */
|
||||
dram0_0_seg (RW) : org = 0x3FFC0000, len = 0x20000 /* Shared RAM, minus rom bss/data/stack.*/
|
||||
drom0_0_seg (R) : org = 0x3F400010, len = 0x800000
|
||||
}
|
||||
|
||||
_heap_end = 0x3fffe000;
|
||||
|
||||
/* Default entry point: */
|
||||
ENTRY(call_user_start_cpu0);
|
||||
|
||||
@ -106,6 +91,7 @@ SECTIONS
|
||||
KEEP(*(.sdata2.*))
|
||||
KEEP(*(.gnu.linkonce.s2.*))
|
||||
KEEP(*(.jcr))
|
||||
*(.dram1 .dram1.*)
|
||||
_data_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_heap_start = ABSOLUTE(.);
|
14
components/esp32/ld/esp32.ld
Normal file
14
components/esp32/ld/esp32.ld
Normal file
@ -0,0 +1,14 @@
|
||||
/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES */
|
||||
/* The load addresses are defined later using the AT statements. */
|
||||
MEMORY
|
||||
{
|
||||
/* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
|
||||
of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
|
||||
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||
iram0_0_seg (RX) : org = 0x40080000, len = 0x20000 /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
|
||||
iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000 /* Even though the segment name is iram, it is actually mapped to flash */
|
||||
dram0_0_seg (RW) : org = 0x3FFB0000, len = 0x50000 /* Shared RAM, minus rom bss/data/stack.*/
|
||||
drom0_0_seg (R) : org = 0x3F400010, len = 0x800000
|
||||
}
|
||||
|
||||
_heap_end = 0x40000000;
|
14
components/esp32/ld/esp32.trace.ld
Normal file
14
components/esp32/ld/esp32.trace.ld
Normal file
@ -0,0 +1,14 @@
|
||||
/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES */
|
||||
/* The load addresses are defined later using the AT statements. */
|
||||
MEMORY
|
||||
{
|
||||
/* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
|
||||
of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
|
||||
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||
iram0_0_seg (RX) : org = 0x40080000, len = 0x20000 /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
|
||||
iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000 /* Even though the segment name is iram, it is actually mapped to flash */
|
||||
dram0_0_seg (RW) : org = 0x3FFB0000, len = 0x48000 /* Shared RAM, minus rom bss/data/stack.*/
|
||||
drom0_0_seg (R) : org = 0x3F400010, len = 0x800000
|
||||
}
|
||||
|
||||
_heap_end = 0x3FFF8000;
|
@ -1 +1 @@
|
||||
Subproject commit 40dc7af7f3d8da6745476e66cbd65be9b8988f6c
|
||||
Subproject commit b95a359c344cd052f45e3c38515e4613dd29f298
|
@ -19,13 +19,15 @@
|
||||
#include <errno.h>
|
||||
#include <sys/reent.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_attr.h"
|
||||
#include "rom/libc_stubs.h"
|
||||
#include "rom/uart.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
int uart_tx_one_char(uint8_t c);
|
||||
|
||||
void abort() {
|
||||
do
|
||||
{
|
||||
@ -136,6 +138,21 @@ int _open_r(struct _reent *r, const char * path, int flags, int mode) {
|
||||
ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) {
|
||||
const char* p = (const char*) data;
|
||||
if (fd == STDOUT_FILENO) {
|
||||
static _lock_t stdout_lock; /* lazily initialised */
|
||||
/* Even though newlib does stream locking on stdout, we need
|
||||
a dedicated stdout UART lock...
|
||||
|
||||
This is because each task has its own _reent structure with
|
||||
unique FILEs for stdin/stdout/stderr, so these are
|
||||
per-thread (lazily initialised by __sinit the first time a
|
||||
stdio function is used, see findfp.c:235.
|
||||
|
||||
It seems like overkill to allocate a FILE-per-task and lock
|
||||
a thread-local stream, but I see no easy way to fix this
|
||||
(pre-__sinit_, tasks have "fake" FILEs ie __sf_fake_stdout
|
||||
which aren't fully valid.)
|
||||
*/
|
||||
_lock_acquire_recursive(&stdout_lock);
|
||||
while(size--) {
|
||||
#if CONFIG_NEWLIB_STDOUT_ADDCR
|
||||
if (*p=='\n') {
|
||||
@ -145,6 +162,7 @@ ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) {
|
||||
uart_tx_one_char(*p);
|
||||
++p;
|
||||
}
|
||||
_lock_release_recursive(&stdout_lock);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@ -158,37 +176,188 @@ ssize_t _read_r(struct _reent *r, int fd, void * dst, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: implement locks via FreeRTOS mutexes
|
||||
void _lock_init(_lock_t *lock) {
|
||||
/* Notes on our newlib lock implementation:
|
||||
*
|
||||
* - Use FreeRTOS mutex semaphores as locks.
|
||||
* - lock_t is int, but we store an xSemaphoreHandle there.
|
||||
* - Locks are no-ops until the FreeRTOS scheduler is running.
|
||||
* - Due to this, locks need to be lazily initialised the first time
|
||||
* they are acquired. Initialisation/deinitialisation of locks is
|
||||
* protected by lock_init_spinlock.
|
||||
* - Race conditions around lazy initialisation (via lock_acquire) are
|
||||
* protected against.
|
||||
* - Anyone calling lock_close is reponsible for ensuring noone else
|
||||
* is holding the lock at this time.
|
||||
* - Race conditions between lock_close & lock_init (for the same lock)
|
||||
* are the responsibility of the caller.
|
||||
*/
|
||||
|
||||
static portMUX_TYPE lock_init_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
/* Initialise the given lock by allocating a new mutex semaphore
|
||||
as the _lock_t value.
|
||||
*/
|
||||
static void IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mutex_type) {
|
||||
portENTER_CRITICAL(&lock_init_spinlock);
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
/* nothing to do until the scheduler is running */
|
||||
*lock = 0; /* ensure lock is zeroed out, in case it's an automatic variable */
|
||||
portEXIT_CRITICAL(&lock_init_spinlock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (*lock) {
|
||||
/* Lock already initialised (either we didn't check earlier,
|
||||
or it got initialised while we were waiting for the
|
||||
spinlock.) */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a new semaphore
|
||||
|
||||
this is a bit of an API violation, as we're calling the
|
||||
private function xQueueCreateMutex(x) directly instead of
|
||||
the xSemaphoreCreateMutex / xSemaphoreCreateRecursiveMutex
|
||||
wrapper functions...
|
||||
|
||||
The better alternative would be to pass pointers to one of
|
||||
the two xSemaphoreCreate___Mutex functions, but as FreeRTOS
|
||||
implements these as macros instead of inline functions
|
||||
(*party like it's 1998!*) it's not possible to do this
|
||||
without writing wrappers. Doing it this way seems much less
|
||||
spaghetti-like.
|
||||
*/
|
||||
xSemaphoreHandle new_sem = xQueueCreateMutex(mutex_type);
|
||||
if (!new_sem) {
|
||||
abort(); /* No more semaphores available or OOM */
|
||||
}
|
||||
*lock = (_lock_t)new_sem;
|
||||
}
|
||||
portEXIT_CRITICAL(&lock_init_spinlock);
|
||||
}
|
||||
|
||||
void _lock_init_recursive(_lock_t *lock) {
|
||||
void IRAM_ATTR _lock_init(_lock_t *lock) {
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void _lock_close(_lock_t *lock) {
|
||||
void IRAM_ATTR _lock_init_recursive(_lock_t *lock) {
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
void _lock_close_recursive(_lock_t *lock) {
|
||||
/* Free the mutex semaphore pointed to by *lock, and zero it out.
|
||||
|
||||
Note that FreeRTOS doesn't account for deleting mutexes while they
|
||||
are held, and neither do we... so take care not to delete newlib
|
||||
locks while they may be held by other tasks!
|
||||
*/
|
||||
void IRAM_ATTR _lock_close(_lock_t *lock) {
|
||||
portENTER_CRITICAL(&lock_init_spinlock);
|
||||
if (*lock) {
|
||||
xSemaphoreHandle h = (xSemaphoreHandle)(*lock);
|
||||
#if (INCLUDE_xSemaphoreGetMutexHolder == 1)
|
||||
configASSERT(xSemaphoreGetMutexHolder(h) == NULL); /* mutex should not be held */
|
||||
#endif
|
||||
vSemaphoreDelete(h);
|
||||
*lock = 0;
|
||||
}
|
||||
portEXIT_CRITICAL(&lock_init_spinlock);
|
||||
}
|
||||
|
||||
void _lock_acquire(_lock_t *lock) {
|
||||
/* Acquire the mutex semaphore for lock. wait up to delay ticks.
|
||||
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
|
||||
*/
|
||||
static int IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type) {
|
||||
xSemaphoreHandle h = (xSemaphoreHandle)(*lock);
|
||||
if (!h) {
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return 0; /* locking is a no-op before scheduler is up, so this "succeeds" */
|
||||
}
|
||||
/* lazy initialise lock - might have had a static initializer in newlib (that we don't use),
|
||||
or _lock_init might have been called before the scheduler was running... */
|
||||
lock_init_generic(lock, mutex_type);
|
||||
h = (xSemaphoreHandle)(*lock);
|
||||
configASSERT(h != NULL);
|
||||
}
|
||||
|
||||
BaseType_t success;
|
||||
if (cpu_in_interrupt_context()) {
|
||||
/* In ISR Context */
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
abort(); /* recursive mutexes make no sense in ISR context */
|
||||
}
|
||||
BaseType_t higher_task_woken = false;
|
||||
success = xSemaphoreTakeFromISR(h, &higher_task_woken);
|
||||
if (!success && delay > 0) {
|
||||
abort(); /* Tried to block on mutex from ISR, couldn't... rewrite your program to avoid libc interactions in ISRs! */
|
||||
}
|
||||
if (higher_task_woken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* In task context */
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
success = xSemaphoreTakeRecursive(h, delay);
|
||||
} else {
|
||||
success = xSemaphoreTake(h, delay);
|
||||
}
|
||||
}
|
||||
|
||||
return (success == pdTRUE) ? 0 : -1;
|
||||
}
|
||||
|
||||
void _lock_acquire_recursive(_lock_t *lock) {
|
||||
void IRAM_ATTR _lock_acquire(_lock_t *lock) {
|
||||
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
int _lock_try_acquire(_lock_t *lock) {
|
||||
return 0;
|
||||
void IRAM_ATTR _lock_acquire_recursive(_lock_t *lock) {
|
||||
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
int _lock_try_acquire_recursive(_lock_t *lock) {
|
||||
return 0;
|
||||
int IRAM_ATTR _lock_try_acquire(_lock_t *lock) {
|
||||
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void _lock_release(_lock_t *lock) {
|
||||
int IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock) {
|
||||
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
void _lock_release_recursive(_lock_t *lock) {
|
||||
/* Release the mutex semaphore for lock.
|
||||
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
|
||||
*/
|
||||
static void IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type) {
|
||||
xSemaphoreHandle h = (xSemaphoreHandle)(*lock);
|
||||
if (h == NULL) {
|
||||
/* This is probably because the scheduler isn't running yet,
|
||||
or the scheduler just started running and some code was
|
||||
"holding" a not-yet-initialised lock... */
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu_in_interrupt_context()) {
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
abort(); /* indicates logic bug, it shouldn't be possible to lock recursively in ISR */
|
||||
}
|
||||
BaseType_t higher_task_woken = false;
|
||||
xSemaphoreGiveFromISR(h, &higher_task_woken);
|
||||
if (higher_task_woken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
} else {
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
xSemaphoreGiveRecursive(h);
|
||||
} else {
|
||||
xSemaphoreGive(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_release(_lock_t *lock) {
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_release_recursive(_lock_t *lock) {
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
static struct _reent s_reent;
|
||||
@ -239,7 +408,7 @@ static struct syscall_stub_table s_stub_table = {
|
||||
._lock_init = &_lock_init,
|
||||
._lock_init_recursive = &_lock_init_recursive,
|
||||
._lock_close = &_lock_close,
|
||||
._lock_close_recursive = &_lock_close_recursive,
|
||||
._lock_close_recursive = &_lock_close,
|
||||
._lock_acquire = &_lock_acquire,
|
||||
._lock_acquire_recursive = &_lock_acquire_recursive,
|
||||
._lock_try_acquire = &_lock_try_acquire,
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi.h"
|
||||
@ -23,30 +24,11 @@
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
//#include "tcpip_adapter.h"
|
||||
|
||||
#define ESP32_WORKAROUND 1
|
||||
|
||||
#if CONFIG_WIFI_ENABLED
|
||||
|
||||
#ifdef ESP32_WORKAROUND
|
||||
|
||||
SemaphoreHandle_t stdio_mutex_tx = NULL;
|
||||
#define os_printf(fmt, ...) do {\
|
||||
if (!stdio_mutex_tx) {\
|
||||
stdio_mutex_tx = xSemaphoreCreateMutex();\
|
||||
}\
|
||||
\
|
||||
xSemaphoreTake(stdio_mutex_tx, portMAX_DELAY);\
|
||||
ets_printf(fmt, ##__VA_ARGS__);\
|
||||
xSemaphoreGive(stdio_mutex_tx);\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
static wifi_startup_cb_t startup_cb;
|
||||
|
||||
#define WIFI_DEBUG os_printf
|
||||
#define WIFI_DEBUG(...)
|
||||
#define WIFI_API_CALL_CHECK(info, api_call, ret) \
|
||||
do{\
|
||||
esp_err_t __err = (api_call);\
|
||||
@ -56,6 +38,8 @@ do{\
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
|
||||
|
||||
static void esp_wifi_task(void *pvParameters)
|
||||
{
|
||||
esp_err_t err;
|
||||
@ -65,29 +49,37 @@ static void esp_wifi_task(void *pvParameters)
|
||||
do {
|
||||
err = esp_wifi_init(&cfg);
|
||||
if (err != ESP_OK) {
|
||||
WIFI_DEBUG("esp_wifi_init fail, ret=%d\n", err);
|
||||
break;
|
||||
}
|
||||
|
||||
if (startup_cb) {
|
||||
err = (*startup_cb)();
|
||||
if (err != ESP_OK) {
|
||||
WIFI_DEBUG("startup_cb fail, ret=%d\n", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
err = esp_wifi_start();
|
||||
if (err != ESP_OK) { // TODO: if already started, it's also OK
|
||||
if (err != ESP_OK) {
|
||||
WIFI_DEBUG("esp_wifi_start fail, ret=%d\n", err);
|
||||
break;
|
||||
}
|
||||
|
||||
#if CONFIG_WIFI_AUTO_CONNECT
|
||||
wifi_mode_t mode;
|
||||
bool auto_connect;
|
||||
err = esp_wifi_get_mode(&mode);
|
||||
if (err != ESP_OK){
|
||||
WIFI_DEBUG("esp_wifi_get_mode fail, ret=%d\n", err);
|
||||
}
|
||||
|
||||
esp_wifi_get_mode(&mode);
|
||||
|
||||
if (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA) {
|
||||
err = esp_wifi_get_auto_connect(&auto_connect);
|
||||
if ((mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA) && auto_connect) {
|
||||
err = esp_wifi_connect();
|
||||
if (err != ESP_OK) {
|
||||
WIFI_DEBUG("esp_wifi_connect fail, ret=%d\n", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -95,6 +87,7 @@ static void esp_wifi_task(void *pvParameters)
|
||||
} while (0);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
WIFI_DEBUG("wifi startup fail, deinit\n");
|
||||
esp_wifi_deinit();
|
||||
}
|
||||
|
||||
|
@ -46,4 +46,52 @@ config ESPTOOLPY_COMPRESSED
|
||||
decompress it on the fly before flashing it. For most payloads, this should result in a
|
||||
speed increase.
|
||||
|
||||
choice ESPTOOLPY_FLASHMODE
|
||||
prompt "Flash SPI mode"
|
||||
default ESPTOOLPY_FLASHMODE_DIO
|
||||
help
|
||||
Mode the flash chip is flashed in, as well as the default mode for the
|
||||
binary to run in.
|
||||
|
||||
config ESPTOOLPY_FLASHMODE_QIO
|
||||
bool "QIO"
|
||||
config ESPTOOLPY_FLASHMODE_QOUT
|
||||
bool "QOUT"
|
||||
config ESPTOOLPY_FLASHMODE_DIO
|
||||
bool "DIO"
|
||||
config ESPTOOLPY_FLASHMODE_DOUT
|
||||
bool "DOUT"
|
||||
endchoice
|
||||
|
||||
config ESPTOOLPY_FLASHMODE
|
||||
string
|
||||
default "qio" if ESPTOOLPY_FLASHMODE_QIO
|
||||
default "qout" if ESPTOOLPY_FLASHMODE_QOUT
|
||||
default "dio" if ESPTOOLPY_FLASHMODE_DIO
|
||||
default "dout" if ESPTOOLPY_FLASHMODE_DOUT
|
||||
|
||||
|
||||
choice ESPTOOLPY_FLASHFREQ
|
||||
prompt "Flash SPI speed"
|
||||
default ESPTOOLPY_FLASHFREQ_40M
|
||||
help
|
||||
The SPI flash frequency to be used.
|
||||
|
||||
config ESPTOOLPY_FLASHFREQ_80M
|
||||
bool "80 MHz"
|
||||
config ESPTOOLPY_FLASHFREQ_40M
|
||||
bool "40 MHz"
|
||||
config ESPTOOLPY_FLASHFREQ_26M
|
||||
bool "26 MHz"
|
||||
config ESPTOOLPY_FLASHFREQ_20M
|
||||
bool "20 MHz"
|
||||
endchoice
|
||||
|
||||
config ESPTOOLPY_FLASHFREQ
|
||||
string
|
||||
default "80m" if ESPTOOLPY_FLASHFREQ_80M
|
||||
default "40m" if ESPTOOLPY_FLASHFREQ_40M
|
||||
default "26m" if ESPTOOLPY_FLASHFREQ_26M
|
||||
default "20m" if ESPTOOLPY_FLASHFREQ_20M
|
||||
|
||||
endmenu
|
||||
|
@ -2,6 +2,8 @@
|
||||
# components have their own flash targets that can use these variables.
|
||||
ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT)
|
||||
ESPBAUD ?= $(CONFIG_ESPTOOLPY_BAUD)
|
||||
ESPFLASHMODE ?= $(CONFIG_ESPTOOLPY_FLASHMODE)
|
||||
ESPFLASHFREQ ?= $(CONFIG_ESPTOOLPY_FLASHFREQ)
|
||||
|
||||
PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
|
||||
|
||||
@ -12,12 +14,12 @@ PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
|
||||
ESPTOOLPY := $(PYTHON) $(IDF_PATH)/bin/esptool.py --chip esp32
|
||||
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
|
||||
|
||||
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z)
|
||||
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ)
|
||||
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
|
||||
|
||||
$(APP_BIN): $(APP_ELF)
|
||||
$(Q) $(ESPTOOLPY) elf2image -o $@ $<
|
||||
$(Q) $(ESPTOOLPY) elf2image --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) -o $@ $<
|
||||
|
||||
flash: all_binaries
|
||||
@echo "Flashing project app to $(CONFIG_APP_OFFSET)..."
|
||||
|
21
components/expat/COPYING
Normal file
21
components/expat/COPYING
Normal file
@ -0,0 +1,21 @@
|
||||
Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
|
||||
Copyright (c) 2001-2016 Expat maintainers
|
||||
|
||||
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.
|
15
components/expat/Makefile
Normal file
15
components/expat/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
|
||||
# this will take the sources in this directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
COMPONENT_ADD_INCLUDEDIRS := port/include include/expat
|
||||
|
||||
COMPONENT_SRCDIRS := library port
|
||||
|
||||
EXTRA_CFLAGS := -Wno-error=address -Waddress -DHAVE_EXPAT_CONFIG_H
|
||||
|
||||
include $(IDF_PATH)/make/component.mk
|
139
components/expat/README
Normal file
139
components/expat/README
Normal file
@ -0,0 +1,139 @@
|
||||
|
||||
Expat, Release 2.2.0
|
||||
|
||||
This is Expat, a C library for parsing XML, written by James Clark.
|
||||
Expat is a stream-oriented XML parser. This means that you register
|
||||
handlers with the parser before starting the parse. These handlers
|
||||
are called when the parser discovers the associated structures in the
|
||||
document being parsed. A start tag is an example of the kind of
|
||||
structures for which you may register handlers.
|
||||
|
||||
Windows users should use the expat_win32bin package, which includes
|
||||
both precompiled libraries and executables, and source code for
|
||||
developers.
|
||||
|
||||
Expat is free software. You may copy, distribute, and modify it under
|
||||
the terms of the License contained in the file COPYING distributed
|
||||
with this package. This license is the same as the MIT/X Consortium
|
||||
license.
|
||||
|
||||
Versions of Expat that have an odd minor version (the middle number in
|
||||
the release above), are development releases and should be considered
|
||||
as beta software. Releases with even minor version numbers are
|
||||
intended to be production grade software.
|
||||
|
||||
If you are building Expat from a check-out from the CVS repository,
|
||||
you need to run a script that generates the configure script using the
|
||||
GNU autoconf and libtool tools. To do this, you need to have
|
||||
autoconf 2.58 or newer. Run the script like this:
|
||||
|
||||
./buildconf.sh
|
||||
|
||||
Once this has been done, follow the same instructions as for building
|
||||
from a source distribution.
|
||||
|
||||
To build Expat from a source distribution, you first run the
|
||||
configuration shell script in the top level distribution directory:
|
||||
|
||||
./configure
|
||||
|
||||
There are many options which you may provide to configure (which you
|
||||
can discover by running configure with the --help option). But the
|
||||
one of most interest is the one that sets the installation directory.
|
||||
By default, the configure script will set things up to install
|
||||
libexpat into /usr/local/lib, expat.h into /usr/local/include, and
|
||||
xmlwf into /usr/local/bin. If, for example, you'd prefer to install
|
||||
into /home/me/mystuff/lib, /home/me/mystuff/include, and
|
||||
/home/me/mystuff/bin, you can tell configure about that with:
|
||||
|
||||
./configure --prefix=/home/me/mystuff
|
||||
|
||||
Another interesting option is to enable 64-bit integer support for
|
||||
line and column numbers and the over-all byte index:
|
||||
|
||||
./configure CPPFLAGS=-DXML_LARGE_SIZE
|
||||
|
||||
However, such a modification would be a breaking change to the ABI
|
||||
and is therefore not recommended for general use - e.g. as part of
|
||||
a Linux distribution - but rather for builds with special requirements.
|
||||
|
||||
After running the configure script, the "make" command will build
|
||||
things and "make install" will install things into their proper
|
||||
location. Have a look at the "Makefile" to learn about additional
|
||||
"make" options. Note that you need to have write permission into
|
||||
the directories into which things will be installed.
|
||||
|
||||
If you are interested in building Expat to provide document
|
||||
information in UTF-16 encoding rather than the default UTF-8, follow
|
||||
these instructions (after having run "make distclean"):
|
||||
|
||||
1. For UTF-16 output as unsigned short (and version/error
|
||||
strings as char), run:
|
||||
|
||||
./configure CPPFLAGS=-DXML_UNICODE
|
||||
|
||||
For UTF-16 output as wchar_t (incl. version/error strings),
|
||||
run:
|
||||
|
||||
./configure CFLAGS="-g -O2 -fshort-wchar" \
|
||||
CPPFLAGS=-DXML_UNICODE_WCHAR_T
|
||||
|
||||
2. Edit the MakeFile, changing:
|
||||
|
||||
LIBRARY = libexpat.la
|
||||
|
||||
to:
|
||||
|
||||
LIBRARY = libexpatw.la
|
||||
|
||||
(Note the additional "w" in the library name.)
|
||||
|
||||
3. Run "make buildlib" (which builds the library only).
|
||||
Or, to save step 2, run "make buildlib LIBRARY=libexpatw.la".
|
||||
|
||||
4. Run "make installlib" (which installs the library only).
|
||||
Or, if step 2 was omitted, run "make installlib LIBRARY=libexpatw.la".
|
||||
|
||||
Using DESTDIR or INSTALL_ROOT is enabled, with INSTALL_ROOT being the default
|
||||
value for DESTDIR, and the rest of the make file using only DESTDIR.
|
||||
It works as follows:
|
||||
$ make install DESTDIR=/path/to/image
|
||||
overrides the in-makefile set DESTDIR, while both
|
||||
$ INSTALL_ROOT=/path/to/image make install
|
||||
$ make install INSTALL_ROOT=/path/to/image
|
||||
use DESTDIR=$(INSTALL_ROOT), even if DESTDIR eventually is defined in the
|
||||
environment, because variable-setting priority is
|
||||
1) commandline
|
||||
2) in-makefile
|
||||
3) environment
|
||||
|
||||
Note: This only applies to the Expat library itself, building UTF-16 versions
|
||||
of xmlwf and the tests is currently not supported.
|
||||
|
||||
Note for Solaris users: The "ar" command is usually located in
|
||||
"/usr/ccs/bin", which is not in the default PATH. You will need to
|
||||
add this to your path for the "make" command, and probably also switch
|
||||
to GNU make (the "make" found in /usr/ccs/bin does not seem to work
|
||||
properly -- apparently it does not understand .PHONY directives). If
|
||||
you're using ksh or bash, use this command to build:
|
||||
|
||||
PATH=/usr/ccs/bin:$PATH make
|
||||
|
||||
When using Expat with a project using autoconf for configuration, you
|
||||
can use the probing macro in conftools/expat.m4 to determine how to
|
||||
include Expat. See the comments at the top of that file for more
|
||||
information.
|
||||
|
||||
A reference manual is available in the file doc/reference.html in this
|
||||
distribution.
|
||||
|
||||
The homepage for this project is http://www.libexpat.org/. There
|
||||
are links there to connect you to the bug reports page. If you need
|
||||
to report a bug when you don't have access to a browser, you may also
|
||||
send a bug report by email to expat-bugs@mail.libexpat.org.
|
||||
|
||||
Discussion related to the direction of future expat development takes
|
||||
place on expat-discuss@mail.libexpat.org. Archives of this list and
|
||||
other Expat-related lists may be found at:
|
||||
|
||||
http://mail.libexpat.org/mailman/listinfo/
|
92
components/expat/include/expat/ascii.h
Normal file
92
components/expat/include/expat/ascii.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
#define ASCII_A 0x41
|
||||
#define ASCII_B 0x42
|
||||
#define ASCII_C 0x43
|
||||
#define ASCII_D 0x44
|
||||
#define ASCII_E 0x45
|
||||
#define ASCII_F 0x46
|
||||
#define ASCII_G 0x47
|
||||
#define ASCII_H 0x48
|
||||
#define ASCII_I 0x49
|
||||
#define ASCII_J 0x4A
|
||||
#define ASCII_K 0x4B
|
||||
#define ASCII_L 0x4C
|
||||
#define ASCII_M 0x4D
|
||||
#define ASCII_N 0x4E
|
||||
#define ASCII_O 0x4F
|
||||
#define ASCII_P 0x50
|
||||
#define ASCII_Q 0x51
|
||||
#define ASCII_R 0x52
|
||||
#define ASCII_S 0x53
|
||||
#define ASCII_T 0x54
|
||||
#define ASCII_U 0x55
|
||||
#define ASCII_V 0x56
|
||||
#define ASCII_W 0x57
|
||||
#define ASCII_X 0x58
|
||||
#define ASCII_Y 0x59
|
||||
#define ASCII_Z 0x5A
|
||||
|
||||
#define ASCII_a 0x61
|
||||
#define ASCII_b 0x62
|
||||
#define ASCII_c 0x63
|
||||
#define ASCII_d 0x64
|
||||
#define ASCII_e 0x65
|
||||
#define ASCII_f 0x66
|
||||
#define ASCII_g 0x67
|
||||
#define ASCII_h 0x68
|
||||
#define ASCII_i 0x69
|
||||
#define ASCII_j 0x6A
|
||||
#define ASCII_k 0x6B
|
||||
#define ASCII_l 0x6C
|
||||
#define ASCII_m 0x6D
|
||||
#define ASCII_n 0x6E
|
||||
#define ASCII_o 0x6F
|
||||
#define ASCII_p 0x70
|
||||
#define ASCII_q 0x71
|
||||
#define ASCII_r 0x72
|
||||
#define ASCII_s 0x73
|
||||
#define ASCII_t 0x74
|
||||
#define ASCII_u 0x75
|
||||
#define ASCII_v 0x76
|
||||
#define ASCII_w 0x77
|
||||
#define ASCII_x 0x78
|
||||
#define ASCII_y 0x79
|
||||
#define ASCII_z 0x7A
|
||||
|
||||
#define ASCII_0 0x30
|
||||
#define ASCII_1 0x31
|
||||
#define ASCII_2 0x32
|
||||
#define ASCII_3 0x33
|
||||
#define ASCII_4 0x34
|
||||
#define ASCII_5 0x35
|
||||
#define ASCII_6 0x36
|
||||
#define ASCII_7 0x37
|
||||
#define ASCII_8 0x38
|
||||
#define ASCII_9 0x39
|
||||
|
||||
#define ASCII_TAB 0x09
|
||||
#define ASCII_SPACE 0x20
|
||||
#define ASCII_EXCL 0x21
|
||||
#define ASCII_QUOT 0x22
|
||||
#define ASCII_AMP 0x26
|
||||
#define ASCII_APOS 0x27
|
||||
#define ASCII_MINUS 0x2D
|
||||
#define ASCII_PERIOD 0x2E
|
||||
#define ASCII_COLON 0x3A
|
||||
#define ASCII_SEMI 0x3B
|
||||
#define ASCII_LT 0x3C
|
||||
#define ASCII_EQUALS 0x3D
|
||||
#define ASCII_GT 0x3E
|
||||
#define ASCII_LSQB 0x5B
|
||||
#define ASCII_RSQB 0x5D
|
||||
#define ASCII_UNDERSCORE 0x5F
|
||||
#define ASCII_LPAREN 0x28
|
||||
#define ASCII_RPAREN 0x29
|
||||
#define ASCII_FF 0x0C
|
||||
#define ASCII_SLASH 0x2F
|
||||
#define ASCII_HASH 0x23
|
||||
#define ASCII_PIPE 0x7C
|
||||
#define ASCII_COMMA 0x2C
|
36
components/expat/include/expat/asciitab.h
Normal file
36
components/expat/include/expat/asciitab.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
|
||||
/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
|
||||
/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
|
||||
/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
|
||||
/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
|
||||
/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
|
||||
/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
|
||||
/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
|
||||
/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
|
||||
/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
|
||||
/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
|
||||
/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
|
||||
/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
|
||||
/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
|
||||
/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
|
||||
/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
|
||||
/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
|
||||
/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
|
1048
components/expat/include/expat/expat.h
Normal file
1048
components/expat/include/expat/expat.h
Normal file
File diff suppressed because it is too large
Load Diff
103
components/expat/include/expat/expat_config.h
Normal file
103
components/expat/include/expat/expat_config.h
Normal file
@ -0,0 +1,103 @@
|
||||
/* expat_config.h. Generated from expat_config.h.in by configure. */
|
||||
/* expat_config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
|
||||
#define BYTEORDER 1234
|
||||
|
||||
/* Define to 1 if you have the `bcopy' function. */
|
||||
#define HAVE_BCOPY 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#define HAVE_GETPAGESIZE 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#define HAVE_MEMMOVE 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#define HAVE_MMAP 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "expat-bugs@libexpat.org"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "expat"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "expat 2.2.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "expat"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.2.0"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* whether byteorder is bigendian */
|
||||
/* #undef WORDS_BIGENDIAN */
|
||||
|
||||
/* Define to specify how much context to retain around the current parse
|
||||
point. */
|
||||
#define XML_CONTEXT_BYTES 1024
|
||||
|
||||
/* Define to make parameter entity parsing functionality available. */
|
||||
#define XML_DTD 1
|
||||
|
||||
/* Define to make XML Namespaces functionality available. */
|
||||
#define XML_NS 1
|
||||
|
||||
/* Define to __FUNCTION__ or "" if `__func__' does not conform to ANSI C. */
|
||||
/* #undef __func__ */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
/* #undef off_t */
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
129
components/expat/include/expat/expat_external.h
Normal file
129
components/expat/include/expat/expat_external.h
Normal file
@ -0,0 +1,129 @@
|
||||
/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
#ifndef Expat_External_INCLUDED
|
||||
#define Expat_External_INCLUDED 1
|
||||
|
||||
/* External API definitions */
|
||||
|
||||
#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
|
||||
#define XML_USE_MSC_EXTENSIONS 1
|
||||
#endif
|
||||
|
||||
/* Expat tries very hard to make the API boundary very specifically
|
||||
defined. There are two macros defined to control this boundary;
|
||||
each of these can be defined before including this header to
|
||||
achieve some different behavior, but doing so it not recommended or
|
||||
tested frequently.
|
||||
|
||||
XMLCALL - The calling convention to use for all calls across the
|
||||
"library boundary." This will default to cdecl, and
|
||||
try really hard to tell the compiler that's what we
|
||||
want.
|
||||
|
||||
XMLIMPORT - Whatever magic is needed to note that a function is
|
||||
to be imported from a dynamically loaded library
|
||||
(.dll, .so, or .sl, depending on your platform).
|
||||
|
||||
The XMLCALL macro was added in Expat 1.95.7. The only one which is
|
||||
expected to be directly useful in client code is XMLCALL.
|
||||
|
||||
Note that on at least some Unix versions, the Expat library must be
|
||||
compiled with the cdecl calling convention as the default since
|
||||
system headers may assume the cdecl convention.
|
||||
*/
|
||||
#ifndef XMLCALL
|
||||
#if defined(_MSC_VER)
|
||||
#define XMLCALL __cdecl
|
||||
#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
|
||||
#define XMLCALL __attribute__((cdecl))
|
||||
#else
|
||||
/* For any platform which uses this definition and supports more than
|
||||
one calling convention, we need to extend this definition to
|
||||
declare the convention used on that platform, if it's possible to
|
||||
do so.
|
||||
|
||||
If this is the case for your platform, please file a bug report
|
||||
with information on how to identify your platform via the C
|
||||
pre-processor and how to specify the same calling convention as the
|
||||
platform's malloc() implementation.
|
||||
*/
|
||||
#define XMLCALL
|
||||
#endif
|
||||
#endif /* not defined XMLCALL */
|
||||
|
||||
|
||||
#if !defined(XML_STATIC) && !defined(XMLIMPORT)
|
||||
#ifndef XML_BUILDING_EXPAT
|
||||
/* using Expat from an application */
|
||||
|
||||
#ifdef XML_USE_MSC_EXTENSIONS
|
||||
#define XMLIMPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* not defined XML_STATIC */
|
||||
|
||||
#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
#define XMLIMPORT __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
|
||||
/* If we didn't define it above, define it away: */
|
||||
#ifndef XMLIMPORT
|
||||
#define XMLIMPORT
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
|
||||
#define XML_ATTR_MALLOC __attribute__((__malloc__))
|
||||
#else
|
||||
#define XML_ATTR_MALLOC
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
||||
#define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
|
||||
#else
|
||||
#define XML_ATTR_ALLOC_SIZE(x)
|
||||
#endif
|
||||
|
||||
#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef XML_UNICODE_WCHAR_T
|
||||
#define XML_UNICODE
|
||||
#endif
|
||||
|
||||
#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
|
||||
#ifdef XML_UNICODE_WCHAR_T
|
||||
typedef wchar_t XML_Char;
|
||||
typedef wchar_t XML_LChar;
|
||||
#else
|
||||
typedef unsigned short XML_Char;
|
||||
typedef char XML_LChar;
|
||||
#endif /* XML_UNICODE_WCHAR_T */
|
||||
#else /* Information is UTF-8 encoded. */
|
||||
typedef char XML_Char;
|
||||
typedef char XML_LChar;
|
||||
#endif /* XML_UNICODE */
|
||||
|
||||
#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
|
||||
#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
|
||||
typedef __int64 XML_Index;
|
||||
typedef unsigned __int64 XML_Size;
|
||||
#else
|
||||
typedef long long XML_Index;
|
||||
typedef unsigned long long XML_Size;
|
||||
#endif
|
||||
#else
|
||||
typedef long XML_Index;
|
||||
typedef unsigned long XML_Size;
|
||||
#endif /* XML_LARGE_SIZE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* not Expat_External_INCLUDED */
|
37
components/expat/include/expat/iasciitab.h
Normal file
37
components/expat/include/expat/iasciitab.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
|
||||
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
|
||||
/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
|
||||
/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
|
||||
/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
|
||||
/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
|
||||
/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
|
||||
/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
|
||||
/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
|
||||
/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
|
||||
/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
|
||||
/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
|
||||
/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
|
||||
/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
|
||||
/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
|
||||
/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
|
||||
/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
|
||||
/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
|
||||
/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
|
95
components/expat/include/expat/internal.h
Normal file
95
components/expat/include/expat/internal.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* internal.h
|
||||
|
||||
Internal definitions used by Expat. This is not needed to compile
|
||||
client code.
|
||||
|
||||
The following calling convention macros are defined for frequently
|
||||
called functions:
|
||||
|
||||
FASTCALL - Used for those internal functions that have a simple
|
||||
body and a low number of arguments and local variables.
|
||||
|
||||
PTRCALL - Used for functions called though function pointers.
|
||||
|
||||
PTRFASTCALL - Like PTRCALL, but for low number of arguments.
|
||||
|
||||
inline - Used for selected internal functions for which inlining
|
||||
may improve performance on some platforms.
|
||||
|
||||
Note: Use of these macros is based on judgement, not hard rules,
|
||||
and therefore subject to change.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
|
||||
/* We'll use this version by default only where we know it helps.
|
||||
|
||||
regparm() generates warnings on Solaris boxes. See SF bug #692878.
|
||||
|
||||
Instability reported with egcs on a RedHat Linux 7.3.
|
||||
Let's comment out:
|
||||
#define FASTCALL __attribute__((stdcall, regparm(3)))
|
||||
and let's try this:
|
||||
*/
|
||||
#define FASTCALL __attribute__((regparm(3)))
|
||||
#define PTRFASTCALL __attribute__((regparm(3)))
|
||||
#endif
|
||||
|
||||
/* Using __fastcall seems to have an unexpected negative effect under
|
||||
MS VC++, especially for function pointers, so we won't use it for
|
||||
now on that platform. It may be reconsidered for a future release
|
||||
if it can be made more effective.
|
||||
Likely reason: __fastcall on Windows is like stdcall, therefore
|
||||
the compiler cannot perform stack optimizations for call clusters.
|
||||
*/
|
||||
|
||||
/* Make sure all of these are defined if they aren't already. */
|
||||
|
||||
#ifndef FASTCALL
|
||||
#define FASTCALL
|
||||
#endif
|
||||
|
||||
#ifndef PTRCALL
|
||||
#define PTRCALL
|
||||
#endif
|
||||
|
||||
#ifndef PTRFASTCALL
|
||||
#define PTRFASTCALL
|
||||
#endif
|
||||
|
||||
#ifndef XML_MIN_SIZE
|
||||
#if !defined(__cplusplus) && !defined(inline)
|
||||
#ifdef __GNUC__
|
||||
#define inline __inline
|
||||
#endif /* __GNUC__ */
|
||||
#endif
|
||||
#endif /* XML_MIN_SIZE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define inline inline
|
||||
#else
|
||||
#ifndef inline
|
||||
#define inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UNUSED_P
|
||||
# ifdef __GNUC__
|
||||
# define UNUSED_P(p) UNUSED_ ## p __attribute__((__unused__))
|
||||
# else
|
||||
# define UNUSED_P(p) UNUSED_ ## p
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
36
components/expat/include/expat/latin1tab.h
Normal file
36
components/expat/include/expat/latin1tab.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
|
||||
/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
|
||||
/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
|
||||
/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
|
||||
/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
|
||||
/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
|
||||
/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
||||
/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
|
150
components/expat/include/expat/nametab.h
Normal file
150
components/expat/include/expat/nametab.h
Normal file
@ -0,0 +1,150 @@
|
||||
static const unsigned namingBitmap[] = {
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
|
||||
0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
|
||||
0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
|
||||
0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
|
||||
0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
|
||||
0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
|
||||
0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
|
||||
0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
|
||||
0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
|
||||
0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
|
||||
0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
|
||||
0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
|
||||
0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
|
||||
0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
|
||||
0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
|
||||
0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
|
||||
0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
|
||||
0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
|
||||
0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
|
||||
0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
|
||||
0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
|
||||
0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
|
||||
0x40000000, 0xF580C900, 0x00000007, 0x02010800,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
|
||||
0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
|
||||
0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
|
||||
0x00000000, 0x00004C40, 0x00000000, 0x00000000,
|
||||
0x00000007, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
|
||||
0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
|
||||
0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
|
||||
0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
|
||||
0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
|
||||
0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
|
||||
0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
|
||||
0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
|
||||
0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
|
||||
0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
|
||||
0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
|
||||
0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
|
||||
0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
|
||||
0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
|
||||
0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
|
||||
0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
|
||||
0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
|
||||
0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
|
||||
0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
|
||||
0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
|
||||
0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
|
||||
0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
|
||||
0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
|
||||
0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
|
||||
0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
|
||||
0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
|
||||
};
|
||||
static const unsigned char nmstrtPages[] = {
|
||||
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
|
||||
0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
|
||||
0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
static const unsigned char namePages[] = {
|
||||
0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
|
||||
0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||
0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
|
||||
0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
37
components/expat/include/expat/utf8tab.h
Normal file
37
components/expat/include/expat/utf8tab.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
|
||||
/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
|
||||
/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||
/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||
/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||
/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||
/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||
/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||
/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||
/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
|
||||
/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
|
||||
/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
|
||||
/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
|
||||
/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
|
||||
/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
|
||||
/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
|
||||
/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
|
114
components/expat/include/expat/xmlrole.h
Normal file
114
components/expat/include/expat/xmlrole.h
Normal file
@ -0,0 +1,114 @@
|
||||
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
#ifndef XmlRole_INCLUDED
|
||||
#define XmlRole_INCLUDED 1
|
||||
|
||||
#ifdef __VMS
|
||||
/* 0 1 2 3 0 1 2 3
|
||||
1234567890123456789012345678901 1234567890123456789012345678901 */
|
||||
#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt
|
||||
#endif
|
||||
|
||||
#include "xmltok.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
XML_ROLE_ERROR = -1,
|
||||
XML_ROLE_NONE = 0,
|
||||
XML_ROLE_XML_DECL,
|
||||
XML_ROLE_INSTANCE_START,
|
||||
XML_ROLE_DOCTYPE_NONE,
|
||||
XML_ROLE_DOCTYPE_NAME,
|
||||
XML_ROLE_DOCTYPE_SYSTEM_ID,
|
||||
XML_ROLE_DOCTYPE_PUBLIC_ID,
|
||||
XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
|
||||
XML_ROLE_DOCTYPE_CLOSE,
|
||||
XML_ROLE_GENERAL_ENTITY_NAME,
|
||||
XML_ROLE_PARAM_ENTITY_NAME,
|
||||
XML_ROLE_ENTITY_NONE,
|
||||
XML_ROLE_ENTITY_VALUE,
|
||||
XML_ROLE_ENTITY_SYSTEM_ID,
|
||||
XML_ROLE_ENTITY_PUBLIC_ID,
|
||||
XML_ROLE_ENTITY_COMPLETE,
|
||||
XML_ROLE_ENTITY_NOTATION_NAME,
|
||||
XML_ROLE_NOTATION_NONE,
|
||||
XML_ROLE_NOTATION_NAME,
|
||||
XML_ROLE_NOTATION_SYSTEM_ID,
|
||||
XML_ROLE_NOTATION_NO_SYSTEM_ID,
|
||||
XML_ROLE_NOTATION_PUBLIC_ID,
|
||||
XML_ROLE_ATTRIBUTE_NAME,
|
||||
XML_ROLE_ATTRIBUTE_TYPE_CDATA,
|
||||
XML_ROLE_ATTRIBUTE_TYPE_ID,
|
||||
XML_ROLE_ATTRIBUTE_TYPE_IDREF,
|
||||
XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
|
||||
XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
|
||||
XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
|
||||
XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
|
||||
XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
|
||||
XML_ROLE_ATTRIBUTE_ENUM_VALUE,
|
||||
XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
|
||||
XML_ROLE_ATTLIST_NONE,
|
||||
XML_ROLE_ATTLIST_ELEMENT_NAME,
|
||||
XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
|
||||
XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
|
||||
XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
|
||||
XML_ROLE_FIXED_ATTRIBUTE_VALUE,
|
||||
XML_ROLE_ELEMENT_NONE,
|
||||
XML_ROLE_ELEMENT_NAME,
|
||||
XML_ROLE_CONTENT_ANY,
|
||||
XML_ROLE_CONTENT_EMPTY,
|
||||
XML_ROLE_CONTENT_PCDATA,
|
||||
XML_ROLE_GROUP_OPEN,
|
||||
XML_ROLE_GROUP_CLOSE,
|
||||
XML_ROLE_GROUP_CLOSE_REP,
|
||||
XML_ROLE_GROUP_CLOSE_OPT,
|
||||
XML_ROLE_GROUP_CLOSE_PLUS,
|
||||
XML_ROLE_GROUP_CHOICE,
|
||||
XML_ROLE_GROUP_SEQUENCE,
|
||||
XML_ROLE_CONTENT_ELEMENT,
|
||||
XML_ROLE_CONTENT_ELEMENT_REP,
|
||||
XML_ROLE_CONTENT_ELEMENT_OPT,
|
||||
XML_ROLE_CONTENT_ELEMENT_PLUS,
|
||||
XML_ROLE_PI,
|
||||
XML_ROLE_COMMENT,
|
||||
#ifdef XML_DTD
|
||||
XML_ROLE_TEXT_DECL,
|
||||
XML_ROLE_IGNORE_SECT,
|
||||
XML_ROLE_INNER_PARAM_ENTITY_REF,
|
||||
#endif /* XML_DTD */
|
||||
XML_ROLE_PARAM_ENTITY_REF
|
||||
};
|
||||
|
||||
typedef struct prolog_state {
|
||||
int (PTRCALL *handler) (struct prolog_state *state,
|
||||
int tok,
|
||||
const char *ptr,
|
||||
const char *end,
|
||||
const ENCODING *enc);
|
||||
unsigned level;
|
||||
int role_none;
|
||||
#ifdef XML_DTD
|
||||
unsigned includeLevel;
|
||||
int documentEntity;
|
||||
int inEntityValue;
|
||||
#endif /* XML_DTD */
|
||||
} PROLOG_STATE;
|
||||
|
||||
void XmlPrologStateInit(PROLOG_STATE *);
|
||||
#ifdef XML_DTD
|
||||
void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
|
||||
#endif /* XML_DTD */
|
||||
|
||||
#define XmlTokenRole(state, tok, ptr, end, enc) \
|
||||
(((state)->handler)(state, tok, ptr, end, enc))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* not XmlRole_INCLUDED */
|
322
components/expat/include/expat/xmltok.h
Normal file
322
components/expat/include/expat/xmltok.h
Normal file
@ -0,0 +1,322 @@
|
||||
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
#ifndef XmlTok_INCLUDED
|
||||
#define XmlTok_INCLUDED 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The following token may be returned by XmlContentTok */
|
||||
#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
|
||||
start of illegal ]]> sequence */
|
||||
/* The following tokens may be returned by both XmlPrologTok and
|
||||
XmlContentTok.
|
||||
*/
|
||||
#define XML_TOK_NONE -4 /* The string to be scanned is empty */
|
||||
#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
|
||||
might be part of CRLF sequence */
|
||||
#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
|
||||
#define XML_TOK_PARTIAL -1 /* only part of a token */
|
||||
#define XML_TOK_INVALID 0
|
||||
|
||||
/* The following tokens are returned by XmlContentTok; some are also
|
||||
returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok.
|
||||
*/
|
||||
#define XML_TOK_START_TAG_WITH_ATTS 1
|
||||
#define XML_TOK_START_TAG_NO_ATTS 2
|
||||
#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
|
||||
#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
|
||||
#define XML_TOK_END_TAG 5
|
||||
#define XML_TOK_DATA_CHARS 6
|
||||
#define XML_TOK_DATA_NEWLINE 7
|
||||
#define XML_TOK_CDATA_SECT_OPEN 8
|
||||
#define XML_TOK_ENTITY_REF 9
|
||||
#define XML_TOK_CHAR_REF 10 /* numeric character reference */
|
||||
|
||||
/* The following tokens may be returned by both XmlPrologTok and
|
||||
XmlContentTok.
|
||||
*/
|
||||
#define XML_TOK_PI 11 /* processing instruction */
|
||||
#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
|
||||
#define XML_TOK_COMMENT 13
|
||||
#define XML_TOK_BOM 14 /* Byte order mark */
|
||||
|
||||
/* The following tokens are returned only by XmlPrologTok */
|
||||
#define XML_TOK_PROLOG_S 15
|
||||
#define XML_TOK_DECL_OPEN 16 /* <!foo */
|
||||
#define XML_TOK_DECL_CLOSE 17 /* > */
|
||||
#define XML_TOK_NAME 18
|
||||
#define XML_TOK_NMTOKEN 19
|
||||
#define XML_TOK_POUND_NAME 20 /* #name */
|
||||
#define XML_TOK_OR 21 /* | */
|
||||
#define XML_TOK_PERCENT 22
|
||||
#define XML_TOK_OPEN_PAREN 23
|
||||
#define XML_TOK_CLOSE_PAREN 24
|
||||
#define XML_TOK_OPEN_BRACKET 25
|
||||
#define XML_TOK_CLOSE_BRACKET 26
|
||||
#define XML_TOK_LITERAL 27
|
||||
#define XML_TOK_PARAM_ENTITY_REF 28
|
||||
#define XML_TOK_INSTANCE_START 29
|
||||
|
||||
/* The following occur only in element type declarations */
|
||||
#define XML_TOK_NAME_QUESTION 30 /* name? */
|
||||
#define XML_TOK_NAME_ASTERISK 31 /* name* */
|
||||
#define XML_TOK_NAME_PLUS 32 /* name+ */
|
||||
#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
|
||||
#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
|
||||
#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
|
||||
#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
|
||||
#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
|
||||
#define XML_TOK_COMMA 38
|
||||
|
||||
/* The following token is returned only by XmlAttributeValueTok */
|
||||
#define XML_TOK_ATTRIBUTE_VALUE_S 39
|
||||
|
||||
/* The following token is returned only by XmlCdataSectionTok */
|
||||
#define XML_TOK_CDATA_SECT_CLOSE 40
|
||||
|
||||
/* With namespace processing this is returned by XmlPrologTok for a
|
||||
name with a colon.
|
||||
*/
|
||||
#define XML_TOK_PREFIXED_NAME 41
|
||||
|
||||
#ifdef XML_DTD
|
||||
#define XML_TOK_IGNORE_SECT 42
|
||||
#endif /* XML_DTD */
|
||||
|
||||
#ifdef XML_DTD
|
||||
#define XML_N_STATES 4
|
||||
#else /* not XML_DTD */
|
||||
#define XML_N_STATES 3
|
||||
#endif /* not XML_DTD */
|
||||
|
||||
#define XML_PROLOG_STATE 0
|
||||
#define XML_CONTENT_STATE 1
|
||||
#define XML_CDATA_SECTION_STATE 2
|
||||
#ifdef XML_DTD
|
||||
#define XML_IGNORE_SECTION_STATE 3
|
||||
#endif /* XML_DTD */
|
||||
|
||||
#define XML_N_LITERAL_TYPES 2
|
||||
#define XML_ATTRIBUTE_VALUE_LITERAL 0
|
||||
#define XML_ENTITY_VALUE_LITERAL 1
|
||||
|
||||
/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
|
||||
#define XML_UTF8_ENCODE_MAX 4
|
||||
/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
|
||||
#define XML_UTF16_ENCODE_MAX 2
|
||||
|
||||
typedef struct position {
|
||||
/* first line and first column are 0 not 1 */
|
||||
XML_Size lineNumber;
|
||||
XML_Size columnNumber;
|
||||
} POSITION;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *valuePtr;
|
||||
const char *valueEnd;
|
||||
char normalized;
|
||||
} ATTRIBUTE;
|
||||
|
||||
struct encoding;
|
||||
typedef struct encoding ENCODING;
|
||||
|
||||
typedef int (PTRCALL *SCANNER)(const ENCODING *,
|
||||
const char *,
|
||||
const char *,
|
||||
const char **);
|
||||
|
||||
enum XML_Convert_Result {
|
||||
XML_CONVERT_COMPLETED = 0,
|
||||
XML_CONVERT_INPUT_INCOMPLETE = 1,
|
||||
XML_CONVERT_OUTPUT_EXHAUSTED = 2 /* and therefore potentially input remaining as well */
|
||||
};
|
||||
|
||||
struct encoding {
|
||||
SCANNER scanners[XML_N_STATES];
|
||||
SCANNER literalScanners[XML_N_LITERAL_TYPES];
|
||||
int (PTRCALL *sameName)(const ENCODING *,
|
||||
const char *,
|
||||
const char *);
|
||||
int (PTRCALL *nameMatchesAscii)(const ENCODING *,
|
||||
const char *,
|
||||
const char *,
|
||||
const char *);
|
||||
int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
|
||||
const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
|
||||
int (PTRCALL *getAtts)(const ENCODING *enc,
|
||||
const char *ptr,
|
||||
int attsMax,
|
||||
ATTRIBUTE *atts);
|
||||
int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
|
||||
int (PTRCALL *predefinedEntityName)(const ENCODING *,
|
||||
const char *,
|
||||
const char *);
|
||||
void (PTRCALL *updatePosition)(const ENCODING *,
|
||||
const char *ptr,
|
||||
const char *end,
|
||||
POSITION *);
|
||||
int (PTRCALL *isPublicId)(const ENCODING *enc,
|
||||
const char *ptr,
|
||||
const char *end,
|
||||
const char **badPtr);
|
||||
enum XML_Convert_Result (PTRCALL *utf8Convert)(const ENCODING *enc,
|
||||
const char **fromP,
|
||||
const char *fromLim,
|
||||
char **toP,
|
||||
const char *toLim);
|
||||
enum XML_Convert_Result (PTRCALL *utf16Convert)(const ENCODING *enc,
|
||||
const char **fromP,
|
||||
const char *fromLim,
|
||||
unsigned short **toP,
|
||||
const unsigned short *toLim);
|
||||
int minBytesPerChar;
|
||||
char isUtf8;
|
||||
char isUtf16;
|
||||
};
|
||||
|
||||
/* Scan the string starting at ptr until the end of the next complete
|
||||
token, but do not scan past eptr. Return an integer giving the
|
||||
type of token.
|
||||
|
||||
Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
|
||||
|
||||
Return XML_TOK_PARTIAL when the string does not contain a complete
|
||||
token; nextTokPtr will not be set.
|
||||
|
||||
Return XML_TOK_INVALID when the string does not start a valid
|
||||
token; nextTokPtr will be set to point to the character which made
|
||||
the token invalid.
|
||||
|
||||
Otherwise the string starts with a valid token; nextTokPtr will be
|
||||
set to point to the character following the end of that token.
|
||||
|
||||
Each data character counts as a single token, but adjacent data
|
||||
characters may be returned together. Similarly for characters in
|
||||
the prolog outside literals, comments and processing instructions.
|
||||
*/
|
||||
|
||||
|
||||
#define XmlTok(enc, state, ptr, end, nextTokPtr) \
|
||||
(((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
|
||||
|
||||
#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
|
||||
XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
|
||||
|
||||
#define XmlContentTok(enc, ptr, end, nextTokPtr) \
|
||||
XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
|
||||
|
||||
#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
|
||||
XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
|
||||
|
||||
#ifdef XML_DTD
|
||||
|
||||
#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
|
||||
XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
|
||||
|
||||
#endif /* XML_DTD */
|
||||
|
||||
/* This is used for performing a 2nd-level tokenization on the content
|
||||
of a literal that has already been returned by XmlTok.
|
||||
*/
|
||||
#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
|
||||
(((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
|
||||
|
||||
#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
|
||||
XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
|
||||
|
||||
#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
|
||||
XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
|
||||
|
||||
#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
|
||||
|
||||
#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
|
||||
(((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
|
||||
|
||||
#define XmlNameLength(enc, ptr) \
|
||||
(((enc)->nameLength)(enc, ptr))
|
||||
|
||||
#define XmlSkipS(enc, ptr) \
|
||||
(((enc)->skipS)(enc, ptr))
|
||||
|
||||
#define XmlGetAttributes(enc, ptr, attsMax, atts) \
|
||||
(((enc)->getAtts)(enc, ptr, attsMax, atts))
|
||||
|
||||
#define XmlCharRefNumber(enc, ptr) \
|
||||
(((enc)->charRefNumber)(enc, ptr))
|
||||
|
||||
#define XmlPredefinedEntityName(enc, ptr, end) \
|
||||
(((enc)->predefinedEntityName)(enc, ptr, end))
|
||||
|
||||
#define XmlUpdatePosition(enc, ptr, end, pos) \
|
||||
(((enc)->updatePosition)(enc, ptr, end, pos))
|
||||
|
||||
#define XmlIsPublicId(enc, ptr, end, badPtr) \
|
||||
(((enc)->isPublicId)(enc, ptr, end, badPtr))
|
||||
|
||||
#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
|
||||
(((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
|
||||
|
||||
#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
|
||||
(((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
|
||||
|
||||
typedef struct {
|
||||
ENCODING initEnc;
|
||||
const ENCODING **encPtr;
|
||||
} INIT_ENCODING;
|
||||
|
||||
int XmlParseXmlDecl(int isGeneralTextEntity,
|
||||
const ENCODING *enc,
|
||||
const char *ptr,
|
||||
const char *end,
|
||||
const char **badPtr,
|
||||
const char **versionPtr,
|
||||
const char **versionEndPtr,
|
||||
const char **encodingNamePtr,
|
||||
const ENCODING **namedEncodingPtr,
|
||||
int *standalonePtr);
|
||||
|
||||
int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
|
||||
const ENCODING *XmlGetUtf8InternalEncoding(void);
|
||||
const ENCODING *XmlGetUtf16InternalEncoding(void);
|
||||
int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
|
||||
int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
|
||||
int XmlSizeOfUnknownEncoding(void);
|
||||
|
||||
|
||||
typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
|
||||
|
||||
ENCODING *
|
||||
XmlInitUnknownEncoding(void *mem,
|
||||
int *table,
|
||||
CONVERTER convert,
|
||||
void *userData);
|
||||
|
||||
int XmlParseXmlDeclNS(int isGeneralTextEntity,
|
||||
const ENCODING *enc,
|
||||
const char *ptr,
|
||||
const char *end,
|
||||
const char **badPtr,
|
||||
const char **versionPtr,
|
||||
const char **versionEndPtr,
|
||||
const char **encodingNamePtr,
|
||||
const ENCODING **namedEncodingPtr,
|
||||
int *standalonePtr);
|
||||
|
||||
int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
|
||||
const ENCODING *XmlGetUtf8InternalEncodingNS(void);
|
||||
const ENCODING *XmlGetUtf16InternalEncodingNS(void);
|
||||
ENCODING *
|
||||
XmlInitUnknownEncodingNS(void *mem,
|
||||
int *table,
|
||||
CONVERTER convert,
|
||||
void *userData);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* not XmlTok_INCLUDED */
|
46
components/expat/include/expat/xmltok_impl.h
Normal file
46
components/expat/include/expat/xmltok_impl.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
enum {
|
||||
BT_NONXML,
|
||||
BT_MALFORM,
|
||||
BT_LT,
|
||||
BT_AMP,
|
||||
BT_RSQB,
|
||||
BT_LEAD2,
|
||||
BT_LEAD3,
|
||||
BT_LEAD4,
|
||||
BT_TRAIL,
|
||||
BT_CR,
|
||||
BT_LF,
|
||||
BT_GT,
|
||||
BT_QUOT,
|
||||
BT_APOS,
|
||||
BT_EQUALS,
|
||||
BT_QUEST,
|
||||
BT_EXCL,
|
||||
BT_SOL,
|
||||
BT_SEMI,
|
||||
BT_NUM,
|
||||
BT_LSQB,
|
||||
BT_S,
|
||||
BT_NMSTRT,
|
||||
BT_COLON,
|
||||
BT_HEX,
|
||||
BT_DIGIT,
|
||||
BT_NAME,
|
||||
BT_MINUS,
|
||||
BT_OTHER, /* known not to be a name or name start character */
|
||||
BT_NONASCII, /* might be a name or name start character */
|
||||
BT_PERCNT,
|
||||
BT_LPAR,
|
||||
BT_RPAR,
|
||||
BT_AST,
|
||||
BT_PLUS,
|
||||
BT_COMMA,
|
||||
BT_VERBAR
|
||||
};
|
||||
|
||||
#include <stddef.h>
|
6475
components/expat/library/xmlparse.c
Normal file
6475
components/expat/library/xmlparse.c
Normal file
File diff suppressed because it is too large
Load Diff
1336
components/expat/library/xmlrole.c
Normal file
1336
components/expat/library/xmlrole.c
Normal file
File diff suppressed because it is too large
Load Diff
1753
components/expat/library/xmltok.c
Normal file
1753
components/expat/library/xmltok.c
Normal file
File diff suppressed because it is too large
Load Diff
1779
components/expat/library/xmltok_impl.c
Normal file
1779
components/expat/library/xmltok_impl.c
Normal file
File diff suppressed because it is too large
Load Diff
115
components/expat/library/xmltok_ns.c
Normal file
115
components/expat/library/xmltok_ns.c
Normal file
@ -0,0 +1,115 @@
|
||||
/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
*/
|
||||
|
||||
/* This file is included! */
|
||||
#ifdef XML_TOK_NS_C
|
||||
|
||||
const ENCODING *
|
||||
NS(XmlGetUtf8InternalEncoding)(void)
|
||||
{
|
||||
return &ns(internal_utf8_encoding).enc;
|
||||
}
|
||||
|
||||
const ENCODING *
|
||||
NS(XmlGetUtf16InternalEncoding)(void)
|
||||
{
|
||||
#if BYTEORDER == 1234
|
||||
return &ns(internal_little2_encoding).enc;
|
||||
#elif BYTEORDER == 4321
|
||||
return &ns(internal_big2_encoding).enc;
|
||||
#else
|
||||
const short n = 1;
|
||||
return (*(const char *)&n
|
||||
? &ns(internal_little2_encoding).enc
|
||||
: &ns(internal_big2_encoding).enc);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const ENCODING * const NS(encodings)[] = {
|
||||
&ns(latin1_encoding).enc,
|
||||
&ns(ascii_encoding).enc,
|
||||
&ns(utf8_encoding).enc,
|
||||
&ns(big2_encoding).enc,
|
||||
&ns(big2_encoding).enc,
|
||||
&ns(little2_encoding).enc,
|
||||
&ns(utf8_encoding).enc /* NO_ENC */
|
||||
};
|
||||
|
||||
static int PTRCALL
|
||||
NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
|
||||
const char **nextTokPtr)
|
||||
{
|
||||
return initScan(NS(encodings), (const INIT_ENCODING *)enc,
|
||||
XML_PROLOG_STATE, ptr, end, nextTokPtr);
|
||||
}
|
||||
|
||||
static int PTRCALL
|
||||
NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
|
||||
const char **nextTokPtr)
|
||||
{
|
||||
return initScan(NS(encodings), (const INIT_ENCODING *)enc,
|
||||
XML_CONTENT_STATE, ptr, end, nextTokPtr);
|
||||
}
|
||||
|
||||
int
|
||||
NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
|
||||
const char *name)
|
||||
{
|
||||
int i = getEncodingIndex(name);
|
||||
if (i == UNKNOWN_ENC)
|
||||
return 0;
|
||||
SET_INIT_ENC_INDEX(p, i);
|
||||
p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
|
||||
p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
|
||||
p->initEnc.updatePosition = initUpdatePosition;
|
||||
p->encPtr = encPtr;
|
||||
*encPtr = &(p->initEnc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const ENCODING *
|
||||
NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
|
||||
{
|
||||
#define ENCODING_MAX 128
|
||||
char buf[ENCODING_MAX];
|
||||
char *p = buf;
|
||||
int i;
|
||||
XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
|
||||
if (ptr != end)
|
||||
return 0;
|
||||
*p = 0;
|
||||
if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
|
||||
return enc;
|
||||
i = getEncodingIndex(buf);
|
||||
if (i == UNKNOWN_ENC)
|
||||
return 0;
|
||||
return NS(encodings)[i];
|
||||
}
|
||||
|
||||
int
|
||||
NS(XmlParseXmlDecl)(int isGeneralTextEntity,
|
||||
const ENCODING *enc,
|
||||
const char *ptr,
|
||||
const char *end,
|
||||
const char **badPtr,
|
||||
const char **versionPtr,
|
||||
const char **versionEndPtr,
|
||||
const char **encodingName,
|
||||
const ENCODING **encoding,
|
||||
int *standalone)
|
||||
{
|
||||
return doParseXmlDecl(NS(findEncoding),
|
||||
isGeneralTextEntity,
|
||||
enc,
|
||||
ptr,
|
||||
end,
|
||||
badPtr,
|
||||
versionPtr,
|
||||
versionEndPtr,
|
||||
encodingName,
|
||||
encoding,
|
||||
standalone);
|
||||
}
|
||||
|
||||
#endif /* XML_TOK_NS_C */
|
127
components/expat/port/chardata.c
Normal file
127
components/expat/port/chardata.c
Normal file
@ -0,0 +1,127 @@
|
||||
/* Copyright (c) 1998-2003 Thai Open Source Software Center Ltd
|
||||
See the file COPYING for copying permission.
|
||||
|
||||
chardata.c
|
||||
*/
|
||||
|
||||
#ifdef HAVE_EXPAT_CONFIG_H
|
||||
#include <expat_config.h>
|
||||
#endif
|
||||
#include "minicheck.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chardata.h"
|
||||
|
||||
|
||||
static int
|
||||
xmlstrlen(const XML_Char *s)
|
||||
{
|
||||
int len = 0;
|
||||
assert(s != NULL);
|
||||
while (s[len] != 0)
|
||||
++len;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CharData_Init(CharData *storage)
|
||||
{
|
||||
assert(storage != NULL);
|
||||
storage->count = -1;
|
||||
}
|
||||
|
||||
void
|
||||
CharData_AppendString(CharData *storage, const char *s)
|
||||
{
|
||||
int maxchars = sizeof(storage->data) / sizeof(storage->data[0]);
|
||||
int len;
|
||||
|
||||
assert(s != NULL);
|
||||
len = strlen(s);
|
||||
if (storage->count < 0)
|
||||
storage->count = 0;
|
||||
if ((len + storage->count) > maxchars) {
|
||||
len = (maxchars - storage->count);
|
||||
}
|
||||
if (len + storage->count < (int)sizeof(storage->data)) {
|
||||
memcpy(storage->data + storage->count, s, len);
|
||||
storage->count += len;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len)
|
||||
{
|
||||
int maxchars;
|
||||
|
||||
assert(storage != NULL);
|
||||
assert(s != NULL);
|
||||
maxchars = sizeof(storage->data) / sizeof(storage->data[0]);
|
||||
if (storage->count < 0)
|
||||
storage->count = 0;
|
||||
if (len < 0)
|
||||
len = xmlstrlen(s);
|
||||
if ((len + storage->count) > maxchars) {
|
||||
len = (maxchars - storage->count);
|
||||
}
|
||||
if (len + storage->count < (int)sizeof(storage->data)) {
|
||||
memcpy(storage->data + storage->count, s,
|
||||
len * sizeof(storage->data[0]));
|
||||
storage->count += len;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CharData_CheckString(CharData *storage, const char *expected)
|
||||
{
|
||||
char buffer[1280];
|
||||
int len;
|
||||
int count;
|
||||
|
||||
assert(storage != NULL);
|
||||
assert(expected != NULL);
|
||||
count = (storage->count < 0) ? 0 : storage->count;
|
||||
len = strlen(expected);
|
||||
if (len != count) {
|
||||
if (sizeof(XML_Char) == 1)
|
||||
sprintf(buffer, "wrong number of data characters:"
|
||||
" got %d, expected %d:\n%s", count, len, storage->data);
|
||||
else
|
||||
sprintf(buffer,
|
||||
"wrong number of data characters: got %d, expected %d",
|
||||
count, len);
|
||||
fail(buffer);
|
||||
return 0;
|
||||
}
|
||||
if (memcmp(expected, storage->data, len) != 0) {
|
||||
fail("got bad data bytes");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
CharData_CheckXMLChars(CharData *storage, const XML_Char *expected)
|
||||
{
|
||||
char buffer[1024];
|
||||
int len = xmlstrlen(expected);
|
||||
int count;
|
||||
|
||||
assert(storage != NULL);
|
||||
count = (storage->count < 0) ? 0 : storage->count;
|
||||
if (len != count) {
|
||||
sprintf(buffer, "wrong number of data characters: got %d, expected %d",
|
||||
count, len);
|
||||
fail(buffer);
|
||||
return 0;
|
||||
}
|
||||
if (memcmp(expected, storage->data, len * sizeof(storage->data[0])) != 0) {
|
||||
fail("got bad data bytes");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
66
components/expat/port/expat_element.c
Normal file
66
components/expat/port/expat_element.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* This is simple demonstration of how to use expat. This program
|
||||
reads an XML document from standard input and writes a line with
|
||||
the name of each element to standard output indenting child
|
||||
elements by one tab stop more than their parent element.
|
||||
It must be used with Expat compiled for UTF-8 output.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "expat.h"
|
||||
|
||||
#define XML_FMT_INT_MOD "l"
|
||||
|
||||
static void XMLCALL
|
||||
startElement(void *userData, const char *name, const char **atts)
|
||||
{
|
||||
int i;
|
||||
int *depthPtr = (int *)userData;
|
||||
(void)atts;
|
||||
|
||||
for (i = 0; i < *depthPtr; i++)
|
||||
putchar('\t');
|
||||
puts(name);
|
||||
*depthPtr += 1;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
endElement(void *userData, const char *name)
|
||||
{
|
||||
int *depthPtr = (int *)userData;
|
||||
(void)name;
|
||||
|
||||
*depthPtr -= 1;
|
||||
}
|
||||
|
||||
int xml_main(int argc, const char *argv)
|
||||
{
|
||||
char *buf = NULL;
|
||||
int depth = 0;
|
||||
if (argv == NULL){
|
||||
printf("no element parse\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
if (parser){
|
||||
XML_SetUserData(parser, &depth);
|
||||
XML_SetElementHandler(parser, startElement, endElement);
|
||||
buf = (char*)malloc(argc + 1);
|
||||
bzero(buf, argc + 1);
|
||||
memcpy(buf, argv, argc);
|
||||
if (XML_Parse(parser, buf, argc, 0) == XML_STATUS_ERROR) {
|
||||
printf( "%s at line %" XML_FMT_INT_MOD "u\n",
|
||||
XML_ErrorString(XML_GetErrorCode(parser)),
|
||||
XML_GetCurrentLineNumber(parser));
|
||||
}else{
|
||||
printf("XML_Parse Sucessful\n ");
|
||||
}
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
return 0;
|
||||
}
|
||||
|
40
components/expat/port/include/chardata.h
Normal file
40
components/expat/port/include/chardata.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* chardata.h
|
||||
|
||||
Interface to some helper routines used to accumulate and check text
|
||||
and attribute content.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef XML_CHARDATA_H
|
||||
#define XML_CHARDATA_H 1
|
||||
|
||||
#ifndef XML_VERSION
|
||||
#include "expat.h" /* need XML_Char */
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
int count; /* # of chars, < 0 if not set */
|
||||
XML_Char data[1024];
|
||||
} CharData;
|
||||
|
||||
|
||||
void CharData_Init(CharData *storage);
|
||||
|
||||
void CharData_AppendString(CharData *storage, const char *s);
|
||||
|
||||
void CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len);
|
||||
|
||||
int CharData_CheckString(CharData *storage, const char *s);
|
||||
|
||||
int CharData_CheckXMLChars(CharData *storage, const XML_Char *s);
|
||||
|
||||
|
||||
#endif /* XML_CHARDATA_H */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
95
components/expat/port/include/minicheck.h
Normal file
95
components/expat/port/include/minicheck.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* Miniature re-implementation of the "check" library.
|
||||
*
|
||||
* This is intended to support just enough of check to run the Expat
|
||||
* tests. This interface is based entirely on the portion of the
|
||||
* check library being used.
|
||||
*
|
||||
* This is *source* compatible, but not necessary *link* compatible.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CK_NOFORK 0
|
||||
#define CK_FORK 1
|
||||
|
||||
#define CK_SILENT 0
|
||||
#define CK_NORMAL 1
|
||||
#define CK_VERBOSE 2
|
||||
|
||||
/* Workaround for Microsoft's compiler and Tru64 Unix systems where the
|
||||
C compiler has a working __func__, but the C++ compiler only has a
|
||||
working __FUNCTION__. This could be fixed in configure.in, but it's
|
||||
not worth it right now. */
|
||||
#if defined (_MSC_VER) || (defined(__osf__) && defined(__cplusplus))
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
/* ISO C90 does not support '__func__' predefined identifier */
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901)
|
||||
# define __func__ "(unknown)"
|
||||
#endif
|
||||
|
||||
#define START_TEST(testname) static void testname(void) { \
|
||||
_check_set_test_info(__func__, __FILE__, __LINE__); \
|
||||
{
|
||||
#define END_TEST
|
||||
|
||||
#define fail(msg) _fail_unless(0, __FILE__, __LINE__, msg)
|
||||
|
||||
typedef void (*tcase_setup_function)(void);
|
||||
typedef void (*tcase_teardown_function)(void);
|
||||
typedef void (*tcase_test_function)(void);
|
||||
|
||||
typedef struct SRunner SRunner;
|
||||
typedef struct Suite Suite;
|
||||
typedef struct TCase TCase;
|
||||
|
||||
struct SRunner {
|
||||
Suite *suite;
|
||||
int nchecks;
|
||||
int nfailures;
|
||||
};
|
||||
|
||||
struct Suite {
|
||||
const char *name;
|
||||
TCase *tests;
|
||||
};
|
||||
|
||||
struct TCase {
|
||||
const char *name;
|
||||
tcase_setup_function setup;
|
||||
tcase_teardown_function teardown;
|
||||
tcase_test_function *tests;
|
||||
int ntests;
|
||||
int allocated;
|
||||
TCase *next_tcase;
|
||||
};
|
||||
|
||||
|
||||
/* Internal helper. */
|
||||
void _check_set_test_info(char const *function,
|
||||
char const *filename, int lineno);
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes for the actual implementation.
|
||||
*/
|
||||
|
||||
void _fail_unless(int condition, const char *file, int line, const char *msg);
|
||||
Suite *suite_create(const char *name);
|
||||
TCase *tcase_create(const char *name);
|
||||
void suite_add_tcase(Suite *suite, TCase *tc);
|
||||
void tcase_add_checked_fixture(TCase *,
|
||||
tcase_setup_function,
|
||||
tcase_teardown_function);
|
||||
void tcase_add_test(TCase *tc, tcase_test_function test);
|
||||
SRunner *srunner_create(Suite *suite);
|
||||
void srunner_run_all(SRunner *runner, int verbosity);
|
||||
int srunner_ntests_failed(SRunner *runner);
|
||||
void srunner_free(SRunner *runner);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
183
components/expat/port/minicheck.c
Normal file
183
components/expat/port/minicheck.c
Normal file
@ -0,0 +1,183 @@
|
||||
/* Miniature re-implementation of the "check" library.
|
||||
*
|
||||
* This is intended to support just enough of check to run the Expat
|
||||
* tests. This interface is based entirely on the portion of the
|
||||
* check library being used.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "internal.h" /* for UNUSED_P only */
|
||||
#include "minicheck.h"
|
||||
|
||||
Suite *
|
||||
suite_create(const char *name)
|
||||
{
|
||||
Suite *suite = (Suite *) calloc(1, sizeof(Suite));
|
||||
if (suite != NULL) {
|
||||
suite->name = name;
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
TCase *
|
||||
tcase_create(const char *name)
|
||||
{
|
||||
TCase *tc = (TCase *) calloc(1, sizeof(TCase));
|
||||
if (tc != NULL) {
|
||||
tc->name = name;
|
||||
}
|
||||
return tc;
|
||||
}
|
||||
|
||||
void
|
||||
suite_add_tcase(Suite *suite, TCase *tc)
|
||||
{
|
||||
assert(suite != NULL);
|
||||
assert(tc != NULL);
|
||||
assert(tc->next_tcase == NULL);
|
||||
|
||||
tc->next_tcase = suite->tests;
|
||||
suite->tests = tc;
|
||||
}
|
||||
|
||||
void
|
||||
tcase_add_checked_fixture(TCase *tc,
|
||||
tcase_setup_function setup,
|
||||
tcase_teardown_function teardown)
|
||||
{
|
||||
assert(tc != NULL);
|
||||
tc->setup = setup;
|
||||
tc->teardown = teardown;
|
||||
}
|
||||
|
||||
void
|
||||
tcase_add_test(TCase *tc, tcase_test_function test)
|
||||
{
|
||||
assert(tc != NULL);
|
||||
if (tc->allocated == tc->ntests) {
|
||||
int nalloc = tc->allocated + 100;
|
||||
size_t new_size = sizeof(tcase_test_function) * nalloc;
|
||||
tcase_test_function *new_tests = realloc(tc->tests, new_size);
|
||||
assert(new_tests != NULL);
|
||||
if (new_tests != tc->tests) {
|
||||
free(tc->tests);
|
||||
tc->tests = new_tests;
|
||||
}
|
||||
tc->allocated = nalloc;
|
||||
}
|
||||
tc->tests[tc->ntests] = test;
|
||||
tc->ntests++;
|
||||
}
|
||||
|
||||
SRunner *
|
||||
srunner_create(Suite *suite)
|
||||
{
|
||||
SRunner *runner = calloc(1, sizeof(SRunner));
|
||||
if (runner != NULL) {
|
||||
runner->suite = suite;
|
||||
}
|
||||
return runner;
|
||||
}
|
||||
|
||||
static jmp_buf env;
|
||||
|
||||
static char const *_check_current_function = NULL;
|
||||
static int _check_current_lineno = -1;
|
||||
static char const *_check_current_filename = NULL;
|
||||
|
||||
void
|
||||
_check_set_test_info(char const *function, char const *filename, int lineno)
|
||||
{
|
||||
_check_current_function = function;
|
||||
_check_current_lineno = lineno;
|
||||
_check_current_filename = filename;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_failure(SRunner *runner, int verbosity)
|
||||
{
|
||||
runner->nfailures++;
|
||||
if (verbosity >= CK_VERBOSE) {
|
||||
printf("%s:%d: %s\n", _check_current_filename,
|
||||
_check_current_lineno, _check_current_function);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
srunner_run_all(SRunner *runner, int verbosity)
|
||||
{
|
||||
Suite *suite;
|
||||
TCase *tc;
|
||||
assert(runner != NULL);
|
||||
suite = runner->suite;
|
||||
tc = suite->tests;
|
||||
while (tc != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < tc->ntests; ++i) {
|
||||
runner->nchecks++;
|
||||
|
||||
if (tc->setup != NULL) {
|
||||
/* setup */
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
continue;
|
||||
}
|
||||
tc->setup();
|
||||
}
|
||||
/* test */
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
continue;
|
||||
}
|
||||
(tc->tests[i])();
|
||||
|
||||
/* teardown */
|
||||
if (tc->teardown != NULL) {
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
continue;
|
||||
}
|
||||
tc->teardown();
|
||||
}
|
||||
}
|
||||
tc = tc->next_tcase;
|
||||
}
|
||||
if (verbosity) {
|
||||
int passed = runner->nchecks - runner->nfailures;
|
||||
double percentage = ((double) passed) / runner->nchecks;
|
||||
int display = (int) (percentage * 100);
|
||||
printf("%d%%: Checks: %d, Failed: %d\n",
|
||||
display, runner->nchecks, runner->nfailures);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_fail_unless(int UNUSED_P(condition), const char *UNUSED_P(file), int UNUSED_P(line), const char *msg)
|
||||
{
|
||||
/* Always print the error message so it isn't lost. In this case,
|
||||
we have a failure, so there's no reason to be quiet about what
|
||||
it is.
|
||||
*/
|
||||
if (msg != NULL)
|
||||
printf("%s", msg);
|
||||
longjmp(env, 1);
|
||||
}
|
||||
|
||||
int
|
||||
srunner_ntests_failed(SRunner *runner)
|
||||
{
|
||||
assert(runner != NULL);
|
||||
return runner->nfailures;
|
||||
}
|
||||
|
||||
void
|
||||
srunner_free(SRunner *runner)
|
||||
{
|
||||
free(runner->suite);
|
||||
free(runner);
|
||||
}
|
23
components/freertos/FreeRTOS-openocd.c
Normal file
23
components/freertos/FreeRTOS-openocd.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer
|
||||
* present in the kernel, so it has to be supplied by other means for
|
||||
* OpenOCD's threads awareness.
|
||||
*
|
||||
* Add this file to your project, and, if you're using --gc-sections,
|
||||
* ``--undefined=uxTopUsedPriority'' (or
|
||||
* ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final
|
||||
* linking) to your LDFLAGS; same with all the other symbols you need.
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define USED __attribute__((used))
|
||||
#else
|
||||
#define USED
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FREERTOS_DEBUG_OCDAWARE
|
||||
const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1;
|
||||
#endif
|
@ -75,13 +75,16 @@ endchoice
|
||||
|
||||
config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
|
||||
int "Amount of thread local storage pointers"
|
||||
range 0 256
|
||||
default 0
|
||||
range 0 256 if !WIFI_ENABLED
|
||||
range 1 256 if WIFI_ENABLED
|
||||
default 1
|
||||
help
|
||||
FreeRTOS has the ability to store per-thread pointers in the task
|
||||
control block. This controls the amount of pointers available;
|
||||
0 turns off this functionality.
|
||||
|
||||
If using the WiFi stack, this value must be at least 1.
|
||||
|
||||
#This still needs to be implemented.
|
||||
choice FREERTOS_PANIC
|
||||
prompt "Panic handler behaviour"
|
||||
@ -121,5 +124,71 @@ config FREERTOS_DEBUG_OCDAWARE
|
||||
The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
|
||||
instead of panicking, have the debugger stop on the offending instruction.
|
||||
|
||||
choice FREERTOS_ASSERT
|
||||
prompt "FreeRTOS assertions"
|
||||
default FREERTOS_ASSERT_FAIL_ABORT
|
||||
help
|
||||
Failed FreeRTOS configASSERT() assertions can be configured to
|
||||
behave in different ways.
|
||||
|
||||
config FREERTOS_ASSERT_FAIL_ABORT
|
||||
bool "abort() on failed assertions"
|
||||
help
|
||||
If a FreeRTOS configASSERT() fails, FreeRTOS will abort() and
|
||||
halt execution. The panic handler can be configured to handle
|
||||
the outcome of an abort() in different ways.
|
||||
|
||||
config FREERTOS_ASSERT_FAIL_PRINT_CONTINUE
|
||||
bool "Print and continue failed assertions"
|
||||
help
|
||||
If a FreeRTOS assertion fails, print it out and continue.
|
||||
|
||||
config FREERTOS_ASSERT_DISABLE
|
||||
bool "Disable FreeRTOS assertions"
|
||||
help
|
||||
FreeRTOS configASSERT() will not be compiled into the binary.
|
||||
|
||||
endchoice
|
||||
|
||||
config FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
||||
bool "Stop program on scheduler start when JTAG/OCD is detected"
|
||||
depends on FREERTOS_DEBUG_OCDAWARE
|
||||
default y
|
||||
help
|
||||
If JTAG/OCD is connected, stop execution when the scheduler is started and the first
|
||||
task is executed.
|
||||
|
||||
menuconfig ENABLE_MEMORY_DEBUG
|
||||
bool "Enable heap memory debug"
|
||||
default n
|
||||
help
|
||||
Enable this option to show malloc heap block and memory crash detect
|
||||
|
||||
menuconfig FREERTOS_DEBUG_INTERNALS
|
||||
bool "Debug FreeRTOS internals"
|
||||
default n
|
||||
help
|
||||
Enable this option to show the menu with internal FreeRTOS debugging features.
|
||||
This option does not change any code by itself, it just shows/hides some options.
|
||||
|
||||
if FREERTOS_DEBUG_INTERNALS
|
||||
|
||||
config FREERTOS_PORTMUX_DEBUG
|
||||
bool "Debug portMUX portENTER_CRITICAL/portEXIT_CRITICAL"
|
||||
depends on FREERTOS_DEBUG_INTERNALS
|
||||
default n
|
||||
help
|
||||
If enabled, debug information (including integrity checks) will be printed
|
||||
to UART for the port-specific MUX implementation.
|
||||
|
||||
config FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
||||
bool "Debug portMUX Recursion"
|
||||
depends on FREERTOS_PORTMUX_DEBUG
|
||||
default n
|
||||
help
|
||||
If enabled, additional debug information will be printed for recursive
|
||||
portMUX usage.
|
||||
|
||||
endif # FREERTOS_DEBUG_INTERNALS
|
||||
|
||||
endmenu
|
||||
|
@ -1,8 +0,0 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include/freertos
|
||||
|
||||
include $(IDF_PATH)/make/component.mk
|
9
components/freertos/component.mk
Normal file
9
components/freertos/component.mk
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) -Wl,--undefined=uxTopUsedPriority
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include/freertos
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
@ -132,6 +132,7 @@ task.h is included from an application file. */
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "heap_regions_debug.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
@ -171,7 +172,7 @@ static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );
|
||||
|
||||
/* The size of the structure placed at the beginning of each allocated memory
|
||||
block must by correctly byte aligned. */
|
||||
static const uint32_t uxHeapStructSize = ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
|
||||
static const uint32_t uxHeapStructSize = ( ( sizeof ( BlockLink_t ) + BLOCK_HEAD_LEN + BLOCK_TAIL_LEN + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
|
||||
|
||||
/* Create a couple of list links to mark the start and end of the list. */
|
||||
static BlockLink_t xStart, *pxEnd = NULL;
|
||||
@ -238,6 +239,13 @@ void *pvReturn = NULL;
|
||||
while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) )
|
||||
{
|
||||
// ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock);
|
||||
|
||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||
{
|
||||
mem_check_block(pxBlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
pxPreviousBlock = pxBlock;
|
||||
pxBlock = pxBlock->pxNextFreeBlock;
|
||||
}
|
||||
@ -248,7 +256,7 @@ void *pvReturn = NULL;
|
||||
{
|
||||
/* Return the memory space pointed to - jumping over the
|
||||
BlockLink_t structure at its start. */
|
||||
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize );
|
||||
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN);
|
||||
|
||||
/* This block is being returned for use so must be taken out
|
||||
of the list of free blocks. */
|
||||
@ -256,13 +264,14 @@ void *pvReturn = NULL;
|
||||
|
||||
/* If the block is larger than required it can be split into
|
||||
two. */
|
||||
|
||||
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||
{
|
||||
/* This block is to be split into two. Create a new
|
||||
block following the number of bytes requested. The void
|
||||
cast is used to prevent byte alignment warnings from the
|
||||
compiler. */
|
||||
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
|
||||
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize);
|
||||
|
||||
/* Calculate the sizes of two blocks split from the
|
||||
single block. */
|
||||
@ -270,6 +279,13 @@ void *pvReturn = NULL;
|
||||
pxNewBlockLink->xTag = tag;
|
||||
pxBlock->xBlockSize = xWantedSize;
|
||||
|
||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||
{
|
||||
mem_init_dog(pxNewBlockLink);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Insert the new block into the list of free blocks. */
|
||||
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
|
||||
}
|
||||
@ -293,6 +309,13 @@ void *pvReturn = NULL;
|
||||
by the application and has no "next" block. */
|
||||
pxBlock->xBlockSize |= xBlockAllocatedBit;
|
||||
pxBlock->pxNextFreeBlock = NULL;
|
||||
|
||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||
{
|
||||
mem_init_dog(pxBlock);
|
||||
mem_malloc_block(pxBlock);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -340,11 +363,20 @@ BlockLink_t *pxLink;
|
||||
{
|
||||
/* The memory being freed will have an BlockLink_t structure immediately
|
||||
before it. */
|
||||
puc -= uxHeapStructSize;
|
||||
puc -= (uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN) ;
|
||||
|
||||
/* This casting is to keep the compiler from issuing warnings. */
|
||||
pxLink = ( void * ) puc;
|
||||
|
||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||
{
|
||||
taskENTER_CRITICAL(&xMallocMutex);
|
||||
mem_check_block(pxLink);
|
||||
mem_free_block(pxLink);
|
||||
taskEXIT_CRITICAL(&xMallocMutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check the block is actually allocated. */
|
||||
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
|
||||
configASSERT( pxLink->pxNextFreeBlock == NULL );
|
||||
@ -497,7 +529,7 @@ const HeapRegionTagged_t *pxHeapRegion;
|
||||
{
|
||||
/* xStart is used to hold a pointer to the first item in the list of
|
||||
free blocks. The void cast is used to prevent compiler warnings. */
|
||||
xStart.pxNextFreeBlock = ( BlockLink_t * ) pucAlignedHeap;
|
||||
xStart.pxNextFreeBlock = ( BlockLink_t * ) (pucAlignedHeap + BLOCK_HEAD_LEN);
|
||||
xStart.xBlockSize = ( size_t ) 0;
|
||||
}
|
||||
else
|
||||
@ -519,7 +551,7 @@ const HeapRegionTagged_t *pxHeapRegion;
|
||||
ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalRegionSize;
|
||||
ulAddress -= uxHeapStructSize;
|
||||
ulAddress &= ~portBYTE_ALIGNMENT_MASK;
|
||||
pxEnd = ( BlockLink_t * ) ulAddress;
|
||||
pxEnd = ( BlockLink_t * ) (ulAddress + BLOCK_HEAD_LEN);
|
||||
pxEnd->xBlockSize = 0;
|
||||
pxEnd->pxNextFreeBlock = NULL;
|
||||
pxEnd->xTag = -1;
|
||||
@ -527,8 +559,8 @@ const HeapRegionTagged_t *pxHeapRegion;
|
||||
/* To start with there is a single free block in this region that is
|
||||
sized to take up the entire heap region minus the space taken by the
|
||||
free block structure. */
|
||||
pxFirstFreeBlockInRegion = ( BlockLink_t * ) pucAlignedHeap;
|
||||
pxFirstFreeBlockInRegion->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlockInRegion;
|
||||
pxFirstFreeBlockInRegion = ( BlockLink_t * ) (pucAlignedHeap + BLOCK_HEAD_LEN);
|
||||
pxFirstFreeBlockInRegion->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlockInRegion + BLOCK_HEAD_LEN;
|
||||
pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;
|
||||
pxFirstFreeBlockInRegion->xTag=pxHeapRegion->xTag;
|
||||
|
||||
@ -545,6 +577,13 @@ const HeapRegionTagged_t *pxHeapRegion;
|
||||
xDefinedRegions++;
|
||||
xRegIdx++;
|
||||
pxHeapRegion = &( pxHeapRegions[ xRegIdx ] );
|
||||
|
||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||
{
|
||||
mem_init_dog(pxFirstFreeBlockInRegion);
|
||||
mem_init_dog(pxEnd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
xMinimumEverFreeBytesRemaining = xTotalHeapSize;
|
||||
@ -555,5 +594,12 @@ const HeapRegionTagged_t *pxHeapRegion;
|
||||
|
||||
/* Work out the position of the top bit in a size_t variable. */
|
||||
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
|
||||
|
||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||
{
|
||||
mem_debug_init(uxHeapStructSize, &xStart, pxEnd, &xMallocMutex, xBlockAllocatedBit);
|
||||
mem_check_all(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
193
components/freertos/heap_regions_debug.c
Normal file
193
components/freertos/heap_regions_debug.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include "heap_regions_debug.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||
|
||||
static os_block_t g_malloc_list, *g_free_list=NULL, *g_end;
|
||||
static size_t g_heap_struct_size;
|
||||
static mem_dbg_ctl_t g_mem_dbg;
|
||||
char g_mem_print = 0;
|
||||
static portMUX_TYPE *g_malloc_mutex = NULL;
|
||||
static unsigned int g_alloc_bit;
|
||||
#define MEM_DEBUG(...)
|
||||
|
||||
void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex, unsigned int alloc_bit)
|
||||
{
|
||||
MEM_DEBUG("size=%d start=%p end=%p mutex=%p alloc_bit=0x%x\n", size, start, end, mutex, alloc_bit);
|
||||
memset(&g_mem_dbg, 0, sizeof(g_mem_dbg));
|
||||
memset(&g_malloc_list, 0, sizeof(g_malloc_list));
|
||||
g_malloc_mutex = mutex;
|
||||
g_heap_struct_size = size;
|
||||
g_free_list = start;
|
||||
g_end = end;
|
||||
g_alloc_bit = alloc_bit;
|
||||
}
|
||||
|
||||
void mem_debug_push(char type, void *addr)
|
||||
{
|
||||
os_block_t *b = (os_block_t*)addr;
|
||||
debug_block_t *debug_b = DEBUG_BLOCK(b);
|
||||
|
||||
MEM_DEBUG("push type=%d addr=%p\n", type, addr);
|
||||
if (g_mem_print){
|
||||
if (type == DEBUG_TYPE_MALLOC){
|
||||
ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size&(~g_alloc_bit), addr);
|
||||
} else {
|
||||
ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size&(~g_alloc_bit), addr);
|
||||
}
|
||||
} else {
|
||||
mem_dbg_info_t *info = &g_mem_dbg.info[g_mem_dbg.cnt%DEBUG_MAX_INFO_NUM];
|
||||
|
||||
info->addr = addr;
|
||||
info->type = type;
|
||||
info->time = g_mem_dbg.cnt;
|
||||
g_mem_dbg.cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void mem_debug_malloc_show(void)
|
||||
{
|
||||
os_block_t *b = g_malloc_list.next;
|
||||
debug_block_t *d;
|
||||
|
||||
taskENTER_CRITICAL(g_malloc_mutex);
|
||||
while (b){
|
||||
d = DEBUG_BLOCK(b);
|
||||
d->head.task[3] = '\0';
|
||||
ets_printf("t=%s s=%u a=%p\n", d->head.task?d->head.task:"", b->size&(~g_alloc_bit), b);
|
||||
b = b->next;
|
||||
}
|
||||
taskEXIT_CRITICAL(g_malloc_mutex);
|
||||
}
|
||||
|
||||
void mem_debug_show(void)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (!g_mem_print) return;
|
||||
|
||||
for (i=0; i<DEBUG_MAX_INFO_NUM; i++){
|
||||
ets_printf("%u %s %p\n", g_mem_dbg.info[i].time, g_mem_dbg.info[i].type == DEBUG_TYPE_FREE?"f":"m", g_mem_dbg.info[i].addr);
|
||||
}
|
||||
}
|
||||
|
||||
void mem_check_block(void* data)
|
||||
{
|
||||
debug_block_t *b = DEBUG_BLOCK(data);
|
||||
|
||||
MEM_DEBUG("check block data=%p\n", data);
|
||||
if (data && (HEAD_DOG(b) == DEBUG_DOG_VALUE)){
|
||||
if (TAIL_DOG(b) != DEBUG_DOG_VALUE){
|
||||
ets_printf("f task=%s a=%p h=%08x t=%08x\n", b->head.task?b->head.task:"", b, HEAD_DOG(b), TAIL_DOG(b));
|
||||
DOG_ASSERT();
|
||||
}
|
||||
} else {
|
||||
ets_printf("f task=%s a=%p h=%08x\n", b->head.task?b->head.task:"", b, HEAD_DOG(b));\
|
||||
DOG_ASSERT();
|
||||
}
|
||||
}
|
||||
|
||||
void mem_init_dog(void *data)
|
||||
{
|
||||
debug_block_t *b = DEBUG_BLOCK(data);
|
||||
xTaskHandle task;
|
||||
|
||||
MEM_DEBUG("init dog, data=%p debug_block=%p block_size=%x\n", data, b, b->os_block.size);
|
||||
if (!data) return;
|
||||
#if (INCLUDE_pcTaskGetTaskName == 1)
|
||||
task = xTaskGetCurrentTaskHandle();
|
||||
if (task){
|
||||
strncpy(b->head.task, pcTaskGetTaskName(task), 3);
|
||||
b->head.task[3] = '\0';
|
||||
}
|
||||
#else
|
||||
b->head.task = '\0';
|
||||
#endif
|
||||
HEAD_DOG(b) = DEBUG_DOG_VALUE;
|
||||
TAIL_DOG(b) = DEBUG_DOG_VALUE;
|
||||
}
|
||||
|
||||
void mem_check_all(void* pv)
|
||||
{
|
||||
os_block_t *b;
|
||||
|
||||
if (pv){
|
||||
char *puc = (char*)(pv);
|
||||
os_block_t *b;
|
||||
puc -= (g_heap_struct_size - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN);
|
||||
b = (os_block_t*)puc;
|
||||
mem_check_block(b);
|
||||
}
|
||||
|
||||
taskENTER_CRITICAL(g_malloc_mutex);
|
||||
b = g_free_list->next;
|
||||
while(b && b != g_end){
|
||||
mem_check_block(b);
|
||||
ets_printf("check b=%p size=%d ok\n", b, b->size);
|
||||
b = b->next;
|
||||
}
|
||||
taskEXIT_CRITICAL(g_malloc_mutex);
|
||||
}
|
||||
|
||||
void mem_malloc_show(void)
|
||||
{
|
||||
os_block_t *b = g_malloc_list.next;
|
||||
debug_block_t *debug_b;
|
||||
|
||||
while (b){
|
||||
debug_b = DEBUG_BLOCK(b);
|
||||
ets_printf("%s %p %p %u\n", debug_b->head.task, debug_b, b, b->size&(~g_alloc_bit));
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
|
||||
void mem_malloc_block(void *data)
|
||||
{
|
||||
os_block_t *b = (os_block_t*)data;
|
||||
|
||||
MEM_DEBUG("mem malloc block data=%p, size=%u\n", data, b->size&(~g_alloc_bit));
|
||||
mem_debug_push(DEBUG_TYPE_MALLOC, data);
|
||||
|
||||
if (b){
|
||||
b->next = g_malloc_list.next;
|
||||
g_malloc_list.next = b;
|
||||
}
|
||||
}
|
||||
|
||||
void mem_free_block(void *data)
|
||||
{
|
||||
os_block_t *del = (os_block_t*)data;
|
||||
os_block_t *b = g_malloc_list.next;
|
||||
os_block_t *pre = &g_malloc_list;
|
||||
debug_block_t *debug_b;
|
||||
|
||||
MEM_DEBUG("mem free block data=%p, size=%d\n", data, del->size&(~g_alloc_bit));
|
||||
mem_debug_push(DEBUG_TYPE_FREE, data);
|
||||
|
||||
if (!del) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (b){
|
||||
if ( (del == b) ){
|
||||
pre->next = b->next;
|
||||
b->next = NULL;
|
||||
return;
|
||||
}
|
||||
pre = b;
|
||||
b = b->next;
|
||||
}
|
||||
|
||||
debug_b = DEBUG_BLOCK(del);
|
||||
ets_printf("%s %p %p %u already free\n", debug_b->head.task, debug_b, del, del->size&(~g_alloc_bit));
|
||||
mem_malloc_show();
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -188,8 +188,12 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef INCLUDE_pcTaskGetTaskName
|
||||
#if ( configENABLE_MEMORY_DEBUG == 1)
|
||||
#define INCLUDE_pcTaskGetTaskName 1
|
||||
#else
|
||||
#define INCLUDE_pcTaskGetTaskName 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef configUSE_APPLICATION_TASK_TAG
|
||||
#define configUSE_APPLICATION_TASK_TAG 0
|
||||
@ -783,6 +787,10 @@ V8 if desired. */
|
||||
#define xList List_t
|
||||
#endif /* configENABLE_BACKWARD_COMPATIBILITY */
|
||||
|
||||
#ifndef configESP32_PER_TASK_DATA
|
||||
#define configESP32_PER_TASK_DATA 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -106,12 +106,25 @@
|
||||
#include "xtensa_config.h"
|
||||
|
||||
|
||||
#if 1
|
||||
/* configASSERT behaviour */
|
||||
#ifndef __ASSEMBLER__
|
||||
#include "rom/ets_sys.h"
|
||||
#define configASSERT(a) if (!(a)) ets_printf("%s:%d (%s)- assert failed!\n", __FILE__, __LINE__, __FUNCTION__)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FREERTOS_ASSERT_DISABLE)
|
||||
#define configASSERT(a) /* assertions disabled */
|
||||
#elif defined(CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE)
|
||||
#define configASSERT(a) if (!(a)) { \
|
||||
ets_printf("%s:%d (%s)- assert failed!\n", __FILE__, __LINE__, \
|
||||
__FUNCTION__); \
|
||||
}
|
||||
#else /* CONFIG_FREERTOS_ASSERT_FAIL_ABORT */
|
||||
#define configASSERT(a) if (!(a)) { \
|
||||
ets_printf("%s:%d (%s)- assert failed!\n", __FILE__, __LINE__, \
|
||||
__FUNCTION__); \
|
||||
abort(); \
|
||||
}
|
||||
#endif
|
||||
#endif /* def __ASSEMBLER__ */
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
@ -209,6 +222,12 @@
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||
|
||||
#ifndef configENABLE_MEMORY_DEBUG
|
||||
#define configENABLE_MEMORY_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define INCLUDE_xSemaphoreGetMutexHolder 1
|
||||
|
||||
/* The priority at which the tick interrupt runs. This should probably be
|
||||
kept at 1. */
|
||||
#define configKERNEL_INTERRUPT_PRIORITY 1
|
||||
|
78
components/freertos/include/freertos/heap_regions_debug.h
Normal file
78
components/freertos/include/freertos/heap_regions_debug.h
Normal file
@ -0,0 +1,78 @@
|
||||
#ifndef _HEAP_REGION_DEBUG_H
|
||||
#define _HEAP_REGION_DEBUG_H
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||
|
||||
#define DEBUG_DOG_VALUE 0x1a2b3c4d
|
||||
#define DEBUG_MAX_INFO_NUM 20
|
||||
#define DEBUG_TYPE_MALLOC 1
|
||||
#define DEBUG_TYPE_FREE 2
|
||||
|
||||
typedef struct {
|
||||
unsigned int dog;
|
||||
char task[4];
|
||||
unsigned int pc;
|
||||
}block_head_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int dog;
|
||||
}block_tail_t;
|
||||
|
||||
/* Please keep this definition same as BlockLink_t */
|
||||
typedef struct _os_block_t {
|
||||
struct _os_block_t *next;
|
||||
size_t size;
|
||||
unsigned int xtag;
|
||||
}os_block_t;
|
||||
|
||||
typedef struct {
|
||||
block_head_t head;
|
||||
os_block_t os_block;
|
||||
}debug_block_t;
|
||||
|
||||
typedef struct _mem_dbg_info{
|
||||
void *addr;
|
||||
char *task;
|
||||
uint32_t pc;
|
||||
uint32_t time;
|
||||
uint8_t type;
|
||||
}mem_dbg_info_t;
|
||||
|
||||
typedef struct _mem_dbg_ctl{
|
||||
mem_dbg_info_t info[DEBUG_MAX_INFO_NUM];
|
||||
uint32_t cnt;
|
||||
}mem_dbg_ctl_t;
|
||||
|
||||
#define BLOCK_HEAD_LEN sizeof(block_head_t)
|
||||
#define BLOCK_TAIL_LEN sizeof(block_tail_t)
|
||||
#define OS_BLOCK(_b) ((os_block_t*)((debug_block_t*)((char*)(_b) + BLOCK_HEAD_LEN)))
|
||||
#define DEBUG_BLOCK(_b) ((debug_block_t*)((char*)(_b) - BLOCK_HEAD_LEN))
|
||||
#define HEAD_DOG(_b) ((_b)->head.dog)
|
||||
#define TAIL_DOG(_b) (*(unsigned int*)((char*)(_b) + (((_b)->os_block.size & (~g_alloc_bit) ) - BLOCK_TAIL_LEN)))
|
||||
|
||||
#define DOG_ASSERT()\
|
||||
{\
|
||||
mem_debug_show();\
|
||||
abort();\
|
||||
}
|
||||
|
||||
extern void mem_check_block(void * data);
|
||||
extern void mem_init_dog(void *data);
|
||||
extern void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex, unsigned int alloc_bit);
|
||||
extern void mem_malloc_block(void *data);
|
||||
extern void mem_free_block(void *data);
|
||||
extern void mem_check_all(void* pv);
|
||||
|
||||
#else
|
||||
|
||||
#define mem_check_block(...)
|
||||
#define mem_init_dog(...)
|
||||
|
||||
#define BLOCK_HEAD_LEN 0
|
||||
#define BLOCK_TAIL_LEN 0
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
7
components/freertos/include/freertos/panic.h
Normal file
7
components/freertos/include/freertos/panic.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef PANIC_H
|
||||
#define PANIC_H
|
||||
|
||||
void setBreakpointIfJtag(void *fn);
|
||||
|
||||
|
||||
#endif
|
@ -118,12 +118,14 @@ typedef unsigned portBASE_TYPE UBaseType_t;
|
||||
// portbenchmark
|
||||
#include "portbenchmark.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define portFIRST_TASK_HOOK CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
||||
|
||||
#define portMUX_DEBUG
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t mux;
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
const char *lastLockedFn;
|
||||
int lastLockedLine;
|
||||
#endif
|
||||
@ -148,7 +150,7 @@ typedef struct {
|
||||
#define portMUX_VAL_SHIFT 0
|
||||
|
||||
//Keep this in sync with the portMUX_TYPE struct definition please.
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifndef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
#define portMUX_INITIALIZER_UNLOCKED { \
|
||||
.mux = portMUX_MAGIC_VAL|portMUX_FREE_VAL \
|
||||
}
|
||||
@ -167,13 +169,6 @@ typedef struct {
|
||||
|
||||
#define portCRITICAL_NESTING_IN_TCB 1
|
||||
|
||||
|
||||
/*
|
||||
Enable this to enable mux debugging. With this on, the mux code will warn you for deadlocks
|
||||
and double releases etc.
|
||||
*/
|
||||
#define portMUX_DEBUG
|
||||
|
||||
/*
|
||||
Modifications to portENTER_CRITICAL:
|
||||
|
||||
@ -195,7 +190,7 @@ This all assumes that interrupts are either entirely disabled or enabled. Interr
|
||||
will break this scheme.
|
||||
*/
|
||||
void vPortCPUInitializeMutex(portMUX_TYPE *mux);
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
void vPortCPUAcquireMutex(portMUX_TYPE *mux, const char *function, int line);
|
||||
portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux, const char *function, int line);
|
||||
void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line );
|
||||
|
@ -75,6 +75,8 @@
|
||||
#error "include FreeRTOS.h must appear in source files before include task.h"
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
@ -91,7 +93,7 @@ extern "C" {
|
||||
#define tskKERNEL_VERSION_MINOR 2
|
||||
#define tskKERNEL_VERSION_BUILD 0
|
||||
|
||||
#define tskNO_AFFINITY portNUM_PROCESSORS
|
||||
#define tskNO_AFFINITY INT_MAX
|
||||
|
||||
/**
|
||||
* task. h
|
||||
|
@ -35,7 +35,7 @@ overflow handler also is in here.
|
||||
*/
|
||||
|
||||
#if !CONFIG_FREERTOS_PANIC_SILENT_REBOOT
|
||||
//os_printf may be broken, so we fix our own printing fns...
|
||||
//printf may be broken, so we fix our own printing fns...
|
||||
inline static void panicPutchar(char c) {
|
||||
while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
|
||||
WRITE_PERI_REG(UART_FIFO_REG(0), c);
|
||||
@ -142,6 +142,16 @@ void panicHandler(XtExcFrame *frame) {
|
||||
commonErrorHandler(frame);
|
||||
}
|
||||
|
||||
static void setFirstBreakpoint(uint32_t pc) {
|
||||
asm(
|
||||
"wsr.ibreaka0 %0\n" \
|
||||
"rsr.ibreakenable a3\n" \
|
||||
"movi a4,1\n" \
|
||||
"or a4, a4, a3\n" \
|
||||
"wsr.ibreakenable a4\n" \
|
||||
::"r"(pc):"a3","a4");
|
||||
}
|
||||
|
||||
void xt_unhandled_exception(XtExcFrame *frame) {
|
||||
int *regs=(int*)frame;
|
||||
int x;
|
||||
@ -158,13 +168,7 @@ void xt_unhandled_exception(XtExcFrame *frame) {
|
||||
panicPutStr(". Setting bp and returning..\r\n");
|
||||
//Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger
|
||||
//will kick in exactly at the context the error happened.
|
||||
asm(
|
||||
"wsr.ibreaka0 %0\n" \
|
||||
"rsr.ibreakenable a3\n" \
|
||||
"movi a4,1\n" \
|
||||
"or a4, a4, a3\n" \
|
||||
"wsr.ibreakenable a4\n" \
|
||||
::"r"(regs[1]):"a3","a4");
|
||||
setFirstBreakpoint(regs[1]);
|
||||
return;
|
||||
}
|
||||
panicPutStr(". Exception was unhandled.\r\n");
|
||||
@ -209,3 +213,9 @@ void commonErrorHandler(XtExcFrame *frame) {
|
||||
while(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void setBreakpointIfJtag(void *fn) {
|
||||
if (!inOCDMode()) return;
|
||||
setFirstBreakpoint((uint32_t)fn);
|
||||
}
|
||||
|
@ -101,6 +101,8 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "panic.h"
|
||||
|
||||
/* Defined in portasm.h */
|
||||
extern void _frxt_tick_timer_init(void);
|
||||
|
||||
@ -249,7 +251,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMOR
|
||||
|
||||
/*
|
||||
* Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare
|
||||
* *addr to compare, and if it's the same, will set *addr to set. It will return the old value
|
||||
* *mux to compare, and if it's the same, will set *mux to set. It will return the old value
|
||||
* of *addr.
|
||||
*
|
||||
* Note: the NOPs are needed on the ESP31 processor but superfluous on the ESP32.
|
||||
@ -274,7 +276,7 @@ uint32_t uxPortCompareSet(volatile uint32_t *mux, uint32_t compare, uint32_t set
|
||||
* For kernel use: Initialize a per-CPU mux. Mux will be initialized unlocked.
|
||||
*/
|
||||
void vPortCPUInitializeMutex(portMUX_TYPE *mux) {
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
ets_printf("Initializing mux %p\n", mux);
|
||||
mux->lastLockedFn="(never locked)";
|
||||
mux->lastLockedLine=-1;
|
||||
@ -286,7 +288,7 @@ void vPortCPUInitializeMutex(portMUX_TYPE *mux) {
|
||||
/*
|
||||
* For kernel use: Acquire a per-CPU mux. Spinlocks, so don't hold on to these muxes for too long.
|
||||
*/
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
void vPortCPUAcquireMutex(portMUX_TYPE *mux, const char *fnName, int line) {
|
||||
#else
|
||||
void vPortCPUAcquireMutex(portMUX_TYPE *mux) {
|
||||
@ -294,7 +296,7 @@ void vPortCPUAcquireMutex(portMUX_TYPE *mux) {
|
||||
uint32_t res;
|
||||
uint32_t recCnt;
|
||||
unsigned int irqStatus;
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
uint32_t cnt=(1<<16);
|
||||
if ( (mux->mux & portMUX_MAGIC_MASK) != portMUX_MAGIC_VAL ) {
|
||||
ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, mux->mux, fnName, line);
|
||||
@ -311,21 +313,21 @@ void vPortCPUAcquireMutex(portMUX_TYPE *mux) {
|
||||
//Mux was already locked by us. Just bump the recurse count by one.
|
||||
recCnt=(res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT;
|
||||
recCnt++;
|
||||
#ifdef portMUX_DEBUG_RECURSIVE
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
||||
ets_printf("Recursive lock: recCnt=%d last non-recursive lock %s line %d, curr %s line %d\n", recCnt, mux->lastLockedFn, mux->lastLockedLine, fnName, line);
|
||||
#endif
|
||||
mux->mux=portMUX_MAGIC_VAL|(recCnt<<portMUX_CNT_SHIFT)|(xPortGetCoreID()<<portMUX_VAL_SHIFT);
|
||||
break;
|
||||
}
|
||||
cnt--;
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
cnt--;
|
||||
if (cnt==0) {
|
||||
ets_printf("Timeout on mux! last non-recursive lock %s line %d, curr %s line %d\n", mux->lastLockedFn, mux->lastLockedLine, fnName, line);
|
||||
ets_printf("Mux value %X\n", mux->mux);
|
||||
}
|
||||
#endif
|
||||
} while (res!=portMUX_FREE_VAL);
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
if (res==portMUX_FREE_VAL) { //initial lock
|
||||
mux->lastLockedFn=fnName;
|
||||
mux->lastLockedLine=line;
|
||||
@ -338,7 +340,7 @@ void vPortCPUAcquireMutex(portMUX_TYPE *mux) {
|
||||
* For kernel use: Release a per-CPU mux. Returns true if everything is OK, false if mux
|
||||
* was already unlocked or is locked by a different core.
|
||||
*/
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux, const char *fnName, int line) {
|
||||
#else
|
||||
portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
||||
@ -349,7 +351,7 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
||||
portBASE_TYPE ret=pdTRUE;
|
||||
// ets_printf("Unlock %p\n", mux);
|
||||
irqStatus=portENTER_CRITICAL_NESTED();
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
const char *lastLockedFn=mux->lastLockedFn;
|
||||
int lastLockedLine=mux->lastLockedLine;
|
||||
mux->lastLockedFn=fnName;
|
||||
@ -360,13 +362,13 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
||||
res=uxPortCompareSet(&mux->mux, (xPortGetCoreID()<<portMUX_VAL_SHIFT)|portMUX_MAGIC_VAL, portMUX_FREE_VAL);
|
||||
|
||||
if ( res == portMUX_FREE_VAL ) {
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux);
|
||||
ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line);
|
||||
#endif
|
||||
ret=pdFALSE;
|
||||
} else if ( ((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT) != xPortGetCoreID() ) {
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p wasn't locked by this core (%d) but by core %d (ret=%x, mux=%x).\n", mux, xPortGetCoreID(), ((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT), res, mux->mux);
|
||||
ets_printf("Last non-recursive lock %s line %d\n", lastLockedFn, lastLockedLine);
|
||||
ets_printf("Called by %s line %d\n", fnName, line);
|
||||
@ -376,7 +378,7 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
||||
//We locked this, but the reccount isn't zero. Decrease refcount and continue.
|
||||
recCnt=(res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT;
|
||||
recCnt--;
|
||||
#ifdef portMUX_DEBUG_RECURSIVE
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
||||
ets_printf("Recursive unlock: recCnt=%d last locked %s line %d, curr %s line %d\n", recCnt, lastLockedFn, lastLockedLine, fnName, line);
|
||||
#endif
|
||||
mux->mux=portMUX_MAGIC_VAL|(recCnt<<portMUX_CNT_SHIFT)|(xPortGetCoreID()<<portMUX_VAL_SHIFT);
|
||||
@ -385,6 +387,10 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
||||
void vPortFirstTaskHook(TaskFunction_t function) {
|
||||
setBreakpointIfJtag(function);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -483,14 +483,15 @@ int8_t *pcAllocatedBuffer;
|
||||
|
||||
void* xQueueGetMutexHolder( QueueHandle_t xSemaphore )
|
||||
{
|
||||
void *pxReturn;
|
||||
Queue_t * const pxQueue = ( Queue_t * ) xSemaphore;
|
||||
void *pxReturn;
|
||||
|
||||
/* This function is called by xSemaphoreGetMutexHolder(), and should not
|
||||
be called directly. Note: This is a good way of determining if the
|
||||
calling task is the mutex holder, but not a good way of determining the
|
||||
identity of the mutex holder, as the holder may change between the
|
||||
following critical section exiting and the function returning. */
|
||||
taskENTER_CRITICAL();
|
||||
taskENTER_CRITICAL(&pxQueue->mux);
|
||||
{
|
||||
if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX )
|
||||
{
|
||||
@ -501,7 +502,7 @@ int8_t *pcAllocatedBuffer;
|
||||
pxReturn = NULL;
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
taskEXIT_CRITICAL(&pxQueue->mux);
|
||||
|
||||
return pxReturn;
|
||||
} /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */
|
||||
|
@ -84,6 +84,7 @@ task.h is included from an application file. */
|
||||
#include "timers.h"
|
||||
#include "StackMacros.h"
|
||||
#include "portmacro.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Lint e961 and e750 are suppressed as a MISRA exception justified because the
|
||||
MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
|
||||
@ -445,6 +446,11 @@ to its original value when it is released. */
|
||||
extern void vApplicationTickHook( void );
|
||||
#endif
|
||||
|
||||
#if portFIRST_TASK_HOOK
|
||||
extern void vPortFirstTaskHook(TaskFunction_t taskfn);
|
||||
#endif
|
||||
|
||||
|
||||
/* File private functions. --------------------------------*/
|
||||
|
||||
/*
|
||||
@ -707,6 +713,12 @@ BaseType_t i;
|
||||
/* Schedule if nothing is scheduled yet, or overwrite a task of lower prio. */
|
||||
if ( pxCurrentTCB[i] == NULL || pxCurrentTCB[i]->uxPriority <= uxPriority )
|
||||
{
|
||||
#if portFIRST_TASK_HOOK
|
||||
if ( i == 0) {
|
||||
vPortFirstTaskHook(pxTaskCode);
|
||||
}
|
||||
#endif /* configFIRST_TASK_HOOK */
|
||||
|
||||
pxCurrentTCB[i] = pxNewTCB;
|
||||
break;
|
||||
}
|
||||
@ -3743,14 +3755,14 @@ scheduler will re-enable the interrupts instead. */
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
|
||||
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line )
|
||||
#else
|
||||
void vTaskEnterCritical( portMUX_TYPE *mux )
|
||||
#endif
|
||||
{
|
||||
portDISABLE_INTERRUPTS();
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
vPortCPUAcquireMutex( mux, function, line );
|
||||
#else
|
||||
vPortCPUAcquireMutex( mux );
|
||||
@ -3783,13 +3795,13 @@ scheduler will re-enable the interrupts instead. */
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
void vTaskExitCritical( portMUX_TYPE *mux, const char *function, int line )
|
||||
#else
|
||||
void vTaskExitCritical( portMUX_TYPE *mux )
|
||||
#endif
|
||||
{
|
||||
#ifdef portMUX_DEBUG
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
vPortCPUReleaseMutex( mux, function, line );
|
||||
#else
|
||||
vPortCPUReleaseMutex( mux );
|
||||
@ -4568,9 +4580,6 @@ TickType_t uxReturn;
|
||||
|
||||
#endif /* configUSE_TASK_NOTIFICATIONS */
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifdef FREERTOS_MODULE_TEST
|
||||
#include "tasks_test_access_functions.h"
|
||||
#endif
|
||||
|
20
components/json/LICENSE
Normal file
20
components/json/LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
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.
|
||||
|
13
components/json/Makefile
Normal file
13
components/json/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
|
||||
# this will take the sources in this directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
COMPONENT_ADD_INCLUDEDIRS := include port/include
|
||||
|
||||
COMPONENT_SRCDIRS := library port
|
||||
|
||||
include $(IDF_PATH)/make/component.mk
|
247
components/json/README
Normal file
247
components/json/README
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
Welcome to cJSON.
|
||||
|
||||
cJSON aims to be the dumbest possible parser that you can get your job done with.
|
||||
It's a single file of C, and a single header file.
|
||||
|
||||
JSON is described best here: http://www.json.org/
|
||||
It's like XML, but fat-free. You use it to move data around, store things, or just
|
||||
generally represent your program's state.
|
||||
|
||||
|
||||
First up, how do I build?
|
||||
Add cJSON.c to your project, and put cJSON.h somewhere in the header search path.
|
||||
For example, to build the test app:
|
||||
|
||||
gcc cJSON.c test.c -o test -lm
|
||||
./test
|
||||
|
||||
|
||||
As a library, cJSON exists to take away as much legwork as it can, but not get in your way.
|
||||
As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it
|
||||
in one of two modes: Auto and Manual. Let's have a quick run-through.
|
||||
|
||||
|
||||
I lifted some JSON from this page: http://www.json.org/fatfree.html
|
||||
That page inspired me to write cJSON, which is a parser that tries to share the same
|
||||
philosophy as JSON itself. Simple, dumb, out of the way.
|
||||
|
||||
Some JSON:
|
||||
{
|
||||
"name": "Jack (\"Bee\") Nimble",
|
||||
"format": {
|
||||
"type": "rect",
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"interlace": false,
|
||||
"frame rate": 24
|
||||
}
|
||||
}
|
||||
|
||||
Assume that you got this from a file, a webserver, or magic JSON elves, whatever,
|
||||
you have a char * to it. Everything is a cJSON struct.
|
||||
Get it parsed:
|
||||
cJSON *root = cJSON_Parse(my_json_string);
|
||||
|
||||
This is an object. We're in C. We don't have objects. But we do have structs.
|
||||
What's the framerate?
|
||||
|
||||
cJSON *format = cJSON_GetObjectItem(root,"format");
|
||||
int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint;
|
||||
|
||||
|
||||
Want to change the framerate?
|
||||
cJSON_GetObjectItem(format,"frame rate")->valueint=25;
|
||||
|
||||
Back to disk?
|
||||
char *rendered=cJSON_Print(root);
|
||||
|
||||
Finished? Delete the root (this takes care of everything else).
|
||||
cJSON_Delete(root);
|
||||
|
||||
That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers
|
||||
before you dereference them. If you want to see how you'd build this struct in code?
|
||||
cJSON *root,*fmt;
|
||||
root=cJSON_CreateObject();
|
||||
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
|
||||
cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(fmt,"type", "rect");
|
||||
cJSON_AddNumberToObject(fmt,"width", 1920);
|
||||
cJSON_AddNumberToObject(fmt,"height", 1080);
|
||||
cJSON_AddFalseToObject (fmt,"interlace");
|
||||
cJSON_AddNumberToObject(fmt,"frame rate", 24);
|
||||
|
||||
Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup.
|
||||
Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and
|
||||
a few from elsewhere.
|
||||
|
||||
What about manual mode? First up you need some detail.
|
||||
Let's cover how the cJSON objects represent the JSON data.
|
||||
cJSON doesn't distinguish arrays from objects in handling; just type.
|
||||
Each cJSON has, potentially, a child, siblings, value, a name.
|
||||
|
||||
The root object has: Object Type and a Child
|
||||
The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling:
|
||||
Sibling has type Object, name "format", and a child.
|
||||
That child has type String, name "type", value "rect", and a sibling:
|
||||
Sibling has type Number, name "width", value 1920, and a sibling:
|
||||
Sibling has type Number, name "height", value 1080, and a sibling:
|
||||
Sibling has type False, name "interlace", and a sibling:
|
||||
Sibling has type Number, name "frame rate", value 24
|
||||
|
||||
Here's the structure:
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev;
|
||||
struct cJSON *child;
|
||||
|
||||
int type;
|
||||
|
||||
char *valuestring;
|
||||
int valueint;
|
||||
double valuedouble;
|
||||
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
By default all values are 0 unless set by virtue of being meaningful.
|
||||
|
||||
next/prev is a doubly linked list of siblings. next takes you to your sibling,
|
||||
prev takes you back from your sibling to you.
|
||||
Only objects and arrays have a "child", and it's the head of the doubly linked list.
|
||||
A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0.
|
||||
The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in
|
||||
cJSON.h
|
||||
|
||||
A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read
|
||||
valuedouble.
|
||||
|
||||
Any entry which is in the linked list which is the child of an object will have a "string"
|
||||
which is the "name" of the entry. When I said "name" in the above example, that's "string".
|
||||
"string" is the JSON name for the 'variable name' if you will.
|
||||
|
||||
Now you can trivially walk the lists, recursively, and parse as you please.
|
||||
You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take
|
||||
the root object, and traverse the structure (which is, formally, an N-tree),
|
||||
and tokenise as you please. If you wanted to build a callback style parser, this is how
|
||||
you'd do it (just an example, since these things are very specific):
|
||||
|
||||
void parse_and_callback(cJSON *item,const char *prefix)
|
||||
{
|
||||
while (item)
|
||||
{
|
||||
char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2);
|
||||
sprintf(newprefix,"%s/%s",prefix,item->name);
|
||||
int dorecurse=callback(newprefix, item->type, item);
|
||||
if (item->child && dorecurse) parse_and_callback(item->child,newprefix);
|
||||
item=item->next;
|
||||
free(newprefix);
|
||||
}
|
||||
}
|
||||
|
||||
The prefix process will build you a separated list, to simplify your callback handling.
|
||||
The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or
|
||||
let you invoke it per-item. For the item above, your callback might look like this:
|
||||
|
||||
int callback(const char *name,int type,cJSON *item)
|
||||
{
|
||||
if (!strcmp(name,"name")) { /* populate name */ }
|
||||
else if (!strcmp(name,"format/type") { /* handle "rect" */ }
|
||||
else if (!strcmp(name,"format/width") { /* 800 */ }
|
||||
else if (!strcmp(name,"format/height") { /* 600 */ }
|
||||
else if (!strcmp(name,"format/interlace") { /* false */ }
|
||||
else if (!strcmp(name,"format/frame rate") { /* 24 */ }
|
||||
return 1;
|
||||
}
|
||||
|
||||
Alternatively, you might like to parse iteratively.
|
||||
You'd use:
|
||||
|
||||
void parse_object(cJSON *item)
|
||||
{
|
||||
int i; for (i=0;i<cJSON_GetArraySize(item);i++)
|
||||
{
|
||||
cJSON *subitem=cJSON_GetArrayItem(item,i);
|
||||
// handle subitem.
|
||||
}
|
||||
}
|
||||
|
||||
Or, for PROPER manual mode:
|
||||
|
||||
void parse_object(cJSON *item)
|
||||
{
|
||||
cJSON *subitem=item->child;
|
||||
while (subitem)
|
||||
{
|
||||
// handle subitem
|
||||
if (subitem->child) parse_object(subitem->child);
|
||||
|
||||
subitem=subitem->next;
|
||||
}
|
||||
}
|
||||
|
||||
Of course, this should look familiar, since this is just a stripped-down version
|
||||
of the callback-parser.
|
||||
|
||||
This should cover most uses you'll find for parsing. The rest should be possible
|
||||
to infer.. and if in doubt, read the source! There's not a lot of it! ;)
|
||||
|
||||
|
||||
In terms of constructing JSON data, the example code above is the right way to do it.
|
||||
You can, of course, hand your sub-objects to other functions to populate.
|
||||
Also, if you find a use for it, you can manually build the objects.
|
||||
For instance, suppose you wanted to build an array of objects?
|
||||
|
||||
cJSON *objects[24];
|
||||
|
||||
cJSON *Create_array_of_anything(cJSON **items,int num)
|
||||
{
|
||||
int i;cJSON *prev, *root=cJSON_CreateArray();
|
||||
for (i=0;i<24;i++)
|
||||
{
|
||||
if (!i) root->child=objects[i];
|
||||
else prev->next=objects[i], objects[i]->prev=prev;
|
||||
prev=objects[i];
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
and simply: Create_array_of_anything(objects,24);
|
||||
|
||||
cJSON doesn't make any assumptions about what order you create things in.
|
||||
You can attach the objects, as above, and later add children to each
|
||||
of those objects.
|
||||
|
||||
As soon as you call cJSON_Print, it renders the structure to text.
|
||||
|
||||
|
||||
|
||||
The test.c code shows how to handle a bunch of typical cases. If you uncomment
|
||||
the code, it'll load, parse and print a bunch of test files, also from json.org,
|
||||
which are more complex than I'd care to try and stash into a const char array[].
|
||||
|
||||
|
||||
Enjoy cJSON!
|
||||
|
||||
|
||||
- Dave Gamble, Aug 2009
|
149
components/json/include/cJSON.h
Normal file
149
components/json/include/cJSON.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
|
||||
int type; /* The type of the item, as above. */
|
||||
|
||||
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||
int valueint; /* The item's number, if type==cJSON_Number */
|
||||
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||
|
||||
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
extern const char *cJSON_GetErrorPtr(void);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
|
||||
|
||||
extern void cJSON_Minify(char *json);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
750
components/json/library/cJSON.c
Normal file
750
components/json/library/cJSON.c
Normal file
@ -0,0 +1,750 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/* cJSON */
|
||||
/* JSON parser in C. */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include "cJSON.h"
|
||||
|
||||
static const char *ep;
|
||||
|
||||
const char *cJSON_GetErrorPtr(void) {return ep;}
|
||||
|
||||
static int cJSON_strcasecmp(const char *s1,const char *s2)
|
||||
{
|
||||
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
|
||||
for(; tolower(*(const unsigned char *)s1) == tolower(*(const unsigned char *)s2); ++s1, ++s2) if(*s1 == 0) return 0;
|
||||
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
||||
}
|
||||
|
||||
static void *(*cJSON_malloc)(size_t sz) = malloc;
|
||||
static void (*cJSON_free)(void *ptr) = free;
|
||||
|
||||
static char* cJSON_strdup(const char* str)
|
||||
{
|
||||
size_t len;
|
||||
char* copy;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||
memcpy(copy,str,len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
void cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||
{
|
||||
if (!hooks) { /* Reset hooks */
|
||||
cJSON_malloc = malloc;
|
||||
cJSON_free = free;
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
|
||||
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
|
||||
}
|
||||
|
||||
/* Internal constructor. */
|
||||
static cJSON *cJSON_New_Item(void)
|
||||
{
|
||||
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
|
||||
if (node) memset(node,0,sizeof(cJSON));
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Delete a cJSON structure. */
|
||||
void cJSON_Delete(cJSON *c)
|
||||
{
|
||||
cJSON *next;
|
||||
while (c)
|
||||
{
|
||||
next=c->next;
|
||||
if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
|
||||
if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
|
||||
if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
|
||||
cJSON_free(c);
|
||||
c=next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the input text to generate a number, and populate the result into item. */
|
||||
static const char *parse_number(cJSON *item,const char *num)
|
||||
{
|
||||
double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
|
||||
|
||||
if (*num=='-') sign=-1,num++; /* Has sign? */
|
||||
if (*num=='0') num++; /* is zero */
|
||||
if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
|
||||
if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
|
||||
if (*num=='e' || *num=='E') /* Exponent? */
|
||||
{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
|
||||
while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
|
||||
}
|
||||
|
||||
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
|
||||
|
||||
item->valuedouble=n;
|
||||
item->valueint=(int)n;
|
||||
item->type=cJSON_Number;
|
||||
return num;
|
||||
}
|
||||
|
||||
static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; }
|
||||
|
||||
typedef struct {char *buffer; int length; int offset; } printbuffer;
|
||||
|
||||
static char* ensure(printbuffer *p,int needed)
|
||||
{
|
||||
char *newbuffer;int newsize;
|
||||
if (!p || !p->buffer) return 0;
|
||||
needed+=p->offset;
|
||||
if (needed<=p->length) return p->buffer+p->offset;
|
||||
|
||||
newsize=pow2gt(needed);
|
||||
newbuffer=(char*)cJSON_malloc(newsize);
|
||||
if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
|
||||
if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
|
||||
cJSON_free(p->buffer);
|
||||
p->length=newsize;
|
||||
p->buffer=newbuffer;
|
||||
return newbuffer+p->offset;
|
||||
}
|
||||
|
||||
static int update(printbuffer *p)
|
||||
{
|
||||
char *str;
|
||||
if (!p || !p->buffer) return 0;
|
||||
str=p->buffer+p->offset;
|
||||
return p->offset+strlen(str);
|
||||
}
|
||||
|
||||
/* Render the number nicely from the given item into a string. */
|
||||
static char *print_number(cJSON *item,printbuffer *p)
|
||||
{
|
||||
char *str=0;
|
||||
double d=item->valuedouble;
|
||||
if (d==0)
|
||||
{
|
||||
if (p) str=ensure(p,2);
|
||||
else str=(char*)cJSON_malloc(2); /* special case for 0. */
|
||||
if (str) strcpy(str,"0");
|
||||
}
|
||||
else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
|
||||
{
|
||||
if (p) str=ensure(p,21);
|
||||
else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
|
||||
if (str) sprintf(str,"%d",item->valueint);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p) str=ensure(p,64);
|
||||
else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
|
||||
if (str)
|
||||
{
|
||||
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
|
||||
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
|
||||
else sprintf(str,"%f",d);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static unsigned parse_hex4(const char *str)
|
||||
{
|
||||
unsigned h=0;
|
||||
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||
h=h<<4;str++;
|
||||
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||
h=h<<4;str++;
|
||||
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||
h=h<<4;str++;
|
||||
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Parse the input text into an unescaped cstring, and populate item. */
|
||||
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
{
|
||||
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
|
||||
if (*str!='\"') {ep=str;return 0;} /* not a string! */
|
||||
|
||||
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
|
||||
|
||||
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
|
||||
if (!out) return 0;
|
||||
|
||||
ptr=str+1;ptr2=out;
|
||||
while (*ptr!='\"' && *ptr)
|
||||
{
|
||||
if (*ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
ptr++;
|
||||
switch (*ptr)
|
||||
{
|
||||
case 'b': *ptr2++='\b'; break;
|
||||
case 'f': *ptr2++='\f'; break;
|
||||
case 'n': *ptr2++='\n'; break;
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': /* transcode utf16 to utf8. */
|
||||
uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
|
||||
|
||||
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
|
||||
|
||||
if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
|
||||
{
|
||||
if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
|
||||
uc2=parse_hex4(ptr+3);ptr+=6;
|
||||
if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
|
||||
uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
|
||||
}
|
||||
|
||||
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
|
||||
|
||||
switch (len) {
|
||||
case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 1: *--ptr2 =(uc | firstByteMark[len]);
|
||||
}
|
||||
ptr2+=len;
|
||||
break;
|
||||
default: *ptr2++=*ptr; break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
*ptr2=0;
|
||||
if (*ptr=='\"') ptr++;
|
||||
item->valuestring=out;
|
||||
item->type=cJSON_String;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Render the cstring provided to an escaped version that can be printed. */
|
||||
static char *print_string_ptr(const char *str,printbuffer *p)
|
||||
{
|
||||
const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
|
||||
|
||||
for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
|
||||
if (!flag)
|
||||
{
|
||||
len=ptr-str;
|
||||
if (p) out=ensure(p,len+3);
|
||||
else out=(char*)cJSON_malloc(len+3);
|
||||
if (!out) return 0;
|
||||
ptr2=out;*ptr2++='\"';
|
||||
strcpy(ptr2,str);
|
||||
ptr2[len]='\"';
|
||||
ptr2[len+1]=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
if (!str)
|
||||
{
|
||||
if (p) out=ensure(p,3);
|
||||
else out=(char*)cJSON_malloc(3);
|
||||
if (!out) return 0;
|
||||
strcpy(out,"\"\"");
|
||||
return out;
|
||||
}
|
||||
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
|
||||
|
||||
if (p) out=ensure(p,len+3);
|
||||
else out=(char*)cJSON_malloc(len+3);
|
||||
if (!out) return 0;
|
||||
|
||||
ptr2=out;ptr=str;
|
||||
*ptr2++='\"';
|
||||
while (*ptr)
|
||||
{
|
||||
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
*ptr2++='\\';
|
||||
switch (token=*ptr++)
|
||||
{
|
||||
case '\\': *ptr2++='\\'; break;
|
||||
case '\"': *ptr2++='\"'; break;
|
||||
case '\b': *ptr2++='b'; break;
|
||||
case '\f': *ptr2++='f'; break;
|
||||
case '\n': *ptr2++='n'; break;
|
||||
case '\r': *ptr2++='r'; break;
|
||||
case '\t': *ptr2++='t'; break;
|
||||
default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
|
||||
}
|
||||
}
|
||||
}
|
||||
*ptr2++='\"';*ptr2++=0;
|
||||
return out;
|
||||
}
|
||||
/* Invote print_string_ptr (which is useful) on an item. */
|
||||
static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);}
|
||||
|
||||
/* Predeclare these prototypes. */
|
||||
static const char *parse_value(cJSON *item,const char *value);
|
||||
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
|
||||
static const char *parse_array(cJSON *item,const char *value);
|
||||
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
|
||||
static const char *parse_object(cJSON *item,const char *value);
|
||||
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
|
||||
|
||||
/* Utility to jump whitespace and cr/lf */
|
||||
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
|
||||
|
||||
/* Parse an object - create a new root, and populate. */
|
||||
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
|
||||
{
|
||||
const char *end=0;
|
||||
cJSON *c=cJSON_New_Item();
|
||||
ep=0;
|
||||
if (!c) return 0; /* memory fail */
|
||||
|
||||
end=parse_value(c,skip(value));
|
||||
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
|
||||
|
||||
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
|
||||
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
|
||||
if (return_parse_end) *return_parse_end=end;
|
||||
return c;
|
||||
}
|
||||
/* Default options for cJSON_Parse */
|
||||
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
|
||||
|
||||
/* Render a cJSON item/entity/structure to text. */
|
||||
char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);}
|
||||
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);}
|
||||
|
||||
char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
|
||||
{
|
||||
printbuffer p;
|
||||
p.buffer=(char*)cJSON_malloc(prebuffer);
|
||||
p.length=prebuffer;
|
||||
p.offset=0;
|
||||
return print_value(item,0,fmt,&p);
|
||||
return p.buffer;
|
||||
}
|
||||
|
||||
|
||||
/* Parser core - when encountering text, process appropriately. */
|
||||
static const char *parse_value(cJSON *item,const char *value)
|
||||
{
|
||||
if (!value) return 0; /* Fail on null. */
|
||||
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
|
||||
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
|
||||
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
|
||||
if (*value=='\"') { return parse_string(item,value); }
|
||||
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
|
||||
if (*value=='[') { return parse_array(item,value); }
|
||||
if (*value=='{') { return parse_object(item,value); }
|
||||
|
||||
ep=value;return 0; /* failure. */
|
||||
}
|
||||
|
||||
/* Render a value to text. */
|
||||
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
|
||||
{
|
||||
char *out=0;
|
||||
if (!item) return 0;
|
||||
if (p)
|
||||
{
|
||||
switch ((item->type)&255)
|
||||
{
|
||||
case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;}
|
||||
case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;}
|
||||
case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;}
|
||||
case cJSON_Number: out=print_number(item,p);break;
|
||||
case cJSON_String: out=print_string(item,p);break;
|
||||
case cJSON_Array: out=print_array(item,depth,fmt,p);break;
|
||||
case cJSON_Object: out=print_object(item,depth,fmt,p);break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ((item->type)&255)
|
||||
{
|
||||
case cJSON_NULL: out=cJSON_strdup("null"); break;
|
||||
case cJSON_False: out=cJSON_strdup("false");break;
|
||||
case cJSON_True: out=cJSON_strdup("true"); break;
|
||||
case cJSON_Number: out=print_number(item,0);break;
|
||||
case cJSON_String: out=print_string(item,0);break;
|
||||
case cJSON_Array: out=print_array(item,depth,fmt,0);break;
|
||||
case cJSON_Object: out=print_object(item,depth,fmt,0);break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Build an array from input text. */
|
||||
static const char *parse_array(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='[') {ep=value;return 0;} /* not an array! */
|
||||
|
||||
item->type=cJSON_Array;
|
||||
value=skip(value+1);
|
||||
if (*value==']') return value+1; /* empty array. */
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0; /* memory fail */
|
||||
value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_value(child,skip(value+1)));
|
||||
if (!value) return 0; /* memory fail */
|
||||
}
|
||||
|
||||
if (*value==']') return value+1; /* end of array */
|
||||
ep=value;return 0; /* malformed. */
|
||||
}
|
||||
|
||||
/* Render an array to text */
|
||||
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
|
||||
{
|
||||
char **entries;
|
||||
char *out=0,*ptr,*ret;int len=5;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,i=0,fail=0;
|
||||
size_t tmplen=0;
|
||||
|
||||
/* How many entries in the array? */
|
||||
while (child) numentries++,child=child->next;
|
||||
/* Explicitly handle numentries==0 */
|
||||
if (!numentries)
|
||||
{
|
||||
if (p) out=ensure(p,3);
|
||||
else out=(char*)cJSON_malloc(3);
|
||||
if (out) strcpy(out,"[]");
|
||||
return out;
|
||||
}
|
||||
|
||||
if (p)
|
||||
{
|
||||
/* Compose the output array. */
|
||||
i=p->offset;
|
||||
ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++;
|
||||
child=item->child;
|
||||
while (child && !fail)
|
||||
{
|
||||
print_value(child,depth+1,fmt,p);
|
||||
p->offset=update(p);
|
||||
if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}
|
||||
child=child->next;
|
||||
}
|
||||
ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0;
|
||||
out=(p->buffer)+i;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Allocate an array to hold the values for each */
|
||||
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!entries) return 0;
|
||||
memset(entries,0,numentries*sizeof(char*));
|
||||
/* Retrieve all the results: */
|
||||
child=item->child;
|
||||
while (child && !fail)
|
||||
{
|
||||
ret=print_value(child,depth+1,fmt,0);
|
||||
entries[i++]=ret;
|
||||
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
|
||||
child=child->next;
|
||||
}
|
||||
|
||||
/* If we didn't fail, try to malloc the output string */
|
||||
if (!fail) out=(char*)cJSON_malloc(len);
|
||||
/* If that fails, we fail. */
|
||||
if (!out) fail=1;
|
||||
|
||||
/* Handle failure. */
|
||||
if (fail)
|
||||
{
|
||||
for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
|
||||
cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose the output array. */
|
||||
*out='[';
|
||||
ptr=out+1;*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
|
||||
if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
|
||||
cJSON_free(entries[i]);
|
||||
}
|
||||
cJSON_free(entries);
|
||||
*ptr++=']';*ptr++=0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Build an object from the text. */
|
||||
static const char *parse_object(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='{') {ep=value;return 0;} /* not an object! */
|
||||
|
||||
item->type=cJSON_Object;
|
||||
value=skip(value+1);
|
||||
if (*value=='}') return value+1; /* empty array. */
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0;
|
||||
value=skip(parse_string(child,skip(value)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_string(child,skip(value+1)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
}
|
||||
|
||||
if (*value=='}') return value+1; /* end of array */
|
||||
ep=value;return 0; /* malformed. */
|
||||
}
|
||||
|
||||
/* Render an object to text. */
|
||||
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
|
||||
{
|
||||
char **entries=0,**names=0;
|
||||
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,fail=0;
|
||||
size_t tmplen=0;
|
||||
/* Count the number of entries. */
|
||||
while (child) numentries++,child=child->next;
|
||||
/* Explicitly handle empty object case */
|
||||
if (!numentries)
|
||||
{
|
||||
if (p) out=ensure(p,fmt?depth+4:3);
|
||||
else out=(char*)cJSON_malloc(fmt?depth+4:3);
|
||||
if (!out) return 0;
|
||||
ptr=out;*ptr++='{';
|
||||
if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
|
||||
*ptr++='}';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
if (p)
|
||||
{
|
||||
/* Compose the output: */
|
||||
i=p->offset;
|
||||
len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0;
|
||||
*ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len;
|
||||
child=item->child;depth++;
|
||||
while (child)
|
||||
{
|
||||
if (fmt)
|
||||
{
|
||||
ptr=ensure(p,depth); if (!ptr) return 0;
|
||||
for (j=0;j<depth;j++) *ptr++='\t';
|
||||
p->offset+=depth;
|
||||
}
|
||||
print_string_ptr(child->string,p);
|
||||
p->offset=update(p);
|
||||
|
||||
len=fmt?2:1;
|
||||
ptr=ensure(p,len); if (!ptr) return 0;
|
||||
*ptr++=':';if (fmt) *ptr++='\t';
|
||||
p->offset+=len;
|
||||
|
||||
print_value(child,depth,fmt,p);
|
||||
p->offset=update(p);
|
||||
|
||||
len=(fmt?1:0)+(child->next?1:0);
|
||||
ptr=ensure(p,len+1); if (!ptr) return 0;
|
||||
if (child->next) *ptr++=',';
|
||||
if (fmt) *ptr++='\n';*ptr=0;
|
||||
p->offset+=len;
|
||||
child=child->next;
|
||||
}
|
||||
ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0;
|
||||
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||
*ptr++='}';*ptr=0;
|
||||
out=(p->buffer)+i;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Allocate space for the names and the objects */
|
||||
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!entries) return 0;
|
||||
names=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!names) {cJSON_free(entries);return 0;}
|
||||
memset(entries,0,sizeof(char*)*numentries);
|
||||
memset(names,0,sizeof(char*)*numentries);
|
||||
|
||||
/* Collect all the results into our arrays: */
|
||||
child=item->child;depth++;if (fmt) len+=depth;
|
||||
while (child)
|
||||
{
|
||||
names[i]=str=print_string_ptr(child->string,0);
|
||||
entries[i++]=ret=print_value(child,depth,fmt,0);
|
||||
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
|
||||
child=child->next;
|
||||
}
|
||||
|
||||
/* Try to allocate the output string */
|
||||
if (!fail) out=(char*)cJSON_malloc(len);
|
||||
if (!out) fail=1;
|
||||
|
||||
/* Handle failure */
|
||||
if (fail)
|
||||
{
|
||||
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose the output: */
|
||||
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
|
||||
tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
|
||||
*ptr++=':';if (fmt) *ptr++='\t';
|
||||
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
||||
if (i!=numentries-1) *ptr++=',';
|
||||
if (fmt) *ptr++='\n';*ptr=0;
|
||||
cJSON_free(names[i]);cJSON_free(entries[i]);
|
||||
}
|
||||
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||
*ptr++='}';*ptr++=0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Get Array size/item / object item. */
|
||||
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
|
||||
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
|
||||
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
|
||||
|
||||
/* Utility for array list handling. */
|
||||
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
|
||||
/* Utility for handling references. */
|
||||
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
|
||||
|
||||
/* Add item to array/object. */
|
||||
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
|
||||
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
|
||||
void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
|
||||
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
|
||||
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
|
||||
|
||||
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
|
||||
if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
|
||||
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
|
||||
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
|
||||
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
|
||||
|
||||
/* Replace array/object items with new ones. */
|
||||
void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}
|
||||
newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
|
||||
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
|
||||
newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
|
||||
if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
|
||||
void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
|
||||
|
||||
/* Create basic types: */
|
||||
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
|
||||
cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
|
||||
cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
|
||||
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
|
||||
cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
|
||||
cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
|
||||
|
||||
/* Create Arrays: */
|
||||
cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
|
||||
/* Duplication */
|
||||
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
|
||||
{
|
||||
cJSON *newitem,*cptr,*nptr=0,*newchild;
|
||||
/* Bail on bad ptr */
|
||||
if (!item) return 0;
|
||||
/* Create new item */
|
||||
newitem=cJSON_New_Item();
|
||||
if (!newitem) return 0;
|
||||
/* Copy over all vars */
|
||||
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
|
||||
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
|
||||
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
|
||||
/* If non-recursive, then we're done! */
|
||||
if (!recurse) return newitem;
|
||||
/* Walk the ->next chain for the child. */
|
||||
cptr=item->child;
|
||||
while (cptr)
|
||||
{
|
||||
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
|
||||
if (!newchild) {cJSON_Delete(newitem);return 0;}
|
||||
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
|
||||
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
|
||||
cptr=cptr->next;
|
||||
}
|
||||
return newitem;
|
||||
}
|
||||
|
||||
void cJSON_Minify(char *json)
|
||||
{
|
||||
char *into=json;
|
||||
while (*json)
|
||||
{
|
||||
if (*json==' ') json++;
|
||||
else if (*json=='\t') json++; /* Whitespace characters. */
|
||||
else if (*json=='\r') json++;
|
||||
else if (*json=='\n') json++;
|
||||
else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */
|
||||
else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */
|
||||
else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
|
||||
else *into++=*json++; /* All other characters. */
|
||||
}
|
||||
*into=0; /* and null-terminate. */
|
||||
}
|
395
components/json/port/cJSON_Utils.c
Normal file
395
components/json/port/cJSON_Utils.c
Normal file
@ -0,0 +1,395 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "cJSON_Utils.h"
|
||||
|
||||
static int cJSONUtils_strcasecmp(const char *s1,const char *s2)
|
||||
{
|
||||
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
|
||||
for(; tolower(*(const unsigned char *)s1) == tolower(*(const unsigned char *)s2); ++s1, ++s2) if(*s1 == 0) return 0;
|
||||
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
||||
}
|
||||
|
||||
/* JSON Pointer implementation: */
|
||||
static int cJSONUtils_Pstrcasecmp(const char *a,const char *e)
|
||||
{
|
||||
if (!a || !e) return (a==e)?0:1;
|
||||
for (;*a && *e && *e!='/';a++,e++) {
|
||||
if (*e=='~') {if (!(e[1]=='0' && *a=='~') && !(e[1]=='1' && *a=='/')) return 1; else e++;}
|
||||
else if (tolower(*(const unsigned char *)a)!=tolower(*(const unsigned char *)e)) return 1;
|
||||
}
|
||||
if ((*e!=0 && *e!='/') != (*a!=0)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cJSONUtils_PointerEncodedstrlen(const char *s) {int l=0;for (;*s;s++,l++) if (*s=='~' || *s=='/') l++;return l;}
|
||||
|
||||
static void cJSONUtils_PointerEncodedstrcpy(char *d,const char *s)
|
||||
{
|
||||
for (;*s;s++)
|
||||
{
|
||||
if (*s=='/') {*d++='~';*d++='1';}
|
||||
else if (*s=='~') {*d++='~';*d++='0';}
|
||||
else *d++=*s;
|
||||
}
|
||||
*d=0;
|
||||
}
|
||||
|
||||
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object,cJSON *target)
|
||||
{
|
||||
int type=object->type,c=0;cJSON *obj=0;
|
||||
|
||||
if (object==target) return strdup("");
|
||||
|
||||
for (obj=object->child;obj;obj=obj->next,c++)
|
||||
{
|
||||
char *found=cJSONUtils_FindPointerFromObjectTo(obj,target);
|
||||
if (found)
|
||||
{
|
||||
if (type==cJSON_Array)
|
||||
{
|
||||
char *ret=(char*)malloc(strlen(found)+23);
|
||||
sprintf(ret,"/%d%s",c,found);
|
||||
free(found);
|
||||
return ret;
|
||||
}
|
||||
else if (type==cJSON_Object)
|
||||
{
|
||||
char *ret=(char*)malloc(strlen(found)+cJSONUtils_PointerEncodedstrlen(obj->string)+2);
|
||||
*ret='/';cJSONUtils_PointerEncodedstrcpy(ret+1,obj->string);
|
||||
strcat(ret,found);
|
||||
free(found);
|
||||
return ret;
|
||||
}
|
||||
free(found);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cJSON *cJSONUtils_GetPointer(cJSON *object,const char *pointer)
|
||||
{
|
||||
while (*pointer++=='/' && object)
|
||||
{
|
||||
if (object->type==cJSON_Array)
|
||||
{
|
||||
int which=0; while (*pointer>='0' && *pointer<='9') which=(10*which) + *pointer++ - '0';
|
||||
if (*pointer && *pointer!='/') return 0;
|
||||
object=cJSON_GetArrayItem(object,which);
|
||||
}
|
||||
else if (object->type==cJSON_Object)
|
||||
{
|
||||
object=object->child; while (object && cJSONUtils_Pstrcasecmp(object->string,pointer)) object=object->next; /* GetObjectItem. */
|
||||
while (*pointer && *pointer!='/') pointer++;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/* JSON Patch implementation. */
|
||||
static void cJSONUtils_InplaceDecodePointerString(char *string)
|
||||
{
|
||||
char *s2=string;
|
||||
for (;*string;s2++,string++) *s2=(*string!='~')?(*string):((*(++string)=='0')?'~':'/');
|
||||
*s2=0;
|
||||
}
|
||||
|
||||
static cJSON *cJSONUtils_PatchDetach(cJSON *object,const char *path)
|
||||
{
|
||||
char *parentptr=0,*childptr=0;cJSON *parent=0,*ret=0;
|
||||
|
||||
parentptr=strdup(path); childptr=strrchr(parentptr,'/'); if (childptr) *childptr++=0;
|
||||
parent=cJSONUtils_GetPointer(object,parentptr);
|
||||
cJSONUtils_InplaceDecodePointerString(childptr);
|
||||
|
||||
if (!parent) ret=0; /* Couldn't find object to remove child from. */
|
||||
else if (parent->type==cJSON_Array) ret=cJSON_DetachItemFromArray(parent,atoi(childptr));
|
||||
else if (parent->type==cJSON_Object) ret=cJSON_DetachItemFromObject(parent,childptr);
|
||||
free(parentptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cJSONUtils_Compare(cJSON *a,cJSON *b)
|
||||
{
|
||||
if (a->type!=b->type) return -1; /* mismatched type. */
|
||||
switch (a->type)
|
||||
{
|
||||
case cJSON_Number: return (a->valueint!=b->valueint || a->valuedouble!=b->valuedouble)?-2:0; /* numeric mismatch. */
|
||||
case cJSON_String: return (strcmp(a->valuestring,b->valuestring)!=0)?-3:0; /* string mismatch. */
|
||||
case cJSON_Array: for (a=a->child,b=b->child;a && b;a=a->next,b=b->next) {int err=cJSONUtils_Compare(a,b);if (err) return err;}
|
||||
return (a || b)?-4:0; /* array size mismatch. */
|
||||
case cJSON_Object:
|
||||
cJSONUtils_SortObject(a);
|
||||
cJSONUtils_SortObject(b);
|
||||
a=a->child,b=b->child;
|
||||
while (a && b)
|
||||
{
|
||||
int err;
|
||||
if (cJSONUtils_strcasecmp(a->string,b->string)) return -6; /* missing member */
|
||||
err=cJSONUtils_Compare(a,b);if (err) return err;
|
||||
a=a->next,b=b->next;
|
||||
}
|
||||
return (a || b)?-5:0; /* object length mismatch */
|
||||
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cJSONUtils_ApplyPatch(cJSON *object,cJSON *patch)
|
||||
{
|
||||
cJSON *op=0,*path=0,*value=0,*parent=0;int opcode=0;char *parentptr=0,*childptr=0;
|
||||
|
||||
op=cJSON_GetObjectItem(patch,"op");
|
||||
path=cJSON_GetObjectItem(patch,"path");
|
||||
if (!op || !path) return 2; /* malformed patch. */
|
||||
|
||||
if (!strcmp(op->valuestring,"add")) opcode=0;
|
||||
else if (!strcmp(op->valuestring,"remove")) opcode=1;
|
||||
else if (!strcmp(op->valuestring,"replace"))opcode=2;
|
||||
else if (!strcmp(op->valuestring,"move")) opcode=3;
|
||||
else if (!strcmp(op->valuestring,"copy")) opcode=4;
|
||||
else if (!strcmp(op->valuestring,"test")) return cJSONUtils_Compare(cJSONUtils_GetPointer(object,path->valuestring),cJSON_GetObjectItem(patch,"value"));
|
||||
else return 3; /* unknown opcode. */
|
||||
|
||||
if (opcode==1 || opcode==2) /* Remove/Replace */
|
||||
{
|
||||
cJSON_Delete(cJSONUtils_PatchDetach(object,path->valuestring)); /* Get rid of old. */
|
||||
if (opcode==1) return 0; /* For Remove, this is job done. */
|
||||
}
|
||||
|
||||
if (opcode==3 || opcode==4) /* Copy/Move uses "from". */
|
||||
{
|
||||
cJSON *from=cJSON_GetObjectItem(patch,"from"); if (!from) return 4; /* missing "from" for copy/move. */
|
||||
|
||||
if (opcode==3) value=cJSONUtils_PatchDetach(object,from->valuestring);
|
||||
if (opcode==4) value=cJSONUtils_GetPointer(object,from->valuestring);
|
||||
if (!value) return 5; /* missing "from" for copy/move. */
|
||||
if (opcode==4) value=cJSON_Duplicate(value,1);
|
||||
if (!value) return 6; /* out of memory for copy/move. */
|
||||
}
|
||||
else /* Add/Replace uses "value". */
|
||||
{
|
||||
value=cJSON_GetObjectItem(patch,"value");
|
||||
if (!value) return 7; /* missing "value" for add/replace. */
|
||||
value=cJSON_Duplicate(value,1);
|
||||
if (!value) return 8; /* out of memory for add/replace. */
|
||||
}
|
||||
|
||||
/* Now, just add "value" to "path". */
|
||||
|
||||
parentptr=strdup(path->valuestring); childptr=strrchr(parentptr,'/'); if (childptr) *childptr++=0;
|
||||
parent=cJSONUtils_GetPointer(object,parentptr);
|
||||
cJSONUtils_InplaceDecodePointerString(childptr);
|
||||
|
||||
/* add, remove, replace, move, copy, test. */
|
||||
if (!parent) {free(parentptr); cJSON_Delete(value); return 9;} /* Couldn't find object to add to. */
|
||||
else if (parent->type==cJSON_Array)
|
||||
{
|
||||
if (!strcmp(childptr,"-")) cJSON_AddItemToArray(parent,value);
|
||||
else cJSON_InsertItemInArray(parent,atoi(childptr),value);
|
||||
}
|
||||
else if (parent->type==cJSON_Object)
|
||||
{
|
||||
cJSON_DeleteItemFromObject(parent,childptr);
|
||||
cJSON_AddItemToObject(parent,childptr,value);
|
||||
}
|
||||
else
|
||||
{
|
||||
cJSON_Delete(value);
|
||||
}
|
||||
free(parentptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cJSONUtils_ApplyPatches(cJSON *object,cJSON *patches)
|
||||
{
|
||||
int err;
|
||||
if (patches->type!=cJSON_Array) return 1; /* malformed patches. */
|
||||
if (patches) patches=patches->child;
|
||||
while (patches)
|
||||
{
|
||||
if ((err=cJSONUtils_ApplyPatch(object,patches))) return err;
|
||||
patches=patches->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cJSONUtils_GeneratePatch(cJSON *patches,const char *op,const char *path,const char *suffix,cJSON *val)
|
||||
{
|
||||
cJSON *patch=cJSON_CreateObject();
|
||||
cJSON_AddItemToObject(patch,"op",cJSON_CreateString(op));
|
||||
if (suffix)
|
||||
{
|
||||
char *newpath=(char*)malloc(strlen(path)+cJSONUtils_PointerEncodedstrlen(suffix)+2);
|
||||
cJSONUtils_PointerEncodedstrcpy(newpath+sprintf(newpath,"%s/",path),suffix);
|
||||
cJSON_AddItemToObject(patch,"path",cJSON_CreateString(newpath));
|
||||
free(newpath);
|
||||
}
|
||||
else cJSON_AddItemToObject(patch,"path",cJSON_CreateString(path));
|
||||
if (val) cJSON_AddItemToObject(patch,"value",cJSON_Duplicate(val,1));
|
||||
cJSON_AddItemToArray(patches,patch);
|
||||
}
|
||||
|
||||
void cJSONUtils_AddPatchToArray(cJSON *array,const char *op,const char *path,cJSON *val) {cJSONUtils_GeneratePatch(array,op,path,0,val);}
|
||||
|
||||
static void cJSONUtils_CompareToPatch(cJSON *patches,const char *path,cJSON *from,cJSON *to)
|
||||
{
|
||||
if (from->type!=to->type) {cJSONUtils_GeneratePatch(patches,"replace",path,0,to); return; }
|
||||
|
||||
switch (from->type)
|
||||
{
|
||||
case cJSON_Number:
|
||||
if (from->valueint!=to->valueint || from->valuedouble!=to->valuedouble)
|
||||
cJSONUtils_GeneratePatch(patches,"replace",path,0,to);
|
||||
return;
|
||||
|
||||
case cJSON_String:
|
||||
if (strcmp(from->valuestring,to->valuestring)!=0)
|
||||
cJSONUtils_GeneratePatch(patches,"replace",path,0,to);
|
||||
return;
|
||||
|
||||
case cJSON_Array:
|
||||
{
|
||||
int c;char *newpath=(char*)malloc(strlen(path)+23); /* Allow space for 64bit int. */
|
||||
for (c=0,from=from->child,to=to->child;from && to;from=from->next,to=to->next,c++){
|
||||
sprintf(newpath,"%s/%d",path,c); cJSONUtils_CompareToPatch(patches,newpath,from,to);
|
||||
}
|
||||
for (;from;from=from->next,c++) {sprintf(newpath,"%d",c); cJSONUtils_GeneratePatch(patches,"remove",path,newpath,0); }
|
||||
for (;to;to=to->next,c++) cJSONUtils_GeneratePatch(patches,"add",path,"-",to);
|
||||
free(newpath);
|
||||
return;
|
||||
}
|
||||
|
||||
case cJSON_Object:
|
||||
{
|
||||
cJSON *a,*b;
|
||||
cJSONUtils_SortObject(from);
|
||||
cJSONUtils_SortObject(to);
|
||||
|
||||
a=from->child,b=to->child;
|
||||
while (a || b)
|
||||
{
|
||||
int diff=(!a)?1:(!b)?-1:cJSONUtils_strcasecmp(a->string,b->string);
|
||||
if (!diff)
|
||||
{
|
||||
char *newpath=(char*)malloc(strlen(path)+cJSONUtils_PointerEncodedstrlen(a->string)+2);
|
||||
cJSONUtils_PointerEncodedstrcpy(newpath+sprintf(newpath,"%s/",path),a->string);
|
||||
cJSONUtils_CompareToPatch(patches,newpath,a,b);
|
||||
free(newpath);
|
||||
a=a->next;
|
||||
b=b->next;
|
||||
}
|
||||
else if (diff<0) {cJSONUtils_GeneratePatch(patches,"remove",path,a->string,0); a=a->next;}
|
||||
else {cJSONUtils_GeneratePatch(patches,"add",path,b->string,b); b=b->next;}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cJSON* cJSONUtils_GeneratePatches(cJSON *from,cJSON *to)
|
||||
{
|
||||
cJSON *patches=cJSON_CreateArray();
|
||||
cJSONUtils_CompareToPatch(patches,"",from,to);
|
||||
return patches;
|
||||
}
|
||||
|
||||
|
||||
static cJSON *cJSONUtils_SortList(cJSON *list)
|
||||
{
|
||||
cJSON *first=list,*second=list,*ptr=list;
|
||||
|
||||
if (!list || !list->next) return list; /* One entry is sorted already. */
|
||||
|
||||
while (ptr && ptr->next && cJSONUtils_strcasecmp(ptr->string,ptr->next->string)<0) ptr=ptr->next; /* Test for list sorted. */
|
||||
if (!ptr || !ptr->next) return list; /* Leave sorted lists unmodified. */
|
||||
ptr=list;
|
||||
|
||||
while (ptr) {second=second->next;ptr=ptr->next;if (ptr) ptr=ptr->next;} /* Walk two pointers to find the middle. */
|
||||
if (second && second->prev) second->prev->next=0; /* Split the lists */
|
||||
|
||||
first=cJSONUtils_SortList(first); /* Recursively sort the sub-lists. */
|
||||
second=cJSONUtils_SortList(second);
|
||||
list=ptr=0;
|
||||
|
||||
while (first && second) /* Merge the sub-lists */
|
||||
{
|
||||
if (cJSONUtils_strcasecmp(first->string,second->string)<0)
|
||||
{
|
||||
if (!list) list=ptr=first;
|
||||
else {ptr->next=first;first->prev=ptr;ptr=first;}
|
||||
first=first->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!list) list=ptr=second;
|
||||
else {ptr->next=second;second->prev=ptr;ptr=second;}
|
||||
second=second->next;
|
||||
}
|
||||
}
|
||||
if (first) { if (!list) return first; ptr->next=first; first->prev=ptr; } /* Append any tails. */
|
||||
if (second) { if (!list) return second; ptr->next=second; second->prev=ptr; }
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void cJSONUtils_SortObject(cJSON *object) {object->child=cJSONUtils_SortList(object->child);}
|
||||
|
||||
cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
|
||||
{
|
||||
if (!patch || patch->type != cJSON_Object) {cJSON_Delete(target);return cJSON_Duplicate(patch,1);}
|
||||
if (!target || target->type != cJSON_Object) {cJSON_Delete(target);target=cJSON_CreateObject();}
|
||||
|
||||
patch=patch->child;
|
||||
while (patch)
|
||||
{
|
||||
if (patch->type == cJSON_NULL) cJSON_DeleteItemFromObject(target,patch->string);
|
||||
else
|
||||
{
|
||||
cJSON *replaceme=cJSON_DetachItemFromObject(target,patch->string);
|
||||
cJSON_AddItemToObject(target,patch->string,cJSONUtils_MergePatch(replaceme,patch));
|
||||
}
|
||||
patch=patch->next;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
cJSON *cJSONUtils_GenerateMergePatch(cJSON *from,cJSON *to)
|
||||
{
|
||||
cJSON *patch=0;
|
||||
if (!to) return cJSON_CreateNull();
|
||||
if (to->type!=cJSON_Object || !from || from->type!=cJSON_Object) return cJSON_Duplicate(to,1);
|
||||
cJSONUtils_SortObject(from);
|
||||
cJSONUtils_SortObject(to);
|
||||
from=from->child;to=to->child;
|
||||
patch=cJSON_CreateObject();
|
||||
while (from || to)
|
||||
{
|
||||
int compare=from?(to?strcmp(from->string,to->string):-1):1;
|
||||
if (compare<0)
|
||||
{
|
||||
cJSON_AddItemToObject(patch,from->string,cJSON_CreateNull());
|
||||
from=from->next;
|
||||
}
|
||||
else if (compare>0)
|
||||
{
|
||||
cJSON_AddItemToObject(patch,to->string,cJSON_Duplicate(to,1));
|
||||
to=to->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cJSONUtils_Compare(from,to)) cJSON_AddItemToObject(patch,to->string,cJSONUtils_GenerateMergePatch(from,to));
|
||||
from=from->next;to=to->next;
|
||||
}
|
||||
}
|
||||
if (!patch->child) {cJSON_Delete(patch);return 0;}
|
||||
return patch;
|
||||
}
|
30
components/json/port/include/cJSON_Utils.h
Normal file
30
components/json/port/include/cJSON_Utils.h
Normal file
@ -0,0 +1,30 @@
|
||||
#include "cJSON.h"
|
||||
|
||||
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
|
||||
cJSON *cJSONUtils_GetPointer(cJSON *object,const char *pointer);
|
||||
|
||||
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
|
||||
cJSON* cJSONUtils_GeneratePatches(cJSON *from,cJSON *to);
|
||||
void cJSONUtils_AddPatchToArray(cJSON *array,const char *op,const char *path,cJSON *val); /* Utility for generating patch array entries. */
|
||||
int cJSONUtils_ApplyPatches(cJSON *object,cJSON *patches); /* Returns 0 for success. */
|
||||
|
||||
/*
|
||||
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
|
||||
//int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches)
|
||||
//{
|
||||
// cJSON *modme=cJSON_Duplicate(*object,1);
|
||||
// int error=cJSONUtils_ApplyPatches(modme,patches);
|
||||
// if (!error) {cJSON_Delete(*object);*object=modme;}
|
||||
// else cJSON_Delete(modme);
|
||||
// return error;
|
||||
//}
|
||||
// Code not added to library since this strategy is a LOT slower.
|
||||
*/
|
||||
|
||||
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
|
||||
cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch); /* target will be modified by patch. return value is new ptr for target. */
|
||||
cJSON *cJSONUtils_GenerateMergePatch(cJSON *from,cJSON *to); /* generates a patch to move from -> to */
|
||||
|
||||
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object,cJSON *target); /* Given a root object and a target object, construct a pointer from one to the other. */
|
||||
|
||||
void cJSONUtils_SortObject(cJSON *object); /* Sorts the members of the object into alphabetical order. */
|
@ -1,11 +0,0 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include/lwip include/lwip/port
|
||||
|
||||
COMPONENT_SRCDIRS := api apps core/ipv4 core/ipv6 core netif port/freertos port/netif port
|
||||
|
||||
EXTRA_CFLAGS := -Wno-error=address -Waddress -DLWIP_ESP8266
|
||||
|
||||
include $(IDF_PATH)/make/component.mk
|
@ -405,7 +405,7 @@ do{\
|
||||
|
||||
/** The global array of available sockets */
|
||||
static struct lwip_sock sockets[NUM_SOCKETS];
|
||||
#ifdef LWIP_THREAD_SAFE
|
||||
#if LWIP_THREAD_SAFE
|
||||
static bool sockets_init_flag = false;
|
||||
#endif
|
||||
/** The global list of tasks waiting for select */
|
||||
|
@ -62,7 +62,7 @@ static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
|
||||
|
||||
/* global variables */
|
||||
#ifdef PERF
|
||||
uint32 g_rx_post_mbox_fail_cnt = 0;
|
||||
uint32_t g_rx_post_mbox_fail_cnt = 0;
|
||||
#endif
|
||||
static tcpip_init_done_fn tcpip_init_done;
|
||||
static void *tcpip_init_done_arg;
|
||||
|
File diff suppressed because it is too large
Load Diff
716
components/lwip/apps/sntp/sntp.c
Normal file
716
components/lwip/apps/sntp/sntp.c
Normal file
@ -0,0 +1,716 @@
|
||||
/**
|
||||
* @file
|
||||
* SNTP client module
|
||||
*
|
||||
* This is simple "SNTP" client for the lwIP raw API.
|
||||
* It is a minimal implementation of SNTPv4 as specified in RFC 4330.
|
||||
*
|
||||
* For a list of some public NTP servers, see this link :
|
||||
* http://support.ntp.org/bin/view/Servers/NTPPoolServers
|
||||
*
|
||||
* @todo:
|
||||
* - set/change servers at runtime
|
||||
* - complete SNTP_CHECK_RESPONSE checks 3 and 4
|
||||
* - support broadcast/multicast mode?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
|
||||
* 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: Frédéric Bernon, Simon Goldschmidt
|
||||
*/
|
||||
|
||||
#include "apps/sntp/sntp.h"
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/timers.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/dhcp.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#if LWIP_UDP
|
||||
|
||||
/* Handle support for more than one server via SNTP_MAX_SERVERS */
|
||||
#if SNTP_MAX_SERVERS > 1
|
||||
#define SNTP_SUPPORT_MULTIPLE_SERVERS 1
|
||||
#else /* NTP_MAX_SERVERS > 1 */
|
||||
#define SNTP_SUPPORT_MULTIPLE_SERVERS 0
|
||||
#endif /* NTP_MAX_SERVERS > 1 */
|
||||
|
||||
#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK)
|
||||
#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
|
||||
#endif
|
||||
|
||||
/* Configure behaviour depending on microsecond or second precision */
|
||||
#ifdef SNTP_SET_SYSTEM_TIME_US
|
||||
#define SNTP_CALC_TIME_US 1
|
||||
#define SNTP_RECEIVE_TIME_SIZE 2
|
||||
#else
|
||||
#define SNTP_SET_SYSTEM_TIME_US(sec, us)
|
||||
#define SNTP_CALC_TIME_US 0
|
||||
#define SNTP_RECEIVE_TIME_SIZE 1
|
||||
#endif
|
||||
|
||||
|
||||
/* the various debug levels for this file */
|
||||
#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
|
||||
#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
|
||||
#define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
|
||||
#define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
|
||||
#define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
|
||||
|
||||
#define SNTP_ERR_KOD 1
|
||||
|
||||
/* SNTP protocol defines */
|
||||
#define SNTP_MSG_LEN 48
|
||||
|
||||
#define SNTP_OFFSET_LI_VN_MODE 0
|
||||
#define SNTP_LI_MASK 0xC0
|
||||
#define SNTP_LI_NO_WARNING 0x00
|
||||
#define SNTP_LI_LAST_MINUTE_61_SEC 0x01
|
||||
#define SNTP_LI_LAST_MINUTE_59_SEC 0x02
|
||||
#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */
|
||||
|
||||
#define SNTP_VERSION_MASK 0x38
|
||||
#define SNTP_VERSION (4/* NTP Version 4*/<<3)
|
||||
|
||||
#define SNTP_MODE_MASK 0x07
|
||||
#define SNTP_MODE_CLIENT 0x03
|
||||
#define SNTP_MODE_SERVER 0x04
|
||||
#define SNTP_MODE_BROADCAST 0x05
|
||||
|
||||
#define SNTP_OFFSET_STRATUM 1
|
||||
#define SNTP_STRATUM_KOD 0x00
|
||||
|
||||
#define SNTP_OFFSET_ORIGINATE_TIME 24
|
||||
#define SNTP_OFFSET_RECEIVE_TIME 32
|
||||
#define SNTP_OFFSET_TRANSMIT_TIME 40
|
||||
|
||||
/* number of seconds between 1900 and 1970 (MSB=1)*/
|
||||
#define DIFF_SEC_1900_1970 (2208988800UL)
|
||||
/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
|
||||
#define DIFF_SEC_1970_2036 (2085978496UL)
|
||||
|
||||
/**
|
||||
* SNTP packet format (without optional fields)
|
||||
* Timestamps are coded as 64 bits:
|
||||
* - 32 bits seconds since Jan 01, 1970, 00:00
|
||||
* - 32 bits seconds fraction (0-padded)
|
||||
* For future use, if the MSB in the seconds part is set, seconds are based
|
||||
* on Feb 07, 2036, 06:28:16.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct sntp_msg {
|
||||
PACK_STRUCT_FLD_8(u8_t li_vn_mode);
|
||||
PACK_STRUCT_FLD_8(u8_t stratum);
|
||||
PACK_STRUCT_FLD_8(u8_t poll);
|
||||
PACK_STRUCT_FLD_8(u8_t precision);
|
||||
PACK_STRUCT_FIELD(u32_t root_delay);
|
||||
PACK_STRUCT_FIELD(u32_t root_dispersion);
|
||||
PACK_STRUCT_FIELD(u32_t reference_identifier);
|
||||
PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
|
||||
PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
|
||||
PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
|
||||
PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* function prototypes */
|
||||
static void sntp_request(void *arg);
|
||||
|
||||
/** The operating mode */
|
||||
static u8_t sntp_opmode;
|
||||
|
||||
/** The UDP pcb used by the SNTP client */
|
||||
static struct udp_pcb* sntp_pcb;
|
||||
/** Names/Addresses of servers */
|
||||
struct sntp_server {
|
||||
#if SNTP_SERVER_DNS
|
||||
char* name;
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
ip_addr_t addr;
|
||||
};
|
||||
static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
|
||||
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP
|
||||
static u8_t sntp_set_servers_from_dhcp;
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||
#if SNTP_SUPPORT_MULTIPLE_SERVERS
|
||||
/** The currently used server (initialized to 0) */
|
||||
static u8_t sntp_current_server;
|
||||
#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
||||
#define sntp_current_server 0
|
||||
#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
||||
|
||||
#if SNTP_RETRY_TIMEOUT_EXP
|
||||
#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
|
||||
/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
|
||||
static u32_t sntp_retry_timeout;
|
||||
#else /* SNTP_RETRY_TIMEOUT_EXP */
|
||||
#define SNTP_RESET_RETRY_TIMEOUT()
|
||||
#define sntp_retry_timeout SNTP_RETRY_TIMEOUT
|
||||
#endif /* SNTP_RETRY_TIMEOUT_EXP */
|
||||
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/** Saves the last server address to compare with response */
|
||||
static ip_addr_t sntp_last_server_address;
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
/** Saves the last timestamp sent (which is sent back by the server)
|
||||
* to compare against in response */
|
||||
static u32_t sntp_last_timestamp_sent[2];
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
|
||||
/**
|
||||
* SNTP processing of received timestamp
|
||||
*/
|
||||
static void
|
||||
sntp_process(u32_t *receive_timestamp)
|
||||
{
|
||||
/* convert SNTP time (1900-based) to unix GMT time (1970-based)
|
||||
* if MSB is 0, SNTP time is 2036-based!
|
||||
*/
|
||||
u32_t rx_secs = ntohl(receive_timestamp[0]);
|
||||
int is_1900_based = ((rx_secs & 0x80000000) != 0);
|
||||
u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036);
|
||||
time_t tim = t;
|
||||
|
||||
#if SNTP_CALC_TIME_US
|
||||
u32_t us = ntohl(receive_timestamp[1]) / 4295;
|
||||
SNTP_SET_SYSTEM_TIME_US(t, us);
|
||||
/* display local time from GMT time */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us));
|
||||
|
||||
#else /* SNTP_CALC_TIME_US */
|
||||
|
||||
/* change system time and/or the update the RTC clock */
|
||||
SNTP_SET_SYSTEM_TIME(t);
|
||||
/* display local time from GMT time */
|
||||
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
|
||||
#endif /* SNTP_CALC_TIME_US */
|
||||
LWIP_UNUSED_ARG(tim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize request struct to be sent to server.
|
||||
*/
|
||||
static void
|
||||
sntp_initialize_request(struct sntp_msg *req)
|
||||
{
|
||||
memset(req, 0, SNTP_MSG_LEN);
|
||||
req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
|
||||
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
{
|
||||
u32_t sntp_time_sec, sntp_time_us;
|
||||
/* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
|
||||
SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
|
||||
sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970);
|
||||
req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
|
||||
/* we send/save us instead of fraction to be faster... */
|
||||
sntp_last_timestamp_sent[1] = htonl(sntp_time_us);
|
||||
req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
|
||||
}
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry: send a new request (and increase retry timeout).
|
||||
*
|
||||
* @param arg is unused (only necessary to conform to sys_timeout)
|
||||
*/
|
||||
static void
|
||||
sntp_retry(void* arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
|
||||
sntp_retry_timeout));
|
||||
|
||||
/* set up a timer to send a retry and increase the retry delay */
|
||||
sys_timeout(sntp_retry_timeout, sntp_request, NULL);
|
||||
|
||||
#if SNTP_RETRY_TIMEOUT_EXP
|
||||
{
|
||||
u32_t new_retry_timeout;
|
||||
/* increase the timeout for next retry */
|
||||
new_retry_timeout = sntp_retry_timeout << 1;
|
||||
/* limit to maximum timeout and prevent overflow */
|
||||
if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
|
||||
(new_retry_timeout > sntp_retry_timeout)) {
|
||||
sntp_retry_timeout = new_retry_timeout;
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_RETRY_TIMEOUT_EXP */
|
||||
}
|
||||
|
||||
#if SNTP_SUPPORT_MULTIPLE_SERVERS
|
||||
/**
|
||||
* If Kiss-of-Death is received (or another packet parsing error),
|
||||
* try the next server or retry the current server and increase the retry
|
||||
* timeout if only one server is available.
|
||||
* (implicitly, SNTP_MAX_SERVERS > 1)
|
||||
*
|
||||
* @param arg is unused (only necessary to conform to sys_timeout)
|
||||
*/
|
||||
static void
|
||||
sntp_try_next_server(void* arg)
|
||||
{
|
||||
u8_t old_server, i;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
old_server = sntp_current_server;
|
||||
for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
|
||||
sntp_current_server++;
|
||||
if (sntp_current_server >= SNTP_MAX_SERVERS) {
|
||||
sntp_current_server = 0;
|
||||
}
|
||||
if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
|
||||
#if SNTP_SERVER_DNS
|
||||
|| (sntp_servers[sntp_current_server].name != NULL)
|
||||
#endif
|
||||
) {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
|
||||
(u16_t)sntp_current_server));
|
||||
/* new server: reset retry timeout */
|
||||
SNTP_RESET_RETRY_TIMEOUT();
|
||||
/* instantly send a request to the next server */
|
||||
sntp_request(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* no other valid server found */
|
||||
sntp_current_server = old_server;
|
||||
sntp_retry(NULL);
|
||||
}
|
||||
#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
||||
/* Always retry on error if only one server is supported */
|
||||
#define sntp_try_next_server sntp_retry
|
||||
#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
||||
|
||||
/** UDP recv callback for the sntp pcb */
|
||||
static void
|
||||
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
u8_t mode;
|
||||
u8_t stratum;
|
||||
u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
|
||||
err_t err;
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
|
||||
/* packet received: stop retry timeout */
|
||||
sys_untimeout(sntp_try_next_server, NULL);
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
|
||||
err = ERR_ARG;
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/* check server address and port */
|
||||
if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
|
||||
(port == SNTP_PORT))
|
||||
#else /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
LWIP_UNUSED_ARG(addr);
|
||||
LWIP_UNUSED_ARG(port);
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
{
|
||||
/* process the response */
|
||||
if (p->tot_len == SNTP_MSG_LEN) {
|
||||
pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);
|
||||
mode &= SNTP_MODE_MASK;
|
||||
/* if this is a SNTP response... */
|
||||
if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
|
||||
((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
|
||||
pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);
|
||||
if (stratum == SNTP_STRATUM_KOD) {
|
||||
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
||||
err = SNTP_ERR_KOD;
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
|
||||
} else {
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
/* check originate_timetamp against sntp_last_timestamp_sent */
|
||||
u32_t originate_timestamp[2];
|
||||
pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);
|
||||
if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||
|
||||
(originate_timestamp[1] != sntp_last_timestamp_sent[1]))
|
||||
{
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n"));
|
||||
} else
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
/* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
|
||||
{
|
||||
/* correct answer */
|
||||
err = ERR_OK;
|
||||
pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
|
||||
/* wait for correct response */
|
||||
err = ERR_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
|
||||
}
|
||||
}
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
else {
|
||||
/* packet from wrong remote address or port, wait for correct response */
|
||||
err = ERR_TIMEOUT;
|
||||
}
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
pbuf_free(p);
|
||||
if (err == ERR_OK) {
|
||||
sntp_process(receive_timestamp);
|
||||
|
||||
/* Set up timeout for next request (only if poll response was received)*/
|
||||
if (sntp_opmode == SNTP_OPMODE_POLL) {
|
||||
/* Correct response, reset retry timeout */
|
||||
SNTP_RESET_RETRY_TIMEOUT();
|
||||
|
||||
sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
|
||||
(u32_t)SNTP_UPDATE_DELAY));
|
||||
}
|
||||
} else if (err != ERR_TIMEOUT) {
|
||||
/* Errors are only processed in case of an explicit poll response */
|
||||
if (sntp_opmode == SNTP_OPMODE_POLL) {
|
||||
if (err == SNTP_ERR_KOD) {
|
||||
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
||||
sntp_try_next_server(NULL);
|
||||
} else {
|
||||
/* another error, try the same server again */
|
||||
sntp_retry(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually send an sntp request to a server.
|
||||
*
|
||||
* @param server_addr resolved IP address of the SNTP server
|
||||
*/
|
||||
static void
|
||||
sntp_send_request(const ip_addr_t *server_addr)
|
||||
{
|
||||
struct pbuf* p;
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
||||
if (p != NULL) {
|
||||
struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
|
||||
/* initialize request message */
|
||||
sntp_initialize_request(sntpmsg);
|
||||
/* send request */
|
||||
udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
|
||||
/* free the pbuf after sending it */
|
||||
pbuf_free(p);
|
||||
/* set up receive timeout: try next server or retry on timeout */
|
||||
sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/* save server address to verify it in sntp_recv */
|
||||
ip_addr_set(&sntp_last_server_address, server_addr);
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
} else {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
|
||||
(u32_t)SNTP_RETRY_TIMEOUT));
|
||||
/* out of memory: set up a timer to send a retry */
|
||||
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#if SNTP_SERVER_DNS
|
||||
/**
|
||||
* DNS found callback when using DNS names as server address.
|
||||
*/
|
||||
static void
|
||||
sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(hostname);
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
if (ipaddr != NULL) {
|
||||
/* Address resolved, send request */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
|
||||
sntp_send_request(ipaddr);
|
||||
} else {
|
||||
/* DNS resolving failed -> try another server */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
|
||||
sntp_try_next_server(NULL);
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
|
||||
/**
|
||||
* Send out an sntp request.
|
||||
*
|
||||
* @param arg is unused (only necessary to conform to sys_timeout)
|
||||
*/
|
||||
static void
|
||||
sntp_request(void *arg)
|
||||
{
|
||||
ip_addr_t sntp_server_address;
|
||||
err_t err;
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
/* initialize SNTP server address */
|
||||
#if SNTP_SERVER_DNS
|
||||
if (sntp_servers[sntp_current_server].name) {
|
||||
/* always resolve the name and rely on dns-internal caching & timeout */
|
||||
ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
|
||||
err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
|
||||
sntp_dns_found, NULL);
|
||||
if (err == ERR_INPROGRESS) {
|
||||
/* DNS request sent, wait for sntp_dns_found being called */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
|
||||
return;
|
||||
} else if (err == ERR_OK) {
|
||||
sntp_servers[sntp_current_server].addr = sntp_server_address;
|
||||
}
|
||||
} else
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
{
|
||||
sntp_server_address = sntp_servers[sntp_current_server].addr;
|
||||
err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
|
||||
}
|
||||
|
||||
if (err == ERR_OK) {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
|
||||
ipaddr_ntoa(&sntp_server_address)));
|
||||
sntp_send_request(&sntp_server_address);
|
||||
} else {
|
||||
/* address conversion failed, try another server */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
|
||||
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this module.
|
||||
* Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
|
||||
*/
|
||||
void
|
||||
sntp_init(void)
|
||||
{
|
||||
#ifdef SNTP_SERVER_ADDRESS
|
||||
#if SNTP_SERVER_DNS
|
||||
sntp_setservername(0, SNTP_SERVER_ADDRESS);
|
||||
#else
|
||||
#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
|
||||
#endif
|
||||
#endif /* SNTP_SERVER_ADDRESS */
|
||||
|
||||
if (sntp_pcb == NULL) {
|
||||
sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
|
||||
if (sntp_pcb != NULL) {
|
||||
udp_recv(sntp_pcb, sntp_recv, NULL);
|
||||
|
||||
if (sntp_opmode == SNTP_OPMODE_POLL) {
|
||||
SNTP_RESET_RETRY_TIMEOUT();
|
||||
#if SNTP_STARTUP_DELAY
|
||||
sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
|
||||
#else
|
||||
sntp_request(NULL);
|
||||
#endif
|
||||
} else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
|
||||
ip_set_option(sntp_pcb, SOF_BROADCAST);
|
||||
udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop this module.
|
||||
*/
|
||||
void
|
||||
sntp_stop(void)
|
||||
{
|
||||
if (sntp_pcb != NULL) {
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
udp_remove(sntp_pcb);
|
||||
sntp_pcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enabled state.
|
||||
*/
|
||||
u8_t sntp_enabled(void)
|
||||
{
|
||||
return (sntp_pcb != NULL)? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the operating mode.
|
||||
* @param operating_mode one of the available operating modes
|
||||
*/
|
||||
void
|
||||
sntp_setoperatingmode(u8_t operating_mode)
|
||||
{
|
||||
LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
|
||||
LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
|
||||
sntp_opmode = operating_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operating mode.
|
||||
*/
|
||||
u8_t
|
||||
sntp_getoperatingmode(void)
|
||||
{
|
||||
return sntp_opmode;
|
||||
}
|
||||
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP
|
||||
/**
|
||||
* Config SNTP server handling by IP address, name, or DHCP; clear table
|
||||
* @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
|
||||
*/
|
||||
void
|
||||
sntp_servermode_dhcp(int set_servers_from_dhcp)
|
||||
{
|
||||
u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
|
||||
if (sntp_set_servers_from_dhcp != new_mode) {
|
||||
sntp_set_servers_from_dhcp = new_mode;
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||
|
||||
/**
|
||||
* Initialize one of the NTP servers by IP address
|
||||
*
|
||||
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param dnsserver IP address of the NTP server to set
|
||||
*/
|
||||
void
|
||||
sntp_setserver(u8_t idx, const ip_addr_t *server)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
if (server != NULL) {
|
||||
sntp_servers[idx].addr = (*server);
|
||||
} else {
|
||||
ip_addr_set_zero(&sntp_servers[idx].addr);
|
||||
}
|
||||
#if SNTP_SERVER_DNS
|
||||
sntp_servers[idx].name = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
|
||||
/**
|
||||
* Initialize one of the NTP servers by IP address, required by DHCP
|
||||
*
|
||||
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param dnsserver IP address of the NTP server to set
|
||||
*/
|
||||
void
|
||||
dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
|
||||
{
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
|
||||
(sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
|
||||
ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
|
||||
if (sntp_set_servers_from_dhcp && num) {
|
||||
u8_t i;
|
||||
for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
|
||||
ip_addr_t addr;
|
||||
ip_addr_copy_from_ip4(addr, server[i]);
|
||||
sntp_setserver(i, &addr);
|
||||
}
|
||||
for (i = num; i < SNTP_MAX_SERVERS; i++) {
|
||||
sntp_setserver(i, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
|
||||
|
||||
/**
|
||||
* Obtain one of the currently configured by IP address (or DHCP) NTP servers
|
||||
*
|
||||
* @param numdns the index of the NTP server
|
||||
* @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
|
||||
* server has not been configured by address (or at all).
|
||||
*/
|
||||
ip_addr_t
|
||||
sntp_getserver(u8_t idx)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
return sntp_servers[idx].addr;
|
||||
}
|
||||
return *IP_ADDR_ANY;
|
||||
}
|
||||
|
||||
#if SNTP_SERVER_DNS
|
||||
/**
|
||||
* Initialize one of the NTP servers by name
|
||||
*
|
||||
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param dnsserver DNS name of the NTP server to set, to be resolved at contact time
|
||||
*/
|
||||
void
|
||||
sntp_setservername(u8_t idx, char *server)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
sntp_servers[idx].name = server;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain one of the currently configured by name NTP servers.
|
||||
*
|
||||
* @param numdns the index of the NTP server
|
||||
* @return IP address of the indexed NTP server or NULL if the NTP
|
||||
* server has not been configured by name (or at all)
|
||||
*/
|
||||
char *
|
||||
sntp_getservername(u8_t idx)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
return sntp_servers[idx].name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
|
||||
#endif /* LWIP_UDP */
|
||||
|
11
components/lwip/component.mk
Normal file
11
components/lwip/component.mk
Normal file
@ -0,0 +1,11 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include/lwip include/lwip/port
|
||||
|
||||
COMPONENT_SRCDIRS := api apps/sntp apps core/ipv4 core/ipv6 core netif port/freertos port/netif port
|
||||
|
||||
EXTRA_CFLAGS := -Wno-error=address -Waddress
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
@ -459,7 +459,7 @@ dhcp_fine_tmr(void)
|
||||
#if 0
|
||||
if (DHCP_MAXRTX != 0) {
|
||||
if (netif->dhcp->tries >= DHCP_MAXRTX){
|
||||
//os_printf("DHCP timeout\n");
|
||||
//printf("DHCP timeout\n");
|
||||
if (netif->dhcp_event != NULL)
|
||||
netif->dhcp_event();
|
||||
break;
|
||||
@ -710,6 +710,24 @@ void dhcp_cleanup(struct netif *netif)
|
||||
}
|
||||
}
|
||||
|
||||
/* Espressif add start. */
|
||||
|
||||
/** Set callback for dhcp, reversed parameter for future use.
|
||||
*
|
||||
* @param netif the netif from which to remove the struct dhcp
|
||||
* @param cb callback for chcp
|
||||
*/
|
||||
void dhcp_set_cb(struct netif *netif, void (*cb)(void))
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||
|
||||
if (netif->dhcp != NULL) {
|
||||
netif->dhcp->cb = cb;
|
||||
}
|
||||
}
|
||||
|
||||
/* Espressif add end. */
|
||||
|
||||
/**
|
||||
* Start DHCP negotiation for a network interface.
|
||||
*
|
||||
@ -1117,32 +1135,19 @@ dhcp_bind(struct netif *netif)
|
||||
}
|
||||
#endif /* LWIP_DHCP_AUTOIP_COOP */
|
||||
|
||||
/* Espressif add start. */
|
||||
/* back up old ip/netmask/gw */
|
||||
ip4_addr_t ip, mask, gw;
|
||||
ip4_addr_set(&ip, ip_2_ip4(&netif->ip_addr));
|
||||
ip4_addr_set(&mask, ip_2_ip4(&netif->netmask));
|
||||
ip4_addr_set(&gw, ip_2_ip4(&netif->gw));
|
||||
/* Espressif add end. */
|
||||
|
||||
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F" SN: 0x%08"X32_F" GW: 0x%08"X32_F"\n",
|
||||
ip4_addr_get_u32(&dhcp->offered_ip_addr), ip4_addr_get_u32(&sn_mask), ip4_addr_get_u32(&gw_addr)));
|
||||
netif_set_addr(netif, &dhcp->offered_ip_addr, &sn_mask, &gw_addr);
|
||||
/* interface is used by routing now that an address is set */
|
||||
|
||||
#ifdef LWIP_ESP8266
|
||||
/* use old ip/mask/gw to check whether ip/mask/gw changed */
|
||||
// extern void system_station_got_ip_set(ip4_addr_t *ip, ip4_addr_t *mask, ip4_addr_t *gw);
|
||||
// system_station_got_ip_set(&ip, &mask, &gw);
|
||||
#endif
|
||||
|
||||
/* use old ip/mask/gw to check whether ip/mask/gw changed */
|
||||
// extern void system_station_got_ip_set(ip4_addr_t *ip, ip4_addr_t *mask, ip4_addr_t *gw);
|
||||
// system_station_got_ip_set(&ip, &mask, &gw);
|
||||
|
||||
/* netif is now bound to DHCP leased address */
|
||||
dhcp_set_state(dhcp, DHCP_STATE_BOUND);
|
||||
|
||||
/* Espressif add start. */
|
||||
if (dhcp->cb != NULL) {
|
||||
dhcp->cb();
|
||||
}
|
||||
/* Espressif add end. */
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1539,7 +1544,7 @@ again:
|
||||
break;
|
||||
case(DHCP_OPTION_DNS_SERVER):
|
||||
/* special case: there might be more than one server */
|
||||
LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;);
|
||||
//LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;);
|
||||
/* limit number of DNS servers */
|
||||
decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
|
||||
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
|
||||
@ -1595,7 +1600,7 @@ decode_next:
|
||||
pbuf_copy_partial(q, &value, copy_len, val_offset);
|
||||
if (decode_len > 4) {
|
||||
/* decode more than one u32_t */
|
||||
LWIP_ERROR("decode_len % 4 == 0", decode_len % 4 == 0, return ERR_VAL;);
|
||||
//LWIP_ERROR("decode_len % 4 == 0", decode_len % 4 == 0, return ERR_VAL;);
|
||||
dhcp_got_option(dhcp, decode_idx);
|
||||
dhcp_set_option_value(dhcp, decode_idx, htonl(value));
|
||||
decode_len -= 4;
|
||||
|
@ -315,14 +315,6 @@ netif_add(struct netif *netif,
|
||||
return netif;
|
||||
}
|
||||
|
||||
typedef int (*netif_addr_change_cb_t)(struct netif *netif);
|
||||
static netif_addr_change_cb_t g_netif_addr_change_cb = NULL;
|
||||
|
||||
void netif_reg_addr_change_cb(void *cb)
|
||||
{
|
||||
g_netif_addr_change_cb = (netif_addr_change_cb_t)cb;
|
||||
}
|
||||
|
||||
#if LWIP_IPV4
|
||||
/**
|
||||
* Change IP address configuration for a network interface (including netmask
|
||||
@ -341,9 +333,6 @@ netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *
|
||||
netif_set_gw(netif, gw);
|
||||
/* set ipaddr last to ensure netmask/gw have been set when status callback is called */
|
||||
netif_set_ipaddr(netif, ipaddr);
|
||||
if (g_netif_addr_change_cb){
|
||||
g_netif_addr_change_cb(netif);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4*/
|
||||
|
@ -17,17 +17,6 @@
|
||||
#include "lwip/ip_addr.h"
|
||||
//#include "esp_common.h"
|
||||
#define USE_DNS
|
||||
/* Here for now until needed in other places in lwIP */
|
||||
#ifndef isprint
|
||||
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
|
||||
#define isprint(c) in_range(c, 0x20, 0x7f)
|
||||
#define isdigit(c) in_range(c, '0', '9')
|
||||
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
|
||||
#define islower(c) in_range(c, 'a', 'z')
|
||||
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
|
||||
#endif
|
||||
|
||||
#ifdef LWIP_ESP8266
|
||||
|
||||
typedef struct dhcps_state{
|
||||
s16_t state;
|
||||
@ -47,220 +36,6 @@ typedef struct dhcps_msg {
|
||||
u8_t options[312];
|
||||
}dhcps_msg;
|
||||
|
||||
struct dhcps_lease {
|
||||
bool enable;
|
||||
ip4_addr_t start_ip;
|
||||
ip4_addr_t end_ip;
|
||||
};
|
||||
|
||||
enum dhcps_offer_option{
|
||||
OFFER_START = 0x00,
|
||||
OFFER_ROUTER = 0x01,
|
||||
OFFER_END
|
||||
};
|
||||
|
||||
struct dhcps_pool{
|
||||
ip4_addr_t ip;
|
||||
u8_t mac[6];
|
||||
u32_t lease_timer;
|
||||
};
|
||||
|
||||
typedef struct _list_node{
|
||||
void *pnode;
|
||||
struct _list_node *pnext;
|
||||
}list_node;
|
||||
|
||||
extern u32_t dhcps_lease_time;
|
||||
#define DHCPS_LEASE_TIMER dhcps_lease_time //0x05A0
|
||||
|
||||
#define dhcps_router_enabled(offer) ((offer & OFFER_ROUTER) != 0)
|
||||
void dhcps_start(struct netif *netif);
|
||||
void dhcps_stop(struct netif *netif);
|
||||
|
||||
#else
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
/** DHCP DEBUG INFO **/
|
||||
#define DHCPS_DEBUG 1
|
||||
#if DHCPS_DEBUG
|
||||
#define log_info(message, ...) do { \
|
||||
os_printf((message), ##__VA_ARGS__); \
|
||||
os_printf("\n"); \
|
||||
} while(0);
|
||||
|
||||
#else
|
||||
#define log_info(message, ...)
|
||||
#endif
|
||||
|
||||
#if (!defined(unlikely))
|
||||
#define unlikely(Expression) !!(Expression)
|
||||
#endif
|
||||
|
||||
#define REQUIRE_ASSERT(Expression) do{if (!(Expression)) log_info("%d\n", __LINE__);}while(0)
|
||||
|
||||
#define REQUIRE_ACTION(Expression,Label,Action) \
|
||||
do{\
|
||||
if (unlikely(!(Expression))) \
|
||||
{\
|
||||
log_info("%d\n", __LINE__);\
|
||||
{Action;}\
|
||||
goto Label;\
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
#define REQUIRE_NOERROR(Expression,Label) \
|
||||
do{\
|
||||
int LocalError;\
|
||||
LocalError = (int)Expression;\
|
||||
if (unlikely(LocalError != 0)) \
|
||||
{\
|
||||
log_info("%d 0x%x\n", __LINE__, LocalError);\
|
||||
goto Label;\
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
#define REQUIRE_NOERROR_ACTION(Expression,Label,Action) \
|
||||
do{\
|
||||
int LocalError;\
|
||||
LocalError = (int)Expression;\
|
||||
if (unlikely(LocalError != 0)) \
|
||||
{\
|
||||
log_info("%d\n", __LINE__);\
|
||||
{Action;}\
|
||||
goto Label;\
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
#define DHCP_OK 0
|
||||
#define DHCP_FAIL -1
|
||||
#define DHCP_SERVER_OPENDNS 0xd043dede /* OpenDNS DNS server 208.67.222.222 */
|
||||
|
||||
/* DHCP message */
|
||||
/*
|
||||
* Code ID of DHCP and BOOTP options
|
||||
* as defined in RFC 2132
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
DHCP_NONE = 0,
|
||||
DHCPS_DISCOVER = 1,
|
||||
DHCPS_OFFER = 2,
|
||||
DHCPS_REQUEST = 3,
|
||||
DHCPS_DECLINE = 4,
|
||||
DHCPS_ACK = 5,
|
||||
DHCPS_NAK = 6,
|
||||
DHCPS_RELEASE = 7,
|
||||
DHCPS_INFORM = 8,
|
||||
DHCP_FORCE_RENEW = 9,
|
||||
DHCP_LEASE_QUERY = 10,
|
||||
DHCP_LEASE_UNASSIGNED = 11,
|
||||
DHCP_LEASE_UNKNOWN = 12,
|
||||
DHCP_LEASE_ACTIVE = 13,
|
||||
} dhcp_msg_type;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BOOTPS = 67,
|
||||
BOOTPC = 68
|
||||
} ports;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BOOTREQUEST = 1,
|
||||
BOOTREPLY = 2,
|
||||
} op_types;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ETHERNET = 0x01,
|
||||
ETHERNET_LAN = 0x06,
|
||||
ETHEFDDI = 0x08,
|
||||
ETHEIEEE1394 = 0x18
|
||||
} hardware_types;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DHCPS_CHADDR_LEN = 16U,
|
||||
DHCPS_SNAME_LEN = 64U,
|
||||
DHCPS_FILE_LEN = 128U,
|
||||
DHCP_HEADER_SIZE = 236U // without size of options
|
||||
} head_size;
|
||||
|
||||
typedef struct dhcps
|
||||
{
|
||||
/** transaction identifier of last sent request */
|
||||
u32_t xid;
|
||||
/** incoming msg */
|
||||
struct dhcps_msg *msg_in;
|
||||
/** track PCB allocation state */
|
||||
u8_t pcb_allocated;
|
||||
/** current DHCP state machine state */
|
||||
u8_t state;
|
||||
/** retries of current request */
|
||||
u8_t tries;
|
||||
#if LWIP_DHCP_AUTOIP_COOP
|
||||
u8_t autoip_coop_state;
|
||||
#endif
|
||||
u8_t subnet_mask_given;
|
||||
|
||||
struct pbuf *p_out; /* pbuf of outcoming msg */
|
||||
struct dhcp_msg *msg_out; /* outgoing msg */
|
||||
u16_t options_out_len; /* outgoing msg options length */
|
||||
u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
|
||||
u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
|
||||
u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
|
||||
u16_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */
|
||||
u16_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */
|
||||
u16_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */
|
||||
u16_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */
|
||||
ip_addr_t server_ip_addr; /* dhcp server address that offered this lease (ip_addr_t because passed to UDP) */
|
||||
ip4_addr_t offered_ip_addr;
|
||||
ip4_addr_t offered_sn_mask;
|
||||
ip4_addr_t offered_gw_addr;
|
||||
|
||||
u32_t offered_t0_lease; /* lease period (in seconds) */
|
||||
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
|
||||
u32_t offered_t2_rebind; /* recommended rebind time (usually 87.5 of lease period) */
|
||||
#if LWIP_DHCP_BOOTP_FILE
|
||||
ip_addr_t offered_si_addr;
|
||||
char boot_file_name[DHCP_FILE_LEN];
|
||||
#endif /* LWIP_DHCP_BOOTPFILE */
|
||||
|
||||
} dhcps;
|
||||
|
||||
typedef struct dhcp_message
|
||||
{
|
||||
PACK_STRUCT_FLD_8(u8_t op);
|
||||
PACK_STRUCT_FLD_8(u8_t htype);
|
||||
PACK_STRUCT_FLD_8(u8_t hlen);
|
||||
PACK_STRUCT_FLD_8(u8_t hops);
|
||||
PACK_STRUCT_FIELD(u32_t xid);
|
||||
PACK_STRUCT_FIELD(u16_t secs);
|
||||
PACK_STRUCT_FIELD(u16_t flags);
|
||||
PACK_STRUCT_FLD_S(ip4_addr_p_t ciaddr);
|
||||
PACK_STRUCT_FLD_S(ip4_addr_p_t yiaddr);
|
||||
PACK_STRUCT_FLD_S(ip4_addr_p_t siaddr);
|
||||
PACK_STRUCT_FLD_S(ip4_addr_p_t giaddr);
|
||||
PACK_STRUCT_FLD_8(u8_t chaddr[DHCPS_CHADDR_LEN]);
|
||||
PACK_STRUCT_FLD_8(u8_t sname[DHCPS_SNAME_LEN]);
|
||||
PACK_STRUCT_FLD_8(u8_t file[DHCPS_FILE_LEN]);
|
||||
// PACK_STRUCT_FIELD(u32_t cookie);
|
||||
#define DHCPS_MIN_OPTIONS_LEN 312U
|
||||
/** make sure user does not configure this too small */
|
||||
#if ((defined(DHCPS_OPTIONS_LEN)) && (DHCPS_OPTIONS_LEN < DHCPS_MIN_OPTIONS_LEN))
|
||||
#undef DHCPS_OPTIONS_LEN
|
||||
#endif
|
||||
/** allow this to be configured in lwipopts.h, but not too small */
|
||||
#if (!defined(DHCPS_OPTIONS_LEN))
|
||||
/** set this to be sufficient for your options in outgoing DHCP msgs */
|
||||
#define DHCPS_OPTIONS_LEN DHCPS_MIN_OPTIONS_LEN
|
||||
#endif
|
||||
PACK_STRUCT_FLD_8(u8_t options[DHCPS_OPTIONS_LEN]);
|
||||
} dhcp_message;
|
||||
|
||||
/** DHCP OPTIONS CODE **/
|
||||
typedef enum
|
||||
{
|
||||
@ -378,117 +153,48 @@ typedef enum
|
||||
CLASSLESS_ROUTE = 121,
|
||||
} dhcp_msg_option;
|
||||
|
||||
typedef struct dhcp_option
|
||||
{
|
||||
uint8_t id; // option id
|
||||
uint8_t len; // option length
|
||||
uint8_t data[256]; // option data
|
||||
/* Defined in esp_misc.h */
|
||||
typedef struct {
|
||||
bool enable;
|
||||
ip4_addr_t start_ip;
|
||||
ip4_addr_t end_ip;
|
||||
} dhcps_lease_t;
|
||||
|
||||
STAILQ_ENTRY(dhcp_option) pointers; // pointers, see queue(3)
|
||||
} dhcp_option;
|
||||
|
||||
typedef STAILQ_HEAD(dhcp_option_list_, dhcp_option) DHCP_OPTION_LIST;
|
||||
typedef struct dhcp_option_list_ dhcp_option_list;
|
||||
|
||||
/*
|
||||
* Header to manage the database of address bindings.
|
||||
*/
|
||||
|
||||
// static association or dynamic
|
||||
enum
|
||||
{
|
||||
DYNAMIC = 0,
|
||||
STATIC = 1,
|
||||
STATIC_OR_DYNAMIC = 2
|
||||
enum dhcps_offer_option{
|
||||
OFFER_START = 0x00,
|
||||
OFFER_ROUTER = 0x01,
|
||||
OFFER_END
|
||||
};
|
||||
|
||||
// binding status
|
||||
enum
|
||||
{
|
||||
EMPTY = 0,
|
||||
ASSOCIATED,
|
||||
PENDINGD,
|
||||
EXPIRED,
|
||||
RELEASED
|
||||
#define DHCPS_MAX_LEASE 0x64
|
||||
#define DHCPS_LEASE_TIME_DEF (120)
|
||||
|
||||
struct dhcps_pool{
|
||||
ip4_addr_t ip;
|
||||
u8_t mac[6];
|
||||
u32_t lease_timer;
|
||||
};
|
||||
|
||||
/*
|
||||
* IP address used to delimitate an address pool.
|
||||
*/
|
||||
typedef struct pool_indexes
|
||||
{
|
||||
uint32_t first; // first address of the pool
|
||||
uint32_t last; // last address of the pool
|
||||
uint32_t current; // current available address
|
||||
}pool_indexes;
|
||||
typedef struct _list_node{
|
||||
void *pnode;
|
||||
struct _list_node *pnext;
|
||||
}list_node;
|
||||
|
||||
/*
|
||||
* The bindings are organized as a double linked list
|
||||
* using the standard queue(3) library
|
||||
*/
|
||||
typedef struct address_binding
|
||||
{
|
||||
uint32_t address; // address
|
||||
uint8_t cident_len; // client identifier len
|
||||
uint8_t cident[256]; // client identifier
|
||||
typedef u32_t dhcps_time_t;
|
||||
typedef u8_t dhcps_offer_t;
|
||||
|
||||
time_t binding_time; // time of binding
|
||||
time_t lease_time; // duration of lease
|
||||
typedef struct {
|
||||
dhcps_offer_t dhcps_offer;
|
||||
dhcps_time_t dhcps_time;
|
||||
dhcps_lease_t dhcps_poll;
|
||||
} dhcps_options_t;
|
||||
|
||||
int status; // binding status
|
||||
int is_static; // check if it is a static binding
|
||||
#define dhcps_router_enabled(offer) ((offer & OFFER_ROUTER) != 0)
|
||||
|
||||
STAILQ_ENTRY(address_binding) pointers; // list pointers, see queue(3)
|
||||
}address_binding;
|
||||
|
||||
typedef STAILQ_HEAD(binding_list_, address_binding) BINDING_LIST_HEAD;
|
||||
typedef struct binding_list_ binding_list;
|
||||
|
||||
/*
|
||||
* Global association pool.
|
||||
*
|
||||
* The (static or dynamic) associations tables of the DHCP server,
|
||||
* are maintained in this global structure.
|
||||
*
|
||||
* Note: all the IP addresses are in host order,
|
||||
* to allow an easy manipulation.
|
||||
*/
|
||||
|
||||
typedef struct address_pool
|
||||
{
|
||||
uint32_t server_id; // this server id (IP address)
|
||||
uint32_t netmask; // network mask
|
||||
uint32_t gateway; // network gateway
|
||||
|
||||
char device[16]; // network device to use
|
||||
|
||||
pool_indexes indexes; // used to delimitate a pool of available addresses
|
||||
|
||||
time_t lease_time; // default lease time
|
||||
time_t pending_time; // duration of a binding in the pending state
|
||||
struct udp_pcb *socket; //
|
||||
bool flags;
|
||||
|
||||
dhcp_option_list options; // options for this pool, see queue
|
||||
|
||||
binding_list bindings; // associated addresses, see queue(3)
|
||||
}address_pool;
|
||||
|
||||
/*
|
||||
* Internal representation of a DHCP message,
|
||||
* with options parsed into a list...
|
||||
*/
|
||||
typedef struct dhcps_msg
|
||||
{
|
||||
dhcp_message hdr;
|
||||
dhcp_option_list opts;
|
||||
} dhcps_msg;
|
||||
|
||||
bool dhcps_option_set(u8_t opt_id, void* optarg);
|
||||
void dhcps_start(struct netif *netif, struct dhcps_lease *lease_pool);
|
||||
void dhcps_start(struct netif *netif, ip4_addr_t ip);
|
||||
void dhcps_stop(struct netif *netif);
|
||||
bool dhcps_lease_set(struct dhcps_lease *please);
|
||||
bool dhcps_lease_get(struct dhcps_lease *please);
|
||||
void *dhcps_option_info(u8_t op_id, u32_t opt_len);
|
||||
bool dhcp_search_ip_on_mac(u8_t *mac, ip4_addr_t *ip);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
71
components/lwip/include/lwip/apps/sntp/sntp.h
Normal file
71
components/lwip/include/lwip/apps/sntp/sntp.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
|
||||
* 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: Frédéric Bernon, Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
#ifndef LWIP_HDR_APPS_SNTP_H
|
||||
#define LWIP_HDR_APPS_SNTP_H
|
||||
|
||||
#include "apps/sntp/sntp_opts.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* SNTP operating modes: default is to poll using unicast.
|
||||
The mode has to be set before calling sntp_init(). */
|
||||
#define SNTP_OPMODE_POLL 0
|
||||
#define SNTP_OPMODE_LISTENONLY 1
|
||||
void sntp_setoperatingmode(u8_t operating_mode);
|
||||
u8_t sntp_getoperatingmode(void);
|
||||
|
||||
void sntp_init(void);
|
||||
void sntp_stop(void);
|
||||
u8_t sntp_enabled(void);
|
||||
|
||||
void sntp_setserver(u8_t idx, const ip_addr_t *addr);
|
||||
ip_addr_t sntp_getserver(u8_t idx);
|
||||
|
||||
#if SNTP_SERVER_DNS
|
||||
void sntp_setservername(u8_t idx, char *server);
|
||||
char *sntp_getservername(u8_t idx);
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP
|
||||
void sntp_servermode_dhcp(int set_servers_from_dhcp);
|
||||
#else /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||
#define sntp_servermode_dhcp(x)
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNTP_H */
|
159
components/lwip/include/lwip/apps/sntp/sntp_opts.h
Normal file
159
components/lwip/include/lwip/apps/sntp/sntp_opts.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
|
||||
* 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: Frédéric Bernon, Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
#ifndef LWIP_HDR_APPS_SNTP_OPTS_H
|
||||
#define LWIP_HDR_APPS_SNTP_OPTS_H
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
/** SNTP macro to change system time in seconds
|
||||
* Define SNTP_SET_SYSTEM_TIME_US(sec, us) to set the time in microseconds instead of this one
|
||||
* if you need the additional precision.
|
||||
*/
|
||||
#ifndef SNTP_SET_SYSTEM_TIME
|
||||
#define SNTP_SET_SYSTEM_TIME(sec) LWIP_UNUSED_ARG(sec)
|
||||
#endif
|
||||
|
||||
/** The maximum number of SNTP servers that can be set */
|
||||
#ifndef SNTP_MAX_SERVERS
|
||||
#define SNTP_MAX_SERVERS LWIP_DHCP_MAX_NTP_SERVERS
|
||||
#endif
|
||||
|
||||
/** Set this to 1 to implement the callback function called by dhcp when
|
||||
* NTP servers are received. */
|
||||
#ifndef SNTP_GET_SERVERS_FROM_DHCP
|
||||
#define SNTP_GET_SERVERS_FROM_DHCP LWIP_DHCP_GET_NTP_SRV
|
||||
#endif
|
||||
|
||||
/* Set this to 1 to support DNS names (or IP address strings) to set sntp servers */
|
||||
#ifndef SNTP_SERVER_DNS
|
||||
#define SNTP_SERVER_DNS 1
|
||||
#endif
|
||||
|
||||
/** One server address/name can be defined as default if SNTP_SERVER_DNS == 1:
|
||||
* #define SNTP_SERVER_ADDRESS "pool.ntp.org"
|
||||
*/
|
||||
|
||||
/**
|
||||
* SNTP_DEBUG: Enable debugging for SNTP.
|
||||
*/
|
||||
#ifndef SNTP_DEBUG
|
||||
#define SNTP_DEBUG LWIP_DBG_OFF
|
||||
#endif
|
||||
|
||||
/** SNTP server port */
|
||||
#ifndef SNTP_PORT
|
||||
#define SNTP_PORT 123
|
||||
#endif
|
||||
|
||||
/** Set this to 1 to allow config of SNTP server(s) by DNS name */
|
||||
#ifndef SNTP_SERVER_DNS
|
||||
#define SNTP_SERVER_DNS 0
|
||||
#endif
|
||||
|
||||
/** Sanity check:
|
||||
* Define this to
|
||||
* - 0 to turn off sanity checks (default; smaller code)
|
||||
* - >= 1 to check address and port of the response packet to ensure the
|
||||
* response comes from the server we sent the request to.
|
||||
* - >= 2 to check returned Originate Timestamp against Transmit Timestamp
|
||||
* sent to the server (to ensure response to older request).
|
||||
* - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp
|
||||
* fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast).
|
||||
* - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each
|
||||
* greater than or equal to 0 and less than infinity, where infinity is
|
||||
* currently a cozy number like one second. This check avoids using a
|
||||
* server whose synchronization source has expired for a very long time.
|
||||
*/
|
||||
#ifndef SNTP_CHECK_RESPONSE
|
||||
#define SNTP_CHECK_RESPONSE 0
|
||||
#endif
|
||||
|
||||
/** According to the RFC, this shall be a random delay
|
||||
* between 1 and 5 minutes (in milliseconds) to prevent load peaks.
|
||||
* This can be defined to a random generation function,
|
||||
* which must return the delay in milliseconds as u32_t.
|
||||
* Turned off by default.
|
||||
*/
|
||||
#ifndef SNTP_STARTUP_DELAY
|
||||
#define SNTP_STARTUP_DELAY 0
|
||||
#endif
|
||||
|
||||
/** If you want the startup delay to be a function, define this
|
||||
* to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1.
|
||||
*/
|
||||
#ifndef SNTP_STARTUP_DELAY_FUNC
|
||||
#define SNTP_STARTUP_DELAY_FUNC SNTP_STARTUP_DELAY
|
||||
#endif
|
||||
|
||||
/** SNTP receive timeout - in milliseconds
|
||||
* Also used as retry timeout - this shouldn't be too low.
|
||||
* Default is 3 seconds.
|
||||
*/
|
||||
#ifndef SNTP_RECV_TIMEOUT
|
||||
#define SNTP_RECV_TIMEOUT 3000
|
||||
#endif
|
||||
|
||||
/** SNTP update delay - in milliseconds
|
||||
* Default is 1 hour. Must not be beolw 15 seconds by specification (i.e. 15000)
|
||||
*/
|
||||
#ifndef SNTP_UPDATE_DELAY
|
||||
#define SNTP_UPDATE_DELAY 3600000
|
||||
#endif
|
||||
|
||||
/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2
|
||||
* to send in request and compare in response.
|
||||
*/
|
||||
#ifndef SNTP_GET_SYSTEM_TIME
|
||||
#define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0)
|
||||
#endif
|
||||
|
||||
/** Default retry timeout (in milliseconds) if the response
|
||||
* received is invalid.
|
||||
* This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached.
|
||||
*/
|
||||
#ifndef SNTP_RETRY_TIMEOUT
|
||||
#define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT
|
||||
#endif
|
||||
|
||||
/** Maximum retry timeout (in milliseconds). */
|
||||
#ifndef SNTP_RETRY_TIMEOUT_MAX
|
||||
#define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10)
|
||||
#endif
|
||||
|
||||
/** Increase retry timeout with every retry sent
|
||||
* Default is on to conform to RFC.
|
||||
*/
|
||||
#ifndef SNTP_RETRY_TIMEOUT_EXP
|
||||
#define SNTP_RETRY_TIMEOUT_EXP 1
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNTP_OPTS_H */
|
@ -94,6 +94,10 @@ struct dhcp
|
||||
ip_addr_t offered_si_addr;
|
||||
char boot_file_name[DHCP_FILE_LEN];
|
||||
#endif /* LWIP_DHCP_BOOTPFILE */
|
||||
|
||||
/* Espressif add start. */
|
||||
void (*cb)(void); /* callback for dhcp, add a parameter to show dhcp status if needed */
|
||||
/* Espressif add end. */
|
||||
};
|
||||
|
||||
/* MUST be compiled with "pack structs" or equivalent! */
|
||||
@ -140,6 +144,10 @@ void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
|
||||
/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
|
||||
#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
|
||||
void dhcp_cleanup(struct netif *netif);
|
||||
/* Espressif add start. */
|
||||
/** set callback for DHCP */
|
||||
void dhcp_set_cb(struct netif *netif, void (*cb)(void));
|
||||
/* Espressif add end. */
|
||||
/** start DHCP configuration */
|
||||
err_t dhcp_start(struct netif *netif);
|
||||
/** enforce early lease renewal (not needed normally)*/
|
||||
|
@ -188,9 +188,9 @@ struct dns_api_msg {
|
||||
|
||||
#if LWIP_NETCONN_SEM_PER_THREAD
|
||||
#ifdef LWIP_ESP8266
|
||||
#define LWIP_NETCONN_THREAD_SEM_GET() sys_thread_sem()
|
||||
#define LWIP_NETCONN_THREAD_SEM_ALLOC()
|
||||
#define LWIP_NETCONN_THREAD_SEM_FREE()
|
||||
#define LWIP_NETCONN_THREAD_SEM_GET() sys_thread_sem_get()
|
||||
#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_thread_sem_init()
|
||||
#define LWIP_NETCONN_THREAD_SEM_FREE() sys_thread_sem_deinit()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -505,7 +505,7 @@ int lwip_fcntl(int s, int cmd, int val);
|
||||
#if LWIP_COMPAT_SOCKETS
|
||||
#if LWIP_COMPAT_SOCKETS != 2
|
||||
|
||||
#ifdef LWIP_THREAD_SAFE
|
||||
#if LWIP_THREAD_SAFE
|
||||
|
||||
int lwip_accept_r(int s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
int lwip_bind_r(int s, const struct sockaddr *name, socklen_t namelen);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#define __ARCH_CC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "arch/sys_arch.h"
|
||||
|
||||
@ -72,6 +73,4 @@ typedef int sys_prot_t;
|
||||
#define LWIP_NOASSERT
|
||||
//#define LWIP_ERROR
|
||||
|
||||
#define LWIP_PROVIDE_ERRNO
|
||||
|
||||
#endif /* __ARCH_CC_H__ */
|
||||
|
@ -64,9 +64,10 @@ typedef struct sys_mbox_s {
|
||||
|
||||
void sys_arch_assert(const char *file, int line);
|
||||
uint32_t system_get_time(void);
|
||||
sys_sem_t* sys_thread_sem(void);
|
||||
void sys_delay_ms(uint32_t ms);
|
||||
|
||||
sys_sem_t* sys_thread_sem_init(void);
|
||||
void sys_thread_sem_deinit(void);
|
||||
sys_sem_t* sys_thread_sem_get(void);
|
||||
|
||||
|
||||
#endif /* __SYS_ARCH_H__ */
|
||||
|
@ -34,6 +34,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Enable all Espressif-only options */
|
||||
#define LWIP_ESP8266
|
||||
|
||||
/*
|
||||
-----------------------------------------------
|
||||
@ -221,8 +223,8 @@ extern unsigned long os_random(void);
|
||||
* TCP_WND: The size of a TCP window. This must be at least
|
||||
* (2 * TCP_MSS) for things to work well
|
||||
*/
|
||||
#define PERF 1
|
||||
#ifdef PERF
|
||||
|
||||
extern unsigned char misc_prof_get_tcpw(void);
|
||||
extern unsigned char misc_prof_get_tcp_snd_buf(void);
|
||||
#define TCP_WND (misc_prof_get_tcpw()*TCP_MSS)
|
||||
@ -506,15 +508,15 @@ extern unsigned char misc_prof_get_tcp_snd_buf(void);
|
||||
* DHCP_DEBUG: Enable debugging in dhcp.c.
|
||||
*/
|
||||
#define DHCP_DEBUG LWIP_DBG_OFF
|
||||
//#define LWIP_DEBUG 1
|
||||
//#define TCP_DEBUG LWIP_DBG_ON
|
||||
#define LWIP_DEBUG 0
|
||||
#define TCP_DEBUG LWIP_DBG_OFF
|
||||
#define THREAD_SAFE_DEBUG LWIP_DBG_OFF
|
||||
#define LWIP_THREAD_SAFE 1
|
||||
|
||||
#define CHECKSUM_CHECK_UDP 0
|
||||
#define CHECKSUM_CHECK_IP 0
|
||||
|
||||
#define HEAP_HIGHWAT 6*1024
|
||||
#define HEAP_HIGHWAT 20*1024
|
||||
|
||||
#define LWIP_NETCONN_FULLDUPLEX 1
|
||||
#define LWIP_NETCONN_SEM_PER_THREAD 1
|
||||
|
@ -213,7 +213,7 @@ sys_mbox_new(sys_mbox_t *mbox, int size)
|
||||
|
||||
(*mbox)->alive = true;
|
||||
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("new *mbox ok\n"));
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("new *mbox ok mbox=%p os_mbox=%p mbox_lock=%p\n", *mbox, (*mbox)->os_mbox, (*mbox)->lock));
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@ -234,6 +234,7 @@ sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
|
||||
if (xQueueSend((*mbox)->os_mbox, &msg, (portTickType)0) == pdPASS) {
|
||||
xReturn = ERR_OK;
|
||||
} else {
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox));
|
||||
xReturn = ERR_MEM;
|
||||
}
|
||||
|
||||
@ -291,9 +292,11 @@ sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
|
||||
ulReturn = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
} else { // block forever for a message.
|
||||
|
||||
while (1){
|
||||
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch: fetch mbox=%p os_mbox=%p lock=%p\n", mbox, (*mbox)->os_mbox, (*mbox)->lock));
|
||||
if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), portMAX_DELAY)){
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch:mbox rx msg=%p\n", (*msg)));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -348,13 +351,15 @@ sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
|
||||
void
|
||||
sys_mbox_free(sys_mbox_t *mbox)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
#define MAX_POLL_CNT 100
|
||||
#define PER_POLL_DELAY 20
|
||||
uint16_t count = 0;
|
||||
bool post_null = true;
|
||||
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free: set alive false\n"));
|
||||
(*mbox)->alive = false;
|
||||
|
||||
while ( count++ < 10 ){
|
||||
while ( count++ < MAX_POLL_CNT ){ //ESP32_WORKAROUND
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free:try lock=%d\n", count));
|
||||
if (!sys_mutex_trylock( &(*mbox)->lock )){
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free:get lock ok %d\n", count));
|
||||
@ -372,10 +377,10 @@ sys_mbox_free(sys_mbox_t *mbox)
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 10){
|
||||
if (count == (MAX_POLL_CNT-1)){
|
||||
printf("WARNING: mbox %p had a consumer who never unblocked. Leaking!\n", (*mbox)->os_mbox);
|
||||
}
|
||||
sys_delay_ms(20);
|
||||
sys_delay_ms(PER_POLL_DELAY);
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free:free mbox\n"));
|
||||
@ -428,6 +433,7 @@ sys_now(void)
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
|
||||
static portMUX_TYPE g_lwip_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
/*
|
||||
This optional function does a "fast" critical region protection and returns
|
||||
the previous protection level. This function is only called during very short
|
||||
@ -444,7 +450,7 @@ sys_now(void)
|
||||
sys_prot_t
|
||||
sys_arch_protect(void)
|
||||
{
|
||||
// vTaskEnterCritical();
|
||||
portENTER_CRITICAL(&g_lwip_mux);
|
||||
return (sys_prot_t) 1;
|
||||
}
|
||||
|
||||
@ -459,7 +465,7 @@ void
|
||||
sys_arch_unprotect(sys_prot_t pval)
|
||||
{
|
||||
(void) pval;
|
||||
// vTaskExitCritical();
|
||||
portEXIT_CRITICAL(&g_lwip_mux);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
@ -475,15 +481,65 @@ sys_arch_assert(const char *file, int line)
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* This is a super hacky thread-local-storage repository
|
||||
FreeRTOS 8.2.3 & up have thread local storage in the
|
||||
OS, which is how we should do this. Once we upgrade FreeRTOS,
|
||||
we can drop this hacky store and use the FreeRTOS TLS API.
|
||||
*/
|
||||
sys_sem_t* sys_thread_sem(void)
|
||||
#define SYS_TLS_INDEX CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX
|
||||
/*
|
||||
* get per thread semphore
|
||||
*/
|
||||
sys_sem_t* sys_thread_sem_get(void)
|
||||
{
|
||||
extern void* xTaskGetLwipSem(void);
|
||||
return (sys_sem_t*)(xTaskGetLwipSem());
|
||||
sys_sem_t *sem = (sys_sem_t*)pvTaskGetThreadLocalStoragePointer(xTaskGetCurrentTaskHandle(), SYS_TLS_INDEX);
|
||||
if (!sem){
|
||||
sem = sys_thread_sem_init();
|
||||
}
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sem_get s=%p\n", sem));
|
||||
return sem;
|
||||
}
|
||||
|
||||
static void sys_thread_tls_free(int index, void* data)
|
||||
{
|
||||
sys_sem_t *sem = (sys_sem_t*)(data);
|
||||
|
||||
if (sem && *sem){
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sem del, i=%d sem=%p\n", index, *sem));
|
||||
vSemaphoreDelete(*sem);
|
||||
}
|
||||
|
||||
if (sem){
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sem pointer del, i=%d sem_p=%p\n", index, sem));
|
||||
free(sem);
|
||||
}
|
||||
}
|
||||
|
||||
sys_sem_t* sys_thread_sem_init(void)
|
||||
{
|
||||
sys_sem_t *sem = (sys_sem_t*)malloc(sizeof(sys_sem_t*));
|
||||
|
||||
if (!sem){
|
||||
printf("sem f1\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sem = xSemaphoreCreateBinary();
|
||||
if (!(*sem)){
|
||||
free(sem);
|
||||
printf("sem f2\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sem init sem_p=%p sem=%p cb=%p\n", sem, *sem, sys_thread_tls_free));
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), SYS_TLS_INDEX, sem, (TlsDeleteCallbackFunction_t)sys_thread_tls_free);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
void sys_thread_sem_deinit(void)
|
||||
{
|
||||
sys_sem_t *sem = (sys_sem_t*)pvTaskGetThreadLocalStoragePointer(xTaskGetCurrentTaskHandle(), SYS_TLS_INDEX);
|
||||
|
||||
sys_thread_tls_free(SYS_TLS_INDEX, (void*)sem);
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), SYS_TLS_INDEX, 0, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void sys_delay_ms(uint32_t ms)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user