mirror of
https://github.com/armink/EasyLogger.git
synced 2025-01-18 23:32:54 +08:00
[demo/nuttx_spiflash] 新增nuttx平台的demo,Easyflash支持spi flash
This commit is contained in:
parent
4fecb2b478
commit
f39726143e
@ -11,7 +11,7 @@
|
||||
- 支持用户自定义输出方式(例如:终端、文件、数据库、串口、485、Flash...);
|
||||
- 日志内容可包含级别、时间戳、线程信息、进程信息等;
|
||||
- 日志输出被设计为线程安全的方式,并支持 **异步输出** 及 **缓冲输出** 模式;
|
||||
- 支持多种操作系统([RT-Thread](http://www.rt-thread.org/)、UCOS、Linux、Windows...),也支持裸机平台;
|
||||
- 支持多种操作系统([RT-Thread](http://www.rt-thread.org/)、UCOS、Linux、Windows、Nuttx...),也支持裸机平台;
|
||||
- 日志支持 **RAW格式** ,支持 **hexdump** ;
|
||||
- 支持按 **标签** 、 **级别** 、 **关键词** 进行动态过滤;
|
||||
- 各级别日志支持不同颜色显示;
|
||||
|
89
demo/os/nuttx-spiflash/README.md
Normal file
89
demo/os/nuttx-spiflash/README.md
Normal file
@ -0,0 +1,89 @@
|
||||
# Nuttx SPI Flash demo
|
||||
|
||||
---
|
||||
|
||||
## 1<><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
ͨ<EFBFBD><EFBFBD> `apps/examples/easylogger/elog_main.c` <20><> `test_elog()` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>첽<EFBFBD><ECB2BD><EFBFBD><EFBFBD>ģʽ<C4A3><CABD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD>Խ<EFBFBD><D4BD><EFBFBD><EFBFBD>ն<EFBFBD><D5B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD>
|
||||
`test_env()` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>Ĺ<DEB8><C4B9>ܣ<EFBFBD>ÿ<EFBFBD><C3BF>ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD>ʼ<EFBFBD><CABC>EasyFlash<73>ɹ<EFBFBD><C9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ø÷<C3B8><C3B7><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
- ƽ̨<C6BD><CCA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>NuttX-12.0.0<EFBFBD><EFBFBD>NuttX-10.X.X<><58>Ҫ<EFBFBD><EFBFBD>Makefile<6C><65><EFBFBD><EFBFBD>include<64><65><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD>
|
||||
- Ӳ<><D3B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>STM32F103<30><33>Nuttx<74><78>apps<70><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><D3B2>ƽ̨<C6BD><CCA8>
|
||||
- Flash<73><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD>W25QXX<58><58>Nuttx֧<78>ֵ<EFBFBD>SPI Flash<73><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`nuttx/drivers/mtd`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
## 2<><32>ʹ<EFBFBD>÷<EFBFBD><C3B7><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɺ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>nsh<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<EFBFBD><EFBFBD><EFBFBD><EFBFBD>`elog`<EFBFBD>س<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ű<EFBFBD><EFBFBD><EFBFBD><EFBFBD>۲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
![ElogNuttxSpiFlashDemo](https://raw.githubusercontent.com/armink/EasyLogger/master/docs/zh/images/ElogNuttxSpiFlashDemo.png)
|
||||
|
||||
## 3<><33><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>У<EFBFBD>˵<EFBFBD><CBB5>
|
||||
|
||||
|Դ<>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>У<EFBFBD> |<7C><><EFBFBD><EFBFBD> |
|
||||
|:------------------------------ |:----- |
|
||||
|apps |nuttx-appsӦ<73>ò<EFBFBD>Ŀ¼|
|
||||
|apps/examples/ |nuttxӦ<78>ò<EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ¼|
|
||||
|apps/examples/easylogger/elog_main.c |Easylogger<65><72>Easyflash<73><68>Example Demo<6D><6F><EFBFBD><EFBFBD>|
|
||||
|apps/system/ |nuttxӦ<78>ò<EFBFBD>ϵͳ<CFB5><CDB3>Ŀ¼|
|
||||
|apps/system/easylogger/inc/elog_cfg.h |Easylogger<65><72><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>|
|
||||
|apps/system/easylogger/port/elog_port.c |Easylogger<65><72>ֲ<EFBFBD>ο<EFBFBD><CEBF>ļ<EFBFBD>|
|
||||
|apps/system/easyflash/inc/ef_cfg.h |Easyflash<73><68><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>|
|
||||
|apps/system/easyflash/port/ef_port.c |Easyflash<73><68>ֲ<EFBFBD>ο<EFBFBD><CEBF>ļ<EFBFBD>|
|
||||
|
||||
## 4<><34><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><CBB5>
|
||||
|
||||
### 4.1<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֲ˵<EFBFBD><EFBFBD>
|
||||
|
||||
1<EFBFBD><EFBFBD><EFBFBD>Ѹ<EFBFBD>Ŀ¼`EasyLogger/`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>λ<EFBFBD>ã<EFBFBD>
|
||||
```
|
||||
cd EasyLogger/
|
||||
cp easylogger/inc/elog.h demo/os/nuttx-spiflash/apps/system/easylogger/inc
|
||||
cp easylogger/plugins/flash/elog_flash.* demo/os/nuttx-spiflash/apps/system/easylogger/plugins/flash/
|
||||
cp -R easylogger/src/ demo/os/nuttx-spiflash/apps/system/easylogger/
|
||||
```
|
||||
|
||||
2<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>apps<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ¼<EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD>nuttx<EFBFBD><EFBFBD>appsĿ¼<EFBFBD>¡<EFBFBD>
|
||||
|
||||
3<EFBFBD><EFBFBD>nuttxĿ¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>appsĿ¼<EFBFBD>ṹ<EFBFBD><EFBFBD><EFBFBD>档
|
||||
```
|
||||
make apps_distclean
|
||||
make menuconfig
|
||||
```
|
||||
|
||||
4<EFBFBD><EFBFBD>`make menuconfig`ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Easylogger Demo Example<6C><65>
|
||||
```
|
||||
CONFIG_EXAMPLES_EASYLOGGER=y
|
||||
```
|
||||
<EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
```
|
||||
CONFIG_MTD_W25=y
|
||||
```
|
||||
|
||||
5<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>mtd ioctl<74><6C>ָ<EFBFBD><D6B8>ID<49><44><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD>Easyflash<73><68><EFBFBD>ܿ<EFBFBD><DCBF><EFBFBD>ʡ<EFBFBD>ԣ<EFBFBD>
|
||||
- <20><><EFBFBD><EFBFBD>`nuttx/include/nuttx/mtd/mtd.h`<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>
|
||||
```C
|
||||
#define MTDIOC_GETMTDDEV _MTDIOC(0x000c)
|
||||
```
|
||||
|
||||
6<EFBFBD><EFBFBD><EFBFBD><EFBFBD>¶w25<EFBFBD><EFBFBD>mtd<EFBFBD>豸<EFBFBD>ڵ㣺<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD>Easyflash<EFBFBD><EFBFBD><EFBFBD>ܿ<EFBFBD><EFBFBD><EFBFBD>ʡ<EFBFBD>ԣ<EFBFBD>
|
||||
- <20><><EFBFBD><EFBFBD>`nuttx/drivers/mtd/w25.c`<EFBFBD>ļ<EFBFBD>
|
||||
- <20><><EFBFBD>ӱ<EFBFBD><D3B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
```C
|
||||
static FAR struct mtd_dev_s *mtd_w25;
|
||||
```
|
||||
- <20>ҵ<EFBFBD>`w25_ioctl`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`switch (cmd)`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>
|
||||
```C
|
||||
case MTDIOC_GETMTDDEV:{
|
||||
FAR struct mtd_dev_s **mtd =
|
||||
(FAR struct mtd_dev_s *)((uintptr_t)arg);
|
||||
DEBUGASSERT(*mtd != NULL);
|
||||
*mtd = mtd_w25;
|
||||
ret = OK;
|
||||
}break;
|
||||
```
|
||||
- <20>ҵ<EFBFBD>`w25_initialize`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`ret = w25_readid(priv)`<EFBFBD><EFBFBD>ID<EFBFBD><EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>
|
||||
```C
|
||||
mtd_w25=&priv->mtd;
|
||||
```
|
||||
|
||||
7<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`make -j4`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>NSH<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<EFBFBD><EFBFBD><EFBFBD><EFBFBD>`elog`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɲ鿴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
35
demo/os/nuttx-spiflash/apps/examples/easylogger/Kconfig
Normal file
35
demo/os/nuttx-spiflash/apps/examples/easylogger/Kconfig
Normal file
@ -0,0 +1,35 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config EXAMPLES_EASYLOGGER
|
||||
tristate "Easylogger and EasyFlash Demo"
|
||||
default n
|
||||
select SYSTEM_EASYLOGGER
|
||||
select SYSTEM_EASYLOGGER_FLASH
|
||||
select SYSTEM_EASYFLASH
|
||||
select CONFIG_MTD
|
||||
select CONFIG_MTD_BYTE_WRITE
|
||||
select CONFIG_MTD_W25
|
||||
---help---
|
||||
Enable the Easylogger Demo
|
||||
|
||||
if EXAMPLES_EASYLOGGER
|
||||
|
||||
config EXAMPLES_EASYLOGGER_PROGNAME
|
||||
string "Program name"
|
||||
default "elog"
|
||||
---help---
|
||||
This is the name of the program that will be used when the NSH ELF
|
||||
program is installed.
|
||||
|
||||
config EXAMPLES_EASYLOGGER_PRIORITY
|
||||
int "Easylogger task priority"
|
||||
default 100
|
||||
|
||||
config EXAMPLES_EASYLOGGER_STACKSIZE
|
||||
int "Easylogger stack size"
|
||||
default DEFAULT_TASK_STACKSIZE
|
||||
|
||||
endif
|
23
demo/os/nuttx-spiflash/apps/examples/easylogger/Make.defs
Normal file
23
demo/os/nuttx-spiflash/apps/examples/easylogger/Make.defs
Normal file
@ -0,0 +1,23 @@
|
||||
############################################################################
|
||||
# apps/examples/easylogger/Make.defs
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_EXAMPLES_EASYLOGGER),)
|
||||
CONFIGURED_APPS += $(APPDIR)/examples/easylogger
|
||||
endif
|
38
demo/os/nuttx-spiflash/apps/examples/easylogger/Makefile
Normal file
38
demo/os/nuttx-spiflash/apps/examples/easylogger/Makefile
Normal file
@ -0,0 +1,38 @@
|
||||
############################################################################
|
||||
# apps/examples/easylogger/Make.defs
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
# Hello, easylogger! built-in application info
|
||||
|
||||
PROGNAME = $(CONFIG_EXAMPLES_EASYLOGGER_PROGNAME)
|
||||
PRIORITY = $(CONFIG_EXAMPLES_EASYLOGGER_PRIORITY)
|
||||
STACKSIZE = $(CONFIG_EXAMPLES_EASYLOGGER_STACKSIZE)
|
||||
MODULE = $(CONFIG_EXAMPLES_EASYLOGGER)
|
||||
|
||||
# Hello, easylogger! Example
|
||||
|
||||
MAINSRC = elog_main.c
|
||||
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/system/easylogger/inc}
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/system/easylogger/plugins/flash}
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/system/easyflash/inc}
|
||||
|
||||
include $(APPDIR)/Application.mk
|
144
demo/os/nuttx-spiflash/apps/examples/easylogger/elog_main.c
Normal file
144
demo/os/nuttx-spiflash/apps/examples/easylogger/elog_main.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* This file is part of the EasyLogger Library.
|
||||
*
|
||||
* Copyright (c) 2015-2017, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: nuttx demo.
|
||||
* Created on: 2023-02-15
|
||||
*/
|
||||
|
||||
#define LOG_TAG "elogdemo"
|
||||
|
||||
#include <elog.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <elog_flash.h>
|
||||
#include <easyflash.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* Env demo.
|
||||
*/
|
||||
static void test_env(void) {
|
||||
uint32_t i_boot_times = NULL;
|
||||
char *c_old_boot_times, c_new_boot_times[11] = {0};
|
||||
|
||||
/* get the boot count number from Env */
|
||||
c_old_boot_times = ef_get_env("boot_times");
|
||||
// assert_param(c_old_boot_times);
|
||||
i_boot_times = atol(c_old_boot_times);
|
||||
/* boot count +1 */
|
||||
i_boot_times ++;
|
||||
printf("The system now boot %d times\n\r", i_boot_times);
|
||||
/* interger to string */
|
||||
sprintf(c_new_boot_times,"%ld", i_boot_times);
|
||||
/* set and store the boot count number to Env */
|
||||
ef_set_env("boot_times", c_new_boot_times);
|
||||
ef_save_env();
|
||||
}
|
||||
|
||||
/**
|
||||
* EasyLogger demo
|
||||
*/
|
||||
static void test_elog(void) {
|
||||
uint8_t buf[256]= {0};
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < sizeof(buf); i++)
|
||||
{
|
||||
buf[i] = i;
|
||||
}
|
||||
while(true) {
|
||||
/* test log output for all level */
|
||||
log_a("Hello EasyLogger!");
|
||||
log_e("Hello EasyLogger!");
|
||||
log_w("Hello EasyLogger!");
|
||||
log_i("Hello EasyLogger!");
|
||||
log_d("Hello EasyLogger!");
|
||||
log_v("Hello EasyLogger!");
|
||||
// elog_raw("Hello EasyLogger!");
|
||||
elog_hexdump("test", 16, buf, sizeof(buf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void easylogger_demo(void) {
|
||||
/* close printf buffer */
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
/* initialize EasyFlash and EasyLogger */
|
||||
if ((easyflash_init() == EF_NO_ERR)&&(elog_init() == ELOG_NO_ERR)) {
|
||||
/* set EasyLogger log format */
|
||||
elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
|
||||
elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
|
||||
elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
|
||||
elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
|
||||
elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
|
||||
elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
|
||||
#ifdef ELOG_COLOR_ENABLE
|
||||
elog_set_text_color_enabled(true);
|
||||
#endif
|
||||
/* initialize EasyLogger Flash plugin */
|
||||
elog_flash_init();
|
||||
/* start EasyLogger */
|
||||
elog_start();
|
||||
|
||||
/* dynamic set enable or disable for output logs (true or false) */
|
||||
// elog_set_output_enabled(false);
|
||||
/* dynamic set output logs's level (from ELOG_LVL_ASSERT to ELOG_LVL_VERBOSE) */
|
||||
// elog_set_filter_lvl(ELOG_LVL_WARN);
|
||||
/* dynamic set output logs's filter for tag */
|
||||
// elog_set_filter_tag("main");
|
||||
/* dynamic set output logs's filter for keyword */
|
||||
// elog_set_filter_kw("Hello");
|
||||
/* dynamic set output logs's tag filter */
|
||||
// elog_set_filter_tag_lvl("main", ELOG_LVL_WARN);
|
||||
|
||||
/* test logger output */
|
||||
test_env();
|
||||
test_elog();
|
||||
}
|
||||
else{
|
||||
printf("easyflash_init or elog_init init fail\n");
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* elog_demo
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, FAR char *argv[])
|
||||
{
|
||||
printf("Hello, EasyLogger!!\n");
|
||||
easylogger_demo();
|
||||
return 0;
|
||||
}
|
||||
|
15
demo/os/nuttx-spiflash/apps/system/easyflash/Kconfig
Normal file
15
demo/os/nuttx-spiflash/apps/system/easyflash/Kconfig
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
menuconfig SYSTEM_EASYFLASH
|
||||
tristate "Easyflash"
|
||||
default n
|
||||
---help---
|
||||
Enable support for the Easyflash
|
||||
|
||||
if SYSTEM_EASYFLASH
|
||||
|
||||
|
||||
endif # SYSTEM_EASYFLASH
|
23
demo/os/nuttx-spiflash/apps/system/easyflash/Make.defs
Normal file
23
demo/os/nuttx-spiflash/apps/system/easyflash/Make.defs
Normal file
@ -0,0 +1,23 @@
|
||||
############################################################################
|
||||
# apps/system/easyflash/Make.defs
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_SYSTEM_EASYFLASH),)
|
||||
CONFIGURED_APPS += $(APPDIR)/system/easyflash
|
||||
endif
|
33
demo/os/nuttx-spiflash/apps/system/easyflash/Makefile
Normal file
33
demo/os/nuttx-spiflash/apps/system/easyflash/Makefile
Normal file
@ -0,0 +1,33 @@
|
||||
############################################################################
|
||||
# apps/system/easyflash/Makefile
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
# easyflash Application
|
||||
|
||||
CSRCS = easyflash.c ef_utils.c ef_port.c
|
||||
CSRCS += ef_env.c # ef_env_wl.c
|
||||
# CSRCS += ef_iap.c ef_log.c
|
||||
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/system/easyflash/inc}
|
||||
|
||||
VPATH += :src port
|
||||
|
||||
include $(APPDIR)/Application.mk
|
107
demo/os/nuttx-spiflash/apps/system/easyflash/inc/easyflash.h
Normal file
107
demo/os/nuttx-spiflash/apps/system/easyflash/inc/easyflash.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2014-2019, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is an head file for this library. You can see all be called functions.
|
||||
* Created on: 2014-09-10
|
||||
*/
|
||||
|
||||
|
||||
#ifndef EASYFLASH_H_
|
||||
#define EASYFLASH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <ef_cfg.h>
|
||||
#include <ef_def.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* easyflash.c */
|
||||
EfErrCode easyflash_init(void);
|
||||
|
||||
#ifdef EF_USING_ENV
|
||||
/* only supported on ef_env.c */
|
||||
size_t ef_get_env_blob(const char *key, void *value_buf, size_t buf_len, size_t *saved_value_len);
|
||||
bool ef_get_env_obj(const char *key, env_node_obj_t env);
|
||||
size_t ef_read_env_value(env_node_obj_t env, uint8_t *value_buf, size_t buf_len);
|
||||
EfErrCode ef_set_env_blob(const char *key, const void *value_buf, size_t buf_len);
|
||||
|
||||
/* ef_env.c, ef_env_legacy_wl.c and ef_env_legacy.c */
|
||||
EfErrCode ef_load_env(void);
|
||||
void ef_print_env(void);
|
||||
char *ef_get_env(const char *key);
|
||||
EfErrCode ef_set_env(const char *key, const char *value);
|
||||
EfErrCode ef_del_env(const char *key);
|
||||
EfErrCode ef_save_env(void);
|
||||
EfErrCode ef_env_set_default(void);
|
||||
size_t ef_get_env_write_bytes(void);
|
||||
EfErrCode ef_set_and_save_env(const char *key, const char *value);
|
||||
EfErrCode ef_del_and_save_env(const char *key);
|
||||
#endif
|
||||
|
||||
#ifdef EF_USING_IAP
|
||||
/* ef_iap.c */
|
||||
EfErrCode ef_erase_bak_app(size_t app_size);
|
||||
EfErrCode ef_erase_user_app(uint32_t user_app_addr, size_t user_app_size);
|
||||
EfErrCode ef_erase_spec_user_app(uint32_t user_app_addr, size_t app_size,
|
||||
EfErrCode (*app_erase)(uint32_t addr, size_t size));
|
||||
EfErrCode ef_erase_bl(uint32_t bl_addr, size_t bl_size);
|
||||
EfErrCode ef_write_data_to_bak(uint8_t *data, size_t size, size_t *cur_size,
|
||||
size_t total_size);
|
||||
EfErrCode ef_copy_app_from_bak(uint32_t user_app_addr, size_t app_size);
|
||||
EfErrCode ef_copy_spec_app_from_bak(uint32_t user_app_addr, size_t app_size,
|
||||
EfErrCode (*app_write)(uint32_t addr, const uint32_t *buf, size_t size));
|
||||
EfErrCode ef_copy_bl_from_bak(uint32_t bl_addr, size_t bl_size);
|
||||
uint32_t ef_get_bak_app_start_addr(void);
|
||||
#endif
|
||||
|
||||
#ifdef EF_USING_LOG
|
||||
/* ef_log.c */
|
||||
EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size);
|
||||
EfErrCode ef_log_write(const uint32_t *log, size_t size);
|
||||
EfErrCode ef_log_clean(void);
|
||||
size_t ef_log_get_used_size(void);
|
||||
#endif
|
||||
|
||||
/* ef_utils.c */
|
||||
uint32_t ef_calc_crc32(uint32_t crc, const void *buf, size_t size);
|
||||
|
||||
/* ef_port.c */
|
||||
EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size);
|
||||
EfErrCode ef_port_erase(uint32_t addr, size_t size);
|
||||
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size);
|
||||
void ef_port_env_lock(void);
|
||||
void ef_port_env_unlock(void);
|
||||
void ef_log_debug(const char *file, const long line, const char *format, ...);
|
||||
void ef_log_info(const char *format, ...);
|
||||
void ef_print(const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EASYFLASH_H_ */
|
79
demo/os/nuttx-spiflash/apps/system/easyflash/inc/ef_cfg.h
Normal file
79
demo/os/nuttx-spiflash/apps/system/easyflash/inc/ef_cfg.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2019, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is the configure head file for this library.
|
||||
* Created on: 2015-07-14
|
||||
*/
|
||||
|
||||
#ifndef EF_CFG_H_
|
||||
#define EF_CFG_H_
|
||||
|
||||
/* using ENV function, default is NG (Next Generation) mode start from V4.0 */
|
||||
#define EF_USING_ENV
|
||||
|
||||
/* using IAP function */
|
||||
// #define EF_USING_IAP
|
||||
|
||||
/* using save log function */
|
||||
// #define EF_USING_LOG
|
||||
|
||||
/* the minimum size of flash erasure */
|
||||
#define EF_ERASE_MIN_SIZE 4096
|
||||
|
||||
/* the flash write granularity, unit: bit
|
||||
* only support 1(nor flash)/ 8(stm32f4)/ 32(stm32f1)/ 64(stm32l4) */
|
||||
#define EF_WRITE_GRAN 1
|
||||
|
||||
/*
|
||||
*
|
||||
* This all Backup Area Flash storage index. All used flash area configure is under here.
|
||||
* |----------------------------| Storage Size
|
||||
* | Environment variables area | ENV area size @see ENV_AREA_SIZE
|
||||
* |----------------------------|
|
||||
* | Saved log area | Log area size @see LOG_AREA_SIZE
|
||||
* |----------------------------|
|
||||
* |(IAP)Downloaded application | IAP already downloaded application, unfixed size
|
||||
* |----------------------------|
|
||||
*
|
||||
* @note all area sizes must be aligned with EF_ERASE_MIN_SIZE
|
||||
*
|
||||
* The EasyFlash add the NG (Next Generation) mode start from V4.0. All old mode before V4.0, called LEGACY mode.
|
||||
*
|
||||
* - NG (Next Generation) mode is default mode from V4.0. It's easy to settings, only defined the ENV_AREA_SIZE.
|
||||
* - The LEGACY mode has been DEPRECATED. It is NOT RECOMMENDED to continue using.
|
||||
* Beacuse it will use ram to buffer the ENV and spend more flash erase times.
|
||||
* If you want use it please using the V3.X version.
|
||||
*/
|
||||
|
||||
/* backup area start address */
|
||||
#define EF_START_ADDR (0) /* from the SPI Flash position: 0KB*/
|
||||
/* ENV area size. It's at least one empty sector for GC. So it's definination must more then or equal 2 flash sector size. */
|
||||
#define ENV_AREA_SIZE (2 * EF_ERASE_MIN_SIZE) /* 8K */
|
||||
/* saved log area size */
|
||||
#define LOG_AREA_SIZE (10 * EF_ERASE_MIN_SIZE) /* 40K */
|
||||
|
||||
/* print debug information of flash */
|
||||
#define PRINT_DEBUG
|
||||
|
||||
#endif /* EF_CFG_H_ */
|
124
demo/os/nuttx-spiflash/apps/system/easyflash/inc/ef_def.h
Normal file
124
demo/os/nuttx-spiflash/apps/system/easyflash/inc/ef_def.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2019-2020, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is the definitions head file for this library.
|
||||
* Created on: 2019-11-20
|
||||
*/
|
||||
|
||||
#ifndef EF_DEF_H_
|
||||
#define EF_DEF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* EasyFlash software version number */
|
||||
#define EF_SW_VERSION "4.1.99"
|
||||
#define EF_SW_VERSION_NUM 0x40199
|
||||
|
||||
/*
|
||||
* ENV version number defined by user.
|
||||
* Please change it when your firmware add a new ENV to default_env_set.
|
||||
*/
|
||||
#ifndef EF_ENV_VER_NUM
|
||||
#define EF_ENV_VER_NUM 0
|
||||
#endif
|
||||
|
||||
/* the ENV max name length must less then it */
|
||||
#ifndef EF_ENV_NAME_MAX
|
||||
#define EF_ENV_NAME_MAX 32
|
||||
#endif
|
||||
|
||||
/* EasyFlash debug print function. Must be implement by user. */
|
||||
#ifdef PRINT_DEBUG
|
||||
#define EF_DEBUG(...) ef_log_debug(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define EF_DEBUG(...)
|
||||
#endif
|
||||
/* EasyFlash routine print function. Must be implement by user. */
|
||||
#define EF_INFO(...) ef_log_info(__VA_ARGS__)
|
||||
/* EasyFlash assert for developer. */
|
||||
#define EF_ASSERT(EXPR) \
|
||||
if (!(EXPR)) \
|
||||
{ \
|
||||
EF_DEBUG("(%s) has assert failed at %s.\n", #EXPR, __FUNCTION__); \
|
||||
while (1); \
|
||||
}
|
||||
|
||||
typedef struct _ef_env {
|
||||
char *key;
|
||||
void *value;
|
||||
size_t value_len;
|
||||
} ef_env, *ef_env_t;
|
||||
|
||||
/* EasyFlash error code */
|
||||
typedef enum {
|
||||
EF_NO_ERR,
|
||||
EF_ERASE_ERR,
|
||||
EF_READ_ERR,
|
||||
EF_WRITE_ERR,
|
||||
EF_ENV_NAME_ERR,
|
||||
EF_ENV_NAME_EXIST,
|
||||
EF_ENV_FULL,
|
||||
EF_ENV_INIT_FAILED,
|
||||
} EfErrCode;
|
||||
|
||||
/* the flash sector current status */
|
||||
typedef enum {
|
||||
EF_SECTOR_EMPTY,
|
||||
EF_SECTOR_USING,
|
||||
EF_SECTOR_FULL,
|
||||
} EfSecrorStatus;
|
||||
|
||||
enum env_status {
|
||||
ENV_UNUSED,
|
||||
ENV_PRE_WRITE,
|
||||
ENV_WRITE,
|
||||
ENV_PRE_DELETE,
|
||||
ENV_DELETED,
|
||||
ENV_ERR_HDR,
|
||||
ENV_STATUS_NUM,
|
||||
};
|
||||
typedef enum env_status env_status_t;
|
||||
|
||||
struct env_node_obj {
|
||||
env_status_t status; /**< ENV node status, @see node_status_t */
|
||||
bool crc_is_ok; /**< ENV node CRC32 check is OK */
|
||||
uint8_t name_len; /**< name length */
|
||||
uint32_t magic; /**< magic word(`K`, `V`, `4`, `0`) */
|
||||
uint32_t len; /**< ENV node total length (header + name + value), must align by EF_WRITE_GRAN */
|
||||
uint32_t value_len; /**< value length */
|
||||
char name[EF_ENV_NAME_MAX]; /**< name */
|
||||
struct {
|
||||
uint32_t start; /**< ENV node start address */
|
||||
uint32_t value; /**< value start address */
|
||||
} addr;
|
||||
};
|
||||
typedef struct env_node_obj *env_node_obj_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EF_DEF_H_ */
|
@ -0,0 +1,152 @@
|
||||
# EasyFlash Types <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>plugin<69><6E>
|
||||
|
||||
---
|
||||
|
||||
## 1<><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
Ŀǰ EasyFlash <20>Ὣ<EFBFBD><E1BDAB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD>洢<EFBFBD><E6B4A2> Flash <20>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ<C4A3>£<EFBFBD><C2A3><EFBFBD><EFBFBD>ڷ<EFBFBD><DAB7>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵Ļ<CDB5><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>ʱ<EFBFBD><CAB1><EFBFBD>ͱ<EFBFBD><CDB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD><D3B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD>롣<EFBFBD><EBA1A3><EFBFBD><EFBFBD> Types <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>˷<EFBFBD><CBB7><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD>ʹ<EFBFBD><CAB9> EasyFlash ʱ<><CAB1><EFBFBD>Ը<EFBFBD><D4B8>Ӽķ<F2B5A5B5>ʽȥ<CABD><C8A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵Ļ<CDB5><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD>Ҫ֧<EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>C <20><> **<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>** <20><> **<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>** <20>Լ<EFBFBD> **<EFBFBD>ṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>** <20><><EFBFBD><EFBFBD><EFBFBD>ڽṹ<DABD><E1B9B9><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD> Types <20><><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD><EFBFBD><EFBFBD> [struct2json](https://github.com/armink/struct2json) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> [struct2json](https://github.com/armink/struct2json) <20>⡣
|
||||
|
||||
## 2<><32>ʹ<EFBFBD><CAB9>
|
||||
|
||||
### 2.1 Դ<>뵼<EFBFBD><EBB5BC>
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮ǰ<EFBFBD><EFBFBD>Ҫȷ<EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><EFBFBD><EFBFBD>Ѱ<EFBFBD><EFBFBD><EFBFBD> EasyFlash <20><><EFBFBD><EFBFBD>Դ<EFBFBD>룬<EFBFBD><EBA3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD> "\easyflash\inc"<22><>"\easyflash\port" <20><> "\easyflash\src" <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>뷽<EFBFBD><EBB7BD><EFBFBD><EFBFBD><EFBFBD>Բο<D4B2><CEBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֲ<EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD>[<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](https://github.com/armink/EasyFlash/blob/master/docs/zh/port.md)<29><><EFBFBD><EFBFBD><EFBFBD>ٽ<EFBFBD> Types <20><><EFBFBD><EFBFBD>Դ<EFBFBD>뵼<EFBFBD>뵽<EFBFBD><EBB5BD>Ŀ<EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ "plugins\types" <20>ļ<EFBFBD><C4BC><EFBFBD>һ<EFBFBD><EFBFBD><F0BFBDB1><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD> easyflash <20>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>¡<EFBFBD>Ȼ<EFBFBD><C8BB><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> `easyflash\plugins\types\struct2json\inc` <20><> `easyflash\plugins\types` <20><><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>·<EFBFBD><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀͷ<C4BF>ļ<EFBFBD>·<EFBFBD><C2B7><EFBFBD>м<EFBFBD><D0BC>ɡ<EFBFBD>
|
||||
|
||||
### 2.2 <20><>ʼ<EFBFBD><CABC>
|
||||
|
||||
```C
|
||||
void ef_types_init(S2jHook *hook)
|
||||
```
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ Types <20><><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>ʼ<EFBFBD><CABC> struct2json <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD><C4AC>ʹ<EFBFBD>õ<EFBFBD> malloc <20><> free <20><>Ϊ<EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Ĭ<EFBFBD><C4AC><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9> RT-Thread <20><><EFBFBD><EFBFBD>ϵͳ<CFB5>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Բο<D4B2><CEBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD>룺
|
||||
|
||||
```C
|
||||
S2jHook s2jHook = {
|
||||
.free_fn = rt_free,
|
||||
.malloc_fn = (void *(*)(size_t))rt_malloc,
|
||||
};
|
||||
ef_types_init(&s2jHook);
|
||||
```
|
||||
|
||||
### 2.3 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
#### 2.3.1 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD>ڻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> EasyFlash ԭ<>е<EFBFBD> API һ<>£<EFBFBD>ֻ<EFBFBD><D6BB><EFBFBD><EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>μ<EFBFBD><CEBC><EFBFBD><EFBFBD>ε<EFBFBD><CEB5><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD>п<EFBFBD><D0BF>õ<EFBFBD> API <20><><EFBFBD>£<EFBFBD>
|
||||
|
||||
```C
|
||||
bool ef_get_bool(const char *key);
|
||||
char ef_get_char(const char *key);
|
||||
short ef_get_short(const char *key);
|
||||
int ef_get_int(const char *key);
|
||||
long ef_get_long(const char *key);
|
||||
float ef_get_float(const char *key);
|
||||
double ef_get_double(const char *key);
|
||||
EfErrCode ef_set_bool(const char *key, bool value);
|
||||
EfErrCode ef_set_char(const char *key, char value);
|
||||
EfErrCode ef_set_short(const char *key, short value);
|
||||
EfErrCode ef_set_int(const char *key, int value);
|
||||
EfErrCode ef_set_long(const char *key, long value);
|
||||
EfErrCode ef_set_float(const char *key, float value);
|
||||
EfErrCode ef_set_double(const char *key, double value);
|
||||
```
|
||||
|
||||
#### 2.3.2 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>£<EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڣ<EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ν<EFBFBD><EFBFBD>з<EFBFBD><EFBFBD>ء<EFBFBD><EFBFBD><EFBFBD><EFBFBD>п<EFBFBD><EFBFBD>õ<EFBFBD> API <20><><EFBFBD>£<EFBFBD>
|
||||
|
||||
```C
|
||||
void ef_get_bool_array(const char *key, bool *value);
|
||||
void ef_get_char_array(const char *key, char *value);
|
||||
void ef_get_short_array(const char *key, short *value);
|
||||
void ef_get_int_array(const char *key, int *value);
|
||||
void ef_get_long_array(const char *key, long *value);
|
||||
void ef_get_float_array(const char *key, float *value);
|
||||
void ef_get_double_array(const char *key, double *value);
|
||||
void ef_get_string_array(const char *key, char **value);
|
||||
EfErrCode ef_set_bool_array(const char *key, bool *value, size_t len);
|
||||
EfErrCode ef_set_char_array(const char *key, char *value, size_t len);
|
||||
EfErrCode ef_set_short_array(const char *key, short *value, size_t len);
|
||||
EfErrCode ef_set_int_array(const char *key, int *value, size_t len);
|
||||
EfErrCode ef_set_long_array(const char *key, long *value, size_t len);
|
||||
EfErrCode ef_set_float_array(const char *key, float *value, size_t len);
|
||||
EfErrCode ef_set_double_array(const char *key, double *value, size_t len);
|
||||
EfErrCode ef_set_string_array(const char *key, char **value, size_t len);
|
||||
```
|
||||
#### 2.3.3 <20>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD>ڽṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫʹ<EFBFBD><EFBFBD> struct2json <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD>ýṹ<C3BD><E1B9B9><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6> JSON <20><>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٽ<EFBFBD><D9BD><EFBFBD>д<EFBFBD>õĻ<C3B5>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ν<EFBFBD><CEBD><EFBFBD>ʹ<EFBFBD>á<EFBFBD><C3A1>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> API <20><><EFBFBD>£<EFBFBD>
|
||||
|
||||
```C
|
||||
void *ef_get_struct(const char *key, ef_types_get_cb get_cb);
|
||||
EfErrCode ef_set_struct(const char *key, void *value, ef_types_set_cb set_cb);
|
||||
```
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̼<EFBFBD><EFBFBD>ṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> JSON ֮<><D6AE><EFBFBD>Ļ<EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Բο<D4B2><CEBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Demo<6D><6F>
|
||||
|
||||
```C
|
||||
/* <20><><EFBFBD><EFBFBD><EFBFBD>ṹ<EFBFBD><E1B9B9> */
|
||||
typedef struct {
|
||||
char name[16];
|
||||
} Hometown;
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
double weight;
|
||||
uint8_t score[8];
|
||||
char name[16];
|
||||
Hometown hometown;
|
||||
} Student;
|
||||
|
||||
/* <20><><EFBFBD><EFBFBD><EFBFBD>ṹ<EFBFBD><E1B9B9>ת JSON <20>ķ<EFBFBD><C4B7><EFBFBD> */
|
||||
static cJSON *stu_set_cb(void* struct_obj) {
|
||||
Student *struct_student = (Student *)struct_obj;
|
||||
/* <20><><EFBFBD><EFBFBD> Student JSON <20><><EFBFBD><EFBFBD> */
|
||||
s2j_create_json_obj(json_student);
|
||||
/* <20><><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD>ݵ<EFBFBD> Student JSON <20><><EFBFBD><EFBFBD> */
|
||||
s2j_json_set_basic_element(json_student, struct_student, int, id);
|
||||
s2j_json_set_basic_element(json_student, struct_student, double, weight);
|
||||
s2j_json_set_array_element(json_student, struct_student, int, score, 8);
|
||||
s2j_json_set_basic_element(json_student, struct_student, string, name);
|
||||
/* <20><><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD>ݵ<EFBFBD> Student.Hometown JSON <20><><EFBFBD><EFBFBD> */
|
||||
s2j_json_set_struct_element(json_hometown, json_student, struct_hometown, struct_student, Hometown, hometown);
|
||||
s2j_json_set_basic_element(json_hometown, struct_hometown, string, name);
|
||||
return json_student;
|
||||
}
|
||||
|
||||
/* <20><><EFBFBD><EFBFBD> JSON ת<>ṹ<EFBFBD><E1B9B9><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD> */
|
||||
static void *stu_get_cb(cJSON* json_obj) {
|
||||
/* <20><><EFBFBD><EFBFBD> Student <20>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE> s2j_ <20><>ͷ<EFBFBD>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD> struct2json <20><><EFBFBD>ṩ<EFBFBD>ģ<EFBFBD> */
|
||||
s2j_create_struct_obj(struct_student, Student);
|
||||
/* <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD>ݵ<EFBFBD> Student <20>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||
s2j_struct_get_basic_element(struct_student, json_obj, int, id);
|
||||
s2j_struct_get_array_element(struct_student, json_obj, int, score);
|
||||
s2j_struct_get_basic_element(struct_student, json_obj, string, name);
|
||||
s2j_struct_get_basic_element(struct_student, json_obj, double, weight);
|
||||
/* <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD>ݵ<EFBFBD> Student.Hometown <20>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||
s2j_struct_get_struct_element(struct_hometown, struct_student, json_hometown, json_obj, Hometown, hometown);
|
||||
s2j_struct_get_basic_element(struct_hometown, json_hometown, string, name);
|
||||
return struct_student;
|
||||
}
|
||||
|
||||
/* <20><><EFBFBD>ýṹ<C3BD><E1B9B9><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||
Student orignal_student = {
|
||||
.id = 24,
|
||||
.weight = 71.2,
|
||||
.score = {1, 2, 3, 4, 5, 6, 7, 8},
|
||||
.name = "<22><><EFBFBD><EFBFBD>",
|
||||
.hometown.name = "<22><><EFBFBD><EFBFBD>",
|
||||
};
|
||||
ef_set_struct("<22><><EFBFBD><EFBFBD>ѧ<EFBFBD><D1A7>", &orignal_student, stu_set_cb);
|
||||
|
||||
/* <20><>ȡ<EFBFBD>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||
Student *student;
|
||||
ef_get_struct("<22><><EFBFBD><EFBFBD>ѧ<EFBFBD><D1A7>", student, stu_get_cb);
|
||||
|
||||
/* <20><>ӡ<EFBFBD><D3A1>ȡ<EFBFBD><C8A1><EFBFBD>Ľṹ<C4BD><E1B9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||
printf("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>%s <20><><EFBFBD>%s \n", student->name, student->hometown.name);
|
||||
|
||||
/* <20>ͷŻ<CDB7>ȡ<EFBFBD>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>п<EFBFBD><D0BF>ٵĶ<D9B5>̬<EFBFBD>ڴ<EFBFBD> */
|
||||
s2jHook.free_fn(student);
|
||||
```
|
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2016, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Types plugin source code for this library.
|
||||
* Created on: 2015-12-16
|
||||
*/
|
||||
|
||||
#include "ef_types.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* array support types
|
||||
*/
|
||||
typedef enum {
|
||||
EF_ARRAY_TYPES_BOOL,
|
||||
EF_ARRAY_TYPES_CHAR,
|
||||
EF_ARRAY_TYPES_SHORT,
|
||||
EF_ARRAY_TYPES_INT,
|
||||
EF_ARRAY_TYPES_LONG,
|
||||
EF_ARRAY_TYPES_FLOAT,
|
||||
EF_ARRAY_TYPES_DOUBLE,
|
||||
EF_ARRAY_TYPES_STRING,
|
||||
} ef_array_types;
|
||||
|
||||
/**
|
||||
* EasyFlash types plugin initialize.
|
||||
*
|
||||
* @param hook Memory management hook function.
|
||||
* If hook is null or not call this function, then use free and malloc of C library.
|
||||
*/
|
||||
void ef_types_init(S2jHook *hook) {
|
||||
s2j_init(hook);
|
||||
}
|
||||
|
||||
bool ef_get_bool(const char *key) {
|
||||
char *value = ef_get_env(key);
|
||||
if(value) {
|
||||
return atoi(value) == 0 ? false : true;
|
||||
} else {
|
||||
EF_INFO("Couldn't find this ENV(%s)!\n", key);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char ef_get_char(const char *key) {
|
||||
return ef_get_long(key);
|
||||
}
|
||||
|
||||
short ef_get_short(const char *key) {
|
||||
return ef_get_long(key);
|
||||
}
|
||||
|
||||
int ef_get_int(const char *key) {
|
||||
return ef_get_long(key);
|
||||
}
|
||||
|
||||
long ef_get_long(const char *key) {
|
||||
char *value = ef_get_env(key);
|
||||
if(value) {
|
||||
return atol(value);
|
||||
} else {
|
||||
EF_INFO("Couldn't find this ENV(%s)!\n", key);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
float ef_get_float(const char *key) {
|
||||
return ef_get_double(key);
|
||||
}
|
||||
|
||||
double ef_get_double(const char *key) {
|
||||
char *value = ef_get_env(key);
|
||||
if(value) {
|
||||
return atof(value);
|
||||
} else {
|
||||
EF_INFO("Couldn't find this ENV(%s)!\n", key);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get array ENV value
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value returned ENV value
|
||||
* @param types ENV array's type
|
||||
*/
|
||||
static void ef_get_array(const char *key, void *value, ef_array_types types) {
|
||||
char *char_value = ef_get_env(key);
|
||||
cJSON *array;
|
||||
size_t size, i;
|
||||
|
||||
EF_ASSERT(value);
|
||||
|
||||
if (char_value) {
|
||||
array = cJSON_Parse(char_value);
|
||||
if (array) {
|
||||
size = cJSON_GetArraySize(array);
|
||||
for (i = 0; i < size; i++) {
|
||||
switch (types) {
|
||||
case EF_ARRAY_TYPES_BOOL: {
|
||||
*((bool *) value + i) = cJSON_GetArrayItem(array, i)->valueint;
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_CHAR: {
|
||||
*((char *) value + i) = cJSON_GetArrayItem(array, i)->valueint;
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_SHORT: {
|
||||
*((short *) value + i) = cJSON_GetArrayItem(array, i)->valueint;
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_INT: {
|
||||
*((int *) value + i) = cJSON_GetArrayItem(array, i)->valueint;
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_LONG: {
|
||||
*((long *) value + i) = cJSON_GetArrayItem(array, i)->valueint;
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_FLOAT: {
|
||||
*((float *) value + i) = cJSON_GetArrayItem(array, i)->valuedouble;
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_DOUBLE: {
|
||||
*((double *) value + i) = cJSON_GetArrayItem(array, i)->valuedouble;
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_STRING: {
|
||||
*((char **) value + i) = cJSON_GetArrayItem(array, i)->valuestring;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EF_INFO("This ENV(%s) value type has error!\n", key);
|
||||
}
|
||||
cJSON_Delete(array);
|
||||
} else {
|
||||
EF_INFO("Couldn't find this ENV(%s)!\n", key);
|
||||
}
|
||||
}
|
||||
|
||||
void ef_get_bool_array(const char *key, bool *value) {
|
||||
ef_get_array(key, value, EF_ARRAY_TYPES_BOOL);
|
||||
}
|
||||
|
||||
void ef_get_char_array(const char *key, char *value) {
|
||||
ef_get_array(key, value, EF_ARRAY_TYPES_CHAR);
|
||||
}
|
||||
|
||||
void ef_get_short_array(const char *key, short *value) {
|
||||
ef_get_array(key, value, EF_ARRAY_TYPES_SHORT);
|
||||
}
|
||||
|
||||
void ef_get_int_array(const char *key, int *value) {
|
||||
ef_get_array(key, value, EF_ARRAY_TYPES_INT);
|
||||
}
|
||||
|
||||
void ef_get_long_array(const char *key, long *value) {
|
||||
ef_get_array(key, value, EF_ARRAY_TYPES_LONG);
|
||||
}
|
||||
|
||||
void ef_get_float_array(const char *key, float *value) {
|
||||
ef_get_array(key, value, EF_ARRAY_TYPES_FLOAT);
|
||||
}
|
||||
|
||||
void ef_get_double_array(const char *key, double *value) {
|
||||
ef_get_array(key, value, EF_ARRAY_TYPES_DOUBLE);
|
||||
}
|
||||
|
||||
void ef_get_string_array(const char *key, char **value) {
|
||||
ef_get_array(key, value, EF_ARRAY_TYPES_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* get structure ENV value
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param get_cb get structure callback function.
|
||||
* You can use json to structure function which in the struct2json lib(https://github.com/armink/struct2json).
|
||||
*
|
||||
* @return value returned structure ENV value pointer. @note The returned value will malloc new ram.
|
||||
* You must free the value then used finish.
|
||||
*/
|
||||
void *ef_get_struct(const char *key, ef_types_get_cb get_cb) {
|
||||
char *char_value = ef_get_env(key);
|
||||
cJSON *json_value = cJSON_Parse(char_value);
|
||||
void *value = NULL;
|
||||
|
||||
if (json_value) {
|
||||
value = get_cb(json_value);
|
||||
cJSON_Delete(json_value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
EfErrCode ef_set_bool(const char *key, bool value) {
|
||||
char char_value[2] = { 0 };
|
||||
if (!value) {
|
||||
strcpy(char_value, "0");
|
||||
} else {
|
||||
strcpy(char_value, "1");
|
||||
}
|
||||
return ef_set_env(key, char_value);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_char(const char *key, char value) {
|
||||
return ef_set_long(key, value);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_short(const char *key, short value) {
|
||||
return ef_set_long(key, value);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_int(const char *key, int value) {
|
||||
return ef_set_long(key, value);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_long(const char *key, long value) {
|
||||
char char_value[21] = { 0 };
|
||||
|
||||
snprintf(char_value, 20, "%ld", value);
|
||||
|
||||
return ef_set_env(key, char_value);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_float(const char *key, float value) {
|
||||
return ef_set_double(key, value);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_double(const char *key, double value) {
|
||||
char char_value[21] = { 0 };
|
||||
|
||||
snprintf(char_value, 20, "%lf", value);
|
||||
|
||||
return ef_set_env(key, char_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* set array ENV value
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
* @param len array length
|
||||
* @param types ENV array's type
|
||||
*
|
||||
* @return ENV set result
|
||||
*/
|
||||
static EfErrCode ef_set_array(const char *key, void *value, size_t len, ef_array_types types) {
|
||||
char *char_value = NULL;
|
||||
cJSON *array = NULL, *array_item = NULL;
|
||||
size_t i;
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
EF_ASSERT(value);
|
||||
|
||||
array = cJSON_CreateArray();
|
||||
if (array) {
|
||||
for (i = 0; i < len; i++) {
|
||||
switch (types) {
|
||||
case EF_ARRAY_TYPES_BOOL: {
|
||||
array_item = cJSON_CreateBool(*((bool *) value + i));
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_CHAR: {
|
||||
array_item = cJSON_CreateNumber(*((char *) value + i));
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_SHORT: {
|
||||
array_item = cJSON_CreateNumber(*((short *) value + i));
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_INT: {
|
||||
array_item = cJSON_CreateNumber(*((int *) value + i));
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_LONG: {
|
||||
array_item = cJSON_CreateNumber(*((long *) value + i));
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_FLOAT: {
|
||||
array_item = cJSON_CreateNumber(*((float *) value + i));
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_DOUBLE: {
|
||||
array_item = cJSON_CreateNumber(*((double *) value + i));
|
||||
break;
|
||||
}
|
||||
case EF_ARRAY_TYPES_STRING: {
|
||||
array_item = cJSON_CreateString(*((char **) value + i));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* the types parameter has error */
|
||||
EF_ASSERT(0);
|
||||
}
|
||||
if (array_item) {
|
||||
cJSON_AddItemToArray(array, array_item);
|
||||
} else {
|
||||
result = EF_ENV_FULL;
|
||||
EF_INFO("Memory full!\n", key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
char_value = cJSON_PrintUnformatted(array);
|
||||
if (char_value) {
|
||||
result = ef_set_env(key, char_value);
|
||||
s2jHook.free_fn(char_value);
|
||||
} else {
|
||||
result = EF_ENV_FULL;
|
||||
EF_INFO("Memory full!\n", key);
|
||||
}
|
||||
cJSON_Delete(array);
|
||||
} else {
|
||||
result = EF_ENV_FULL;
|
||||
EF_INFO("Memory full!\n", key);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
EfErrCode ef_set_bool_array(const char *key, bool *value, size_t len) {
|
||||
return ef_set_array(key, value, len, EF_ARRAY_TYPES_BOOL);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_char_array(const char *key, char *value, size_t len) {
|
||||
return ef_set_array(key, value, len, EF_ARRAY_TYPES_CHAR);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_short_array(const char *key, short *value, size_t len) {
|
||||
return ef_set_array(key, value, len, EF_ARRAY_TYPES_SHORT);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_int_array(const char *key, int *value, size_t len) {
|
||||
return ef_set_array(key, value, len, EF_ARRAY_TYPES_INT);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_long_array(const char *key, long *value, size_t len) {
|
||||
return ef_set_array(key, value, len, EF_ARRAY_TYPES_LONG);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_float_array(const char *key, float *value, size_t len) {
|
||||
return ef_set_array(key, value, len, EF_ARRAY_TYPES_FLOAT);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_double_array(const char *key, double *value, size_t len) {
|
||||
return ef_set_array(key, value, len, EF_ARRAY_TYPES_DOUBLE);
|
||||
}
|
||||
|
||||
EfErrCode ef_set_string_array(const char *key, char **value, size_t len) {
|
||||
return ef_set_array(key, value, len, EF_ARRAY_TYPES_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* set structure ENV value
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value structure ENV value pointer
|
||||
* @param get_cb set structure callback function.
|
||||
* You can use structure to json function which in the struct2json lib(https://github.com/armink/struct2json).
|
||||
*/
|
||||
EfErrCode ef_set_struct(const char *key, void *value, ef_types_set_cb set_cb) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
cJSON *json_value = set_cb(value);
|
||||
char *char_value = cJSON_PrintUnformatted(json_value);
|
||||
|
||||
result = ef_set_env(key, char_value);
|
||||
|
||||
cJSON_Delete(json_value);
|
||||
s2jHook.free_fn(char_value);
|
||||
|
||||
return result;
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2016, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is an head file for this plugin. You can see all be called functions.
|
||||
* Created on: 2015-12-16
|
||||
*/
|
||||
|
||||
#ifndef EF_TYPES_H_
|
||||
#define EF_TYPES_H_
|
||||
|
||||
#include <easyflash.h>
|
||||
#include <stdbool.h>
|
||||
#include "struct2json\inc\s2j.h"
|
||||
|
||||
/* EasyFlash types plugin's software version number */
|
||||
#define EF_TYPES_SW_VERSION "0.11.03"
|
||||
|
||||
typedef cJSON *(*ef_types_set_cb)(void* struct_obj);
|
||||
typedef void *(*ef_types_get_cb)(cJSON* json_obj);
|
||||
|
||||
void ef_types_init(S2jHook *hook);
|
||||
bool ef_get_bool(const char *key);
|
||||
char ef_get_char(const char *key);
|
||||
short ef_get_short(const char *key);
|
||||
int ef_get_int(const char *key);
|
||||
long ef_get_long(const char *key);
|
||||
float ef_get_float(const char *key);
|
||||
double ef_get_double(const char *key);
|
||||
void ef_get_bool_array(const char *key, bool *value);
|
||||
void ef_get_char_array(const char *key, char *value);
|
||||
void ef_get_short_array(const char *key, short *value);
|
||||
void ef_get_int_array(const char *key, int *value);
|
||||
void ef_get_long_array(const char *key, long *value);
|
||||
void ef_get_float_array(const char *key, float *value);
|
||||
void ef_get_double_array(const char *key, double *value);
|
||||
void ef_get_string_array(const char *key, char **value);
|
||||
void *ef_get_struct(const char *key, ef_types_get_cb get_cb);
|
||||
EfErrCode ef_set_bool(const char *key, bool value);
|
||||
EfErrCode ef_set_char(const char *key, char value);
|
||||
EfErrCode ef_set_short(const char *key, short value);
|
||||
EfErrCode ef_set_int(const char *key, int value);
|
||||
EfErrCode ef_set_long(const char *key, long value);
|
||||
EfErrCode ef_set_float(const char *key, float value);
|
||||
EfErrCode ef_set_double(const char *key, double value);
|
||||
EfErrCode ef_set_bool_array(const char *key, bool *value, size_t len);
|
||||
EfErrCode ef_set_char_array(const char *key, char *value, size_t len);
|
||||
EfErrCode ef_set_short_array(const char *key, short *value, size_t len);
|
||||
EfErrCode ef_set_int_array(const char *key, int *value, size_t len);
|
||||
EfErrCode ef_set_long_array(const char *key, long *value, size_t len);
|
||||
EfErrCode ef_set_float_array(const char *key, float *value, size_t len);
|
||||
EfErrCode ef_set_double_array(const char *key, double *value, size_t len);
|
||||
EfErrCode ef_set_string_array(const char *key, char **value, size_t len);
|
||||
EfErrCode ef_set_struct(const char *key, void *value, ef_types_set_cb set_cb);
|
||||
|
||||
#endif /* EF_TYPES_H_ */
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
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
|
||||
|
||||
#include <stddef.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);
|
||||
extern int cJSON_HasObjectItem(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))
|
||||
|
||||
/* Macro for iterating over an array */
|
||||
#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* This file is part of the struct2json Library.
|
||||
*
|
||||
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is an head file for this library. You can see all be called functions.
|
||||
* Created on: 2015-10-14
|
||||
*/
|
||||
|
||||
#ifndef __S2J_H__
|
||||
#define __S2J_H__
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <string.h>
|
||||
#include "s2jdef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* struct2json software version number */
|
||||
#define S2J_SW_VERSION "1.0.2"
|
||||
|
||||
/* Create JSON object */
|
||||
#define s2j_create_json_obj(json_obj) \
|
||||
S2J_CREATE_JSON_OBJECT(json_obj)
|
||||
|
||||
/* Delete JSON object */
|
||||
#define s2j_delete_json_obj(json_obj) \
|
||||
S2J_DELETE_JSON_OBJECT(json_obj)
|
||||
|
||||
/* Set basic type element for JSON object */
|
||||
#define s2j_json_set_basic_element(to_json, from_struct, type, element) \
|
||||
S2J_JSON_SET_BASIC_ELEMENT(to_json, from_struct, type, element)
|
||||
|
||||
/* Set array type element for JSON object */
|
||||
#define s2j_json_set_array_element(to_json, from_struct, type, element, size) \
|
||||
S2J_JSON_SET_ARRAY_ELEMENT(to_json, from_struct, type, element, size)
|
||||
|
||||
/* Set child structure type element for JSON object */
|
||||
#define s2j_json_set_struct_element(child_json, to_json, child_struct, from_struct, type, element) \
|
||||
S2J_JSON_SET_STRUCT_ELEMENT(child_json, to_json, child_struct, from_struct, type, element)
|
||||
|
||||
/* Create structure object */
|
||||
#define s2j_create_struct_obj(struct_obj, type) \
|
||||
S2J_CREATE_STRUCT_OBJECT(struct_obj, type)
|
||||
|
||||
/* Delete structure object */
|
||||
#define s2j_delete_struct_obj(struct_obj) \
|
||||
S2J_DELETE_STRUCT_OBJECT(struct_obj)
|
||||
|
||||
/* Get basic type element for structure object */
|
||||
#define s2j_struct_get_basic_element(to_struct, from_json, type, element) \
|
||||
S2J_STRUCT_GET_BASIC_ELEMENT(to_struct, from_json, type, element)
|
||||
|
||||
/* Get array type element for structure object */
|
||||
#define s2j_struct_get_array_element(to_struct, from_json, type, element) \
|
||||
S2J_STRUCT_GET_ARRAY_ELEMENT(to_struct, from_json, type, element)
|
||||
|
||||
/* Get child structure type element for structure object */
|
||||
#define s2j_struct_get_struct_element(child_struct, to_struct, child_json, from_json, type, element) \
|
||||
S2J_STRUCT_GET_STRUCT_ELEMENT(child_struct, to_struct, child_json, from_json, type, element)
|
||||
|
||||
/* s2j.c */
|
||||
extern S2jHook s2jHook;
|
||||
void s2j_init(S2jHook *hook);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __S2J_H__ */
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* This file is part of the struct2json Library.
|
||||
*
|
||||
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is an head file for this library.
|
||||
* Created on: 2015-10-14
|
||||
*/
|
||||
|
||||
#ifndef __S2JDEF_H__
|
||||
#define __S2JDEF_H__
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} S2jHook, *S2jHook_t;
|
||||
|
||||
#define S2J_STRUCT_GET_int_ELEMENT(to_struct, from_json, _element) \
|
||||
json_temp = cJSON_GetObjectItem(from_json, #_element); \
|
||||
if (json_temp) (to_struct)->_element = json_temp->valueint;
|
||||
|
||||
#define S2J_STRUCT_GET_string_ELEMENT(to_struct, from_json, _element) \
|
||||
json_temp = cJSON_GetObjectItem(from_json, #_element); \
|
||||
if (json_temp) strcpy((to_struct)->_element, json_temp->valuestring);
|
||||
|
||||
#define S2J_STRUCT_GET_double_ELEMENT(to_struct, from_json, _element) \
|
||||
json_temp = cJSON_GetObjectItem(from_json, #_element); \
|
||||
if (json_temp) (to_struct)->_element = json_temp->valuedouble;
|
||||
|
||||
#define S2J_STRUCT_ARRAY_GET_int_ELEMENT(to_struct, from_json, _element, index) \
|
||||
(to_struct)->_element[index] = from_json->valueint;
|
||||
|
||||
#define S2J_STRUCT_ARRAY_GET_string_ELEMENT(to_struct, from_json, _element, index) \
|
||||
strcpy((to_struct)->_element[index], from_json->valuestring);
|
||||
|
||||
#define S2J_STRUCT_ARRAY_GET_double_ELEMENT(to_struct, from_json, _element, index) \
|
||||
(to_struct)->_element[index] = from_json->valuedouble;
|
||||
|
||||
#define S2J_STRUCT_ARRAY_GET_ELEMENT(to_struct, from_json, type, _element, index) \
|
||||
S2J_STRUCT_ARRAY_GET_##type##_ELEMENT(to_struct, from_json, _element, index)
|
||||
|
||||
#define S2J_JSON_SET_int_ELEMENT(to_json, from_struct, _element) \
|
||||
cJSON_AddNumberToObject(to_json, #_element, (from_struct)->_element);
|
||||
|
||||
#define S2J_JSON_SET_double_ELEMENT(to_json, from_struct, _element) \
|
||||
cJSON_AddNumberToObject(to_json, #_element, (from_struct)->_element);
|
||||
|
||||
#define S2J_JSON_SET_string_ELEMENT(to_json, from_struct, _element) \
|
||||
cJSON_AddStringToObject(to_json, #_element, (from_struct)->_element);
|
||||
|
||||
#define S2J_JSON_ARRAY_SET_int_ELEMENT(to_json, from_struct, _element, index) \
|
||||
cJSON_AddItemToArray(to_json, cJSON_CreateNumber((from_struct)->_element[index]));
|
||||
|
||||
#define S2J_JSON_ARRAY_SET_double_ELEMENT(to_json, from_struct, _element, index) \
|
||||
cJSON_AddItemToArray(to_json, cJSON_CreateNumber((from_struct)->_element[index]));
|
||||
|
||||
#define S2J_JSON_ARRAY_SET_string_ELEMENT(to_json, from_struct, _element, index) \
|
||||
cJSON_AddItemToArray(to_json, cJSON_CreateString((from_struct)->_element[index]));
|
||||
|
||||
#define S2J_JSON_ARRAY_SET_ELEMENT(to_json, from_struct, type, _element, index) \
|
||||
S2J_JSON_ARRAY_SET_##type##_ELEMENT(to_json, from_struct, _element, index)
|
||||
|
||||
|
||||
#define S2J_CREATE_JSON_OBJECT(json_obj) \
|
||||
cJSON *json_obj = cJSON_CreateObject();
|
||||
|
||||
#define S2J_DELETE_JSON_OBJECT(json_obj) \
|
||||
cJSON_Delete(json_obj);
|
||||
|
||||
#define S2J_JSON_SET_BASIC_ELEMENT(to_json, from_struct, type, _element) \
|
||||
S2J_JSON_SET_##type##_ELEMENT(to_json, from_struct, _element)
|
||||
|
||||
#define S2J_JSON_SET_ARRAY_ELEMENT(to_json, from_struct, type, _element, size) \
|
||||
{ \
|
||||
cJSON *array; \
|
||||
size_t index = 0; \
|
||||
array = cJSON_CreateArray(); \
|
||||
if (array) { \
|
||||
while (index < size) { \
|
||||
S2J_JSON_ARRAY_SET_ELEMENT(array, from_struct, type, _element, index++); \
|
||||
} \
|
||||
cJSON_AddItemToObject(to_json, #_element, array); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define S2J_JSON_SET_STRUCT_ELEMENT(child_json, to_json, child_struct, from_struct, type, _element) \
|
||||
type *child_struct = &((from_struct)->_element); \
|
||||
cJSON *child_json = cJSON_CreateObject(); \
|
||||
if (child_json) cJSON_AddItemToObject(to_json, #_element, child_json);
|
||||
|
||||
#define S2J_CREATE_STRUCT_OBJECT(struct_obj, type) \
|
||||
cJSON *json_temp; \
|
||||
type *struct_obj = s2jHook.malloc_fn(sizeof(type)); \
|
||||
if (struct_obj) memset(struct_obj, 0, sizeof(type));
|
||||
|
||||
#define S2J_DELETE_STRUCT_OBJECT(struct_obj) \
|
||||
s2jHook.free_fn(struct_obj);
|
||||
|
||||
#define S2J_STRUCT_GET_BASIC_ELEMENT(to_struct, from_json, type, _element) \
|
||||
S2J_STRUCT_GET_##type##_ELEMENT(to_struct, from_json, _element)
|
||||
|
||||
#define S2J_STRUCT_GET_ARRAY_ELEMENT(to_struct, from_json, type, _element) \
|
||||
{ \
|
||||
cJSON *array, *array_element; \
|
||||
size_t index = 0, size = 0; \
|
||||
array = cJSON_GetObjectItem(from_json, #_element); \
|
||||
if (array) { \
|
||||
size = cJSON_GetArraySize(array); \
|
||||
while (index < size) { \
|
||||
array_element = cJSON_GetArrayItem(array, index); \
|
||||
if (array_element) S2J_STRUCT_ARRAY_GET_ELEMENT(to_struct, array_element, type, _element, index++); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define S2J_STRUCT_GET_STRUCT_ELEMENT(child_struct, to_struct, child_json, from_json, type, _element) \
|
||||
type *child_struct = &((to_struct)->_element); \
|
||||
cJSON *child_json = cJSON_GetObjectItem(from_json, #_element);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __S2JDEF_H__ */
|
@ -0,0 +1,61 @@
|
||||
# C结构体与 JSON 快速互转库
|
||||
|
||||
---
|
||||
|
||||
## struct2json
|
||||
|
||||
[struct2json](https://github.com/armink/struct2json) 是一个开源的C结构体与 JSON 快速互转库,它可以快速实现 **结构体对象** 与 **JSON 对象** 之间序列化及反序列化要求。快速、简洁的 API 设计,大大降低直接使用 JSON 解析库来实现此类功能的代码复杂度。
|
||||
|
||||
## 起源
|
||||
|
||||
把面向对象设计应用到C语言中,是当下很流行的设计思想。由于C语言中没有类,所以一般使用结构体 `struct` 充当类,那么结构体变量就是对象。有了对象之后,很多时候需要考虑对象的序列化及反序列化问题。C语言不像很多高级语言拥有反射等机制,使得对象序列化及反序列化被原生的支持。
|
||||
|
||||
对于C语言来说,序列化为 JSON 字符串是个不错的选择,所以就得使用 [cJSON](https://github.com/kbranigan/cJSON) 这类 JSON 解析库,但是使用后的代码冗余且逻辑性差,所以萌生对cJSON库进行二次封装,实现一个 struct 与 JSON 之间快速互转的库。 struct2json 就诞生于此。下面是 struct2json 主要使用场景:
|
||||
|
||||
- **持久化** :结构体对象序列化为 JSON 对象后,可直接保存至文件、Flash,实现对结构体对象的掉电存储;
|
||||
- **通信** :高级语言对JSON支持的很友好,例如: Javascript、Groovy 就对 JSON 具有原生的支持,所以 JSON 也可作为C语言与其他语言软件之间的通信协议格式及对象传递格式;
|
||||
- **可视化** :序列化为 JSON 后的对象,可以更加直观的展示到控制台或者 UI 上,可用于产品调试、产品二次开发等场景;
|
||||
|
||||
## 如何使用
|
||||
|
||||
### 声明结构体
|
||||
|
||||
如下声明了两个结构体,结构体 `Hometown` 是结构体 `Student` 的子结构体
|
||||
|
||||
```C
|
||||
/* 籍贯 */
|
||||
typedef struct {
|
||||
char name[16];
|
||||
} Hometown;
|
||||
|
||||
/* 学生 */
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
uint8_t score[8];
|
||||
char name[10];
|
||||
double weight;
|
||||
Hometown hometown;
|
||||
} Student;
|
||||
```
|
||||
|
||||
### 将结构体对象序列化为 JSON 对象
|
||||
|
||||
|使用前([源文件](https://github.com/armink/struct2json/blob/master/docs/zh/assets/not_use_struct2json.c))|使用后([源文件](https://github.com/armink/struct2json/blob/master/docs/zh/assets/used_struct2json.c))|
|
||||
|:-----:|:-----:|
|
||||
|![结构体转JSON-使用前](https://git.oschina.net/Armink/struct2json/raw/master/docs/zh/images/not_use_struct2json.png)| ![结构体转JSON-使用后](https://git.oschina.net/Armink/struct2json/raw/master/docs/zh/images/used_struct2json.png)|
|
||||
|
||||
### 将 JSON 对象反序列化为结构体对象
|
||||
|
||||
|使用前([源文件](https://github.com/armink/struct2json/blob/master/docs/zh/assets/not_use_struct2json_for_json.c))|使用后([源文件](https://github.com/armink/struct2json/blob/master/docs/zh/assets/used_struct2json_for_json.c))|
|
||||
|:-----:|:-----:|
|
||||
|![JSON转结构体-使用前](https://git.oschina.net/Armink/struct2json/raw/master/docs/zh/images/not_use_struct2json_for_json.png)| ![JSON转结构体-使用后](https://git.oschina.net/Armink/struct2json/raw/master/docs/zh/images/used_struct2json_for_json.png)|
|
||||
|
||||
欢迎大家 **fork and pull request**([Github](https://github.com/armink/struct2json)|[OSChina](http://git.oschina.net/armink/struct2json)|[Coding](https://coding.net/u/armink/p/struct2json/git)) 。如果觉得这个开源项目很赞,可以点击[项目主页](https://github.com/armink/struct2json) 右上角的**Star**,同时把它推荐给更多有需要的朋友。
|
||||
|
||||
## 文档
|
||||
|
||||
具体内容参考[`\docs\zh\`](https://github.com/armink/struct2json/tree/master/docs/zh)下的文件。务必保证在 **阅读文档** 后再使用。
|
||||
|
||||
## 许可
|
||||
|
||||
MIT Copyright (c) armink.ztl@gmail.com
|
@ -0,0 +1,762 @@
|
||||
/*
|
||||
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(*s1) == tolower(*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)) == NULL) 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 (fpclassify(d) != FP_ZERO && !isnormal(d)) sprintf(str,"null");
|
||||
else 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 (('\0' != (token=*ptr)) && ++len) {if (NULL != 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()) == NULL) 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()) == NULL) 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 && !fail)
|
||||
{
|
||||
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;}
|
||||
int cJSON_HasObjectItem(cJSON *object,const char *string) {
|
||||
cJSON *c=object->child;
|
||||
while (c )
|
||||
{
|
||||
if(cJSON_strcasecmp(c->string,string)==0){
|
||||
return 1;
|
||||
}
|
||||
c=c->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of the struct2json Library.
|
||||
*
|
||||
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Initialize interface for this library.
|
||||
* Created on: 2015-10-14
|
||||
*/
|
||||
|
||||
#include <s2j.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
S2jHook s2jHook = {
|
||||
.malloc_fn = malloc,
|
||||
.free_fn = free,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct2json library initialize
|
||||
* @note It will initialize cJSON library hooks.
|
||||
*/
|
||||
void s2j_init(S2jHook *hook) {
|
||||
/* initialize cJSON library */
|
||||
cJSON_InitHooks((cJSON_Hooks *)hook);
|
||||
/* initialize hooks */
|
||||
if (hook) {
|
||||
s2jHook.malloc_fn = (hook->malloc_fn) ? hook->malloc_fn : malloc;
|
||||
s2jHook.free_fn = (hook->free_fn) ? hook->free_fn : free;
|
||||
} else {
|
||||
hook->malloc_fn = malloc;
|
||||
hook->free_fn = free;
|
||||
}
|
||||
}
|
232
demo/os/nuttx-spiflash/apps/system/easyflash/port/ef_port.c
Normal file
232
demo/os/nuttx-spiflash/apps/system/easyflash/port/ef_port.c
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Portable interface for stm32f10x platform.
|
||||
* Created on: 2015-01-16
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
#include <nuttx/config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <nuttx/mtd/mtd.h>
|
||||
#include <nuttx/drivers/drivers.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
|
||||
/* default environment variables set for user */
|
||||
static const ef_env default_env_set[] = {
|
||||
{"iap_need_copy_app","0"},
|
||||
{"iap_copy_app_size","0"},
|
||||
{"stop_in_bootloader","0"},
|
||||
{"device_id","1"},
|
||||
{"boot_times","0"},
|
||||
};
|
||||
|
||||
static char log_buf[128];
|
||||
static pthread_mutex_t env_cache_lock;
|
||||
static FAR struct mtd_dev_s *mtd_dev;
|
||||
static const char *devpath="/dev/mtd0";
|
||||
|
||||
/**
|
||||
* Flash port for hardware initialize.
|
||||
*
|
||||
* @param default_env default ENV set for user
|
||||
* @param default_env_size default ENV size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_port_init(ef_env const **default_env, size_t *default_env_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
int fd;
|
||||
|
||||
*default_env = default_env_set;
|
||||
*default_env_size = sizeof(default_env_set) / sizeof(default_env_set[0]);
|
||||
|
||||
pthread_mutex_init(&env_cache_lock, NULL);
|
||||
|
||||
if (bchdev_register("/dev/mtdblock0", devpath, false) < 0){
|
||||
result = EF_ENV_INIT_FAILED;
|
||||
fprintf(stderr, "ERROR: bchdev_register /dev/mtd0 failed: %d\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fd = open(devpath, O_RDWR);
|
||||
if(fd < 0){
|
||||
result = EF_ENV_INIT_FAILED;
|
||||
fprintf(stderr, "ERROR: Failed to open %s: %d\n", devpath, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (ioctl(fd, MTDIOC_GETMTDDEV, (unsigned long) ((uintptr_t)&mtd_dev)) < 0){
|
||||
result = EF_ENV_INIT_FAILED;
|
||||
fprintf(stderr, "ERROR: Failed to set pintype on %s: %d\n",
|
||||
devpath, result);
|
||||
}
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from flash.
|
||||
* @note This operation's units is word.
|
||||
*
|
||||
* @param addr flash address
|
||||
* @param buf buffer to store read data
|
||||
* @param size read bytes size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
if(!MTD_READ(mtd_dev, addr, size, (uint8_t *)buf)){
|
||||
result = EF_READ_ERR;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase data on flash.
|
||||
* @note This operation is irreversible.
|
||||
* @note This operation's units is different which on many chips.
|
||||
*
|
||||
* @param addr flash address
|
||||
* @param size erase bytes size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_port_erase(uint32_t addr, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
/* make sure the start address is a multiple of FLASH_ERASE_MIN_SIZE */
|
||||
EF_ASSERT(addr % EF_ERASE_MIN_SIZE == 0);
|
||||
|
||||
if(!MTD_ERASE(mtd_dev, addr/EF_ERASE_MIN_SIZE, size/EF_ERASE_MIN_SIZE)){
|
||||
result = EF_ERASE_ERR;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to flash.
|
||||
* @note This operation's units is word.
|
||||
* @note This operation must after erase. @see flash_erase.
|
||||
*
|
||||
* @param addr flash address
|
||||
* @param buf the write data buffer
|
||||
* @param size write bytes size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
if(!MTD_WRITE(mtd_dev, addr, size, (const uint8_t *)buf)){
|
||||
result = EF_WRITE_ERR;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* lock the ENV ram cache
|
||||
*/
|
||||
void ef_port_env_lock(void) {
|
||||
pthread_mutex_lock(&env_cache_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* unlock the ENV ram cache
|
||||
*/
|
||||
void ef_port_env_unlock(void) {
|
||||
pthread_mutex_unlock(&env_cache_lock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is print flash debug info.
|
||||
*
|
||||
* @param file the file which has call this function
|
||||
* @param line the line number which has call this function
|
||||
* @param format output format
|
||||
* @param ... args
|
||||
*
|
||||
*/
|
||||
void ef_log_debug(const char *file, const long line, const char *format, ...) {
|
||||
|
||||
#ifdef PRINT_DEBUG
|
||||
|
||||
va_list args;
|
||||
|
||||
/* args point to the first variable parameter */
|
||||
va_start(args, format);
|
||||
printf("[Flash](%s:%ld) ", file, line);
|
||||
/* must use vprintf to print */
|
||||
vsprintf(log_buf, format, args);
|
||||
printf("%s", log_buf);
|
||||
va_end(args);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is print flash routine info.
|
||||
*
|
||||
* @param format output format
|
||||
* @param ... args
|
||||
*/
|
||||
void ef_log_info(const char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
/* args point to the first variable parameter */
|
||||
va_start(args, format);
|
||||
printf("[Flash]");
|
||||
/* must use vprintf to print */
|
||||
vsprintf(log_buf, format, args);
|
||||
printf("%s", log_buf);
|
||||
va_end(args);
|
||||
}
|
||||
/**
|
||||
* This function is print flash non-package info.
|
||||
*
|
||||
* @param format output format
|
||||
* @param ... args
|
||||
*/
|
||||
void ef_print(const char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
/* args point to the first variable parameter */
|
||||
va_start(args, format);
|
||||
/* must use vprintf to print */
|
||||
vsprintf(log_buf, format, args);
|
||||
printf("%s", log_buf);
|
||||
va_end(args);
|
||||
}
|
109
demo/os/nuttx-spiflash/apps/system/easyflash/src/easyflash.c
Normal file
109
demo/os/nuttx-spiflash/apps/system/easyflash/src/easyflash.c
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2014-2019, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Initialize interface for this library.
|
||||
* Created on: 2014-09-09
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* This all Backup Area Flash storage index. All used flash area configure is under here.
|
||||
* |----------------------------| Storage Size
|
||||
* | Environment variables area | ENV area size @see ENV_AREA_SIZE
|
||||
* |----------------------------|
|
||||
* | Saved log area | Log area size @see LOG_AREA_SIZE
|
||||
* |----------------------------|
|
||||
* |(IAP)Downloaded application | IAP already downloaded application, unfixed size
|
||||
* |----------------------------|
|
||||
*
|
||||
* @note all area sizes must be aligned with EF_ERASE_MIN_SIZE
|
||||
*
|
||||
* The EasyFlash add the NG (Next Generation) mode start from V4.0. All old mode before V4.0, called LEGACY mode.
|
||||
*
|
||||
* - NG (Next Generation) mode is default mode from V4.0. It's easy to settings, only defined the ENV_AREA_SIZE.
|
||||
* - The LEGACY mode has been DEPRECATED. It is NOT RECOMMENDED to continue using.
|
||||
* Beacuse it will use ram to buffer the ENV and spend more flash erase times.
|
||||
* If you want use it please using the V3.X version.
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
|
||||
#if !defined(EF_START_ADDR)
|
||||
#error "Please configure backup area start address (in ef_cfg.h)"
|
||||
#endif
|
||||
|
||||
#if !defined(EF_ERASE_MIN_SIZE)
|
||||
#error "Please configure minimum size of flash erasure (in ef_cfg.h)"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* EasyFlash system initialize.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode easyflash_init(void) {
|
||||
extern EfErrCode ef_port_init(ef_env const **default_env, size_t *default_env_size);
|
||||
extern EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size);
|
||||
extern EfErrCode ef_iap_init(void);
|
||||
extern EfErrCode ef_log_init(void);
|
||||
|
||||
size_t default_env_set_size = 0;
|
||||
const ef_env *default_env_set;
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
static bool init_ok = false;
|
||||
|
||||
if (init_ok) {
|
||||
return EF_NO_ERR;
|
||||
}
|
||||
|
||||
result = ef_port_init(&default_env_set, &default_env_set_size);
|
||||
|
||||
#ifdef EF_USING_ENV
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_env_init(default_env_set, default_env_set_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EF_USING_IAP
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_iap_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EF_USING_LOG
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_log_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (result == EF_NO_ERR) {
|
||||
init_ok = true;
|
||||
EF_INFO("EasyFlash V%s is initialize success.\n", EF_SW_VERSION);
|
||||
} else {
|
||||
EF_INFO("EasyFlash V%s is initialize fail.\n", EF_SW_VERSION);
|
||||
}
|
||||
EF_INFO("You can get the latest version on https://github.com/armink/EasyFlash .\n");
|
||||
|
||||
return result;
|
||||
}
|
1841
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_env.c
Normal file
1841
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_env.c
Normal file
File diff suppressed because it is too large
Load Diff
922
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_env_legacy.c
Normal file
922
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_env_legacy.c
Normal file
@ -0,0 +1,922 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2014-2018, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Environment variables operating interface. (normal mode)
|
||||
* Created on: 2014-10-06
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(EF_USING_ENV) && defined(EF_ENV_USING_LEGACY_MODE)
|
||||
|
||||
#ifndef EF_ENV_USING_WL_MODE
|
||||
|
||||
#if defined(EF_USING_ENV) && (!defined(ENV_USER_SETTING_SIZE) || !defined(ENV_AREA_SIZE))
|
||||
#error "Please configure user setting ENV size or ENV area size (in ef_cfg.h)"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ENV area has 2 sections
|
||||
* 1. System section
|
||||
* It storages ENV parameters. (Units: Word)
|
||||
* 2. Data section
|
||||
* It storages all ENV. Storage format is key=value\0.
|
||||
* All ENV must be 4 bytes alignment. The remaining part must fill '\0'.
|
||||
*
|
||||
* @note Word = 4 Bytes in this file
|
||||
* @note When using power fail safeguard mode, it has two ENV areas(Area0, Area1).
|
||||
*/
|
||||
|
||||
/* flash ENV parameters index and size in system section */
|
||||
enum {
|
||||
/* data section ENV end address index in system section */
|
||||
ENV_PARAM_INDEX_END_ADDR = 0,
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* saved count for ENV area */
|
||||
ENV_PARAM_INDEX_SAVED_COUNT,
|
||||
#endif
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
/* current version number for ENV */
|
||||
ENV_PARAM_INDEX_VER_NUM,
|
||||
#endif
|
||||
|
||||
/* data section CRC32 code index in system section */
|
||||
ENV_PARAM_INDEX_DATA_CRC,
|
||||
/* flash ENV parameters word size */
|
||||
ENV_PARAM_WORD_SIZE,
|
||||
/* flash ENV parameters byte size */
|
||||
ENV_PARAM_BYTE_SIZE = ENV_PARAM_WORD_SIZE * 4,
|
||||
};
|
||||
|
||||
/* default ENV set, must be initialized by user */
|
||||
static ef_env const *default_env_set;
|
||||
/* default ENV set size, must be initialized by user */
|
||||
static size_t default_env_set_size = 0;
|
||||
/* ENV ram cache */
|
||||
static uint32_t env_cache[ENV_USER_SETTING_SIZE / 4] = { 0 };
|
||||
/* ENV start address in flash */
|
||||
static uint32_t env_start_addr = 0;
|
||||
/* ENV ram cache has changed when ENV created, deleted and changed value. */
|
||||
static bool env_cache_changed = false;
|
||||
/* initialize OK flag */
|
||||
static bool init_ok = false;
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* current load ENV area address */
|
||||
static uint32_t cur_load_area_addr = 0;
|
||||
/* next save ENV area address */
|
||||
static uint32_t next_save_area_addr = 0;
|
||||
#endif
|
||||
|
||||
static uint32_t get_env_system_addr(void);
|
||||
static uint32_t get_env_data_addr(void);
|
||||
static uint32_t get_env_end_addr(void);
|
||||
static void set_env_end_addr(uint32_t end_addr);
|
||||
static EfErrCode write_env(const char *key, const char *value);
|
||||
static char *find_env(const char *key);
|
||||
static EfErrCode del_env(const char *key);
|
||||
static size_t get_env_data_size(void);
|
||||
static size_t get_env_user_used_size(void);
|
||||
static EfErrCode create_env(const char *key, const char *value);
|
||||
static uint32_t calc_env_crc(void);
|
||||
static bool env_crc_is_ok(void);
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
static EfErrCode env_auto_update(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Flash ENV initialize.
|
||||
*
|
||||
* @param default_env default ENV set for user
|
||||
* @param default_env_size default ENV set size
|
||||
*
|
||||
* @note user_size must equal with total_size in normal mode
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
EF_ASSERT(ENV_AREA_SIZE);
|
||||
EF_ASSERT(ENV_USER_SETTING_SIZE);
|
||||
EF_ASSERT(EF_ERASE_MIN_SIZE);
|
||||
/* must be word alignment for ENV */
|
||||
EF_ASSERT(ENV_USER_SETTING_SIZE % 4 == 0);
|
||||
EF_ASSERT(ENV_AREA_SIZE % 4 == 0);
|
||||
EF_ASSERT(default_env);
|
||||
EF_ASSERT(default_env_size < ENV_USER_SETTING_SIZE);
|
||||
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
/* total_size must be aligned with erase_min_size */
|
||||
if (ENV_USER_SETTING_SIZE % EF_ERASE_MIN_SIZE == 0) {
|
||||
EF_ASSERT(ENV_USER_SETTING_SIZE == ENV_AREA_SIZE);
|
||||
} else {
|
||||
EF_ASSERT((ENV_USER_SETTING_SIZE / EF_ERASE_MIN_SIZE + 1)*EF_ERASE_MIN_SIZE == ENV_AREA_SIZE);
|
||||
}
|
||||
#else
|
||||
/* total_size must be aligned with erase_min_size */
|
||||
if (ENV_USER_SETTING_SIZE % EF_ERASE_MIN_SIZE == 0) {
|
||||
/* it has double area when used power fail safeguard mode */
|
||||
EF_ASSERT(2 * ENV_USER_SETTING_SIZE == ENV_AREA_SIZE);
|
||||
} else {
|
||||
/* it has double area when used power fail safeguard mode */
|
||||
EF_ASSERT(2 * (ENV_USER_SETTING_SIZE / EF_ERASE_MIN_SIZE + 1)*EF_ERASE_MIN_SIZE == ENV_AREA_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
env_start_addr = EF_START_ADDR;
|
||||
default_env_set = default_env;
|
||||
default_env_set_size = default_env_size;
|
||||
|
||||
EF_DEBUG("ENV start address is 0x%08X, size is %d bytes.\n", EF_START_ADDR, ENV_AREA_SIZE);
|
||||
|
||||
result = ef_load_env();
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
if (result == EF_NO_ERR) {
|
||||
env_auto_update();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (result == EF_NO_ERR) {
|
||||
init_ok = true;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ENV set default.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_env_set_default(void) {
|
||||
extern EfErrCode ef_env_ver_num_set_default(void);
|
||||
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t i;
|
||||
|
||||
EF_ASSERT(default_env_set);
|
||||
EF_ASSERT(default_env_set_size);
|
||||
|
||||
/* lock the ENV cache */
|
||||
ef_port_env_lock();
|
||||
|
||||
/* set environment end address is at data section start address */
|
||||
set_env_end_addr(get_env_data_addr());
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* set saved count to default 0 */
|
||||
env_cache[ENV_PARAM_INDEX_SAVED_COUNT] = 0;
|
||||
#endif
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
/* initialize version number */
|
||||
env_cache[ENV_PARAM_INDEX_VER_NUM] = EF_ENV_VER_NUM;
|
||||
#endif
|
||||
|
||||
/* create default ENV */
|
||||
for (i = 0; i < default_env_set_size; i++) {
|
||||
create_env(default_env_set[i].key, default_env_set[i].value);
|
||||
}
|
||||
|
||||
/* unlock the ENV cache */
|
||||
ef_port_env_unlock();
|
||||
|
||||
result = ef_save_env();
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* reset other PFS area's data */
|
||||
if (result == EF_NO_ERR) {
|
||||
env_cache_changed = true;
|
||||
result = ef_save_env();
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ENV system section start address.
|
||||
*
|
||||
* @return system section start address
|
||||
*/
|
||||
static uint32_t get_env_system_addr(void) {
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
return env_start_addr;
|
||||
#else
|
||||
return cur_load_area_addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ENV data section start address.
|
||||
*
|
||||
* @return data section start address
|
||||
*/
|
||||
static uint32_t get_env_data_addr(void) {
|
||||
return get_env_system_addr() + ENV_PARAM_BYTE_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ENV end address.
|
||||
* It's the first word in ENV.
|
||||
*
|
||||
* @return ENV end address
|
||||
*/
|
||||
static uint32_t get_env_end_addr(void) {
|
||||
/* it is the first word */
|
||||
return env_cache[ENV_PARAM_INDEX_END_ADDR];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ENV end address.
|
||||
* It's the first word in ENV.
|
||||
*
|
||||
* @param end_addr ENV end address
|
||||
*/
|
||||
static void set_env_end_addr(uint32_t end_addr) {
|
||||
env_cache[ENV_PARAM_INDEX_END_ADDR] = end_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ENV data section size.
|
||||
*
|
||||
* @return size
|
||||
*/
|
||||
static size_t get_env_data_size(void) {
|
||||
if (get_env_end_addr() > get_env_data_addr()) {
|
||||
return get_env_end_addr() - get_env_data_addr();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user used ENV size.
|
||||
*
|
||||
* @return bytes
|
||||
*/
|
||||
static size_t get_env_user_used_size(void) {
|
||||
if (get_env_end_addr() > get_env_system_addr()) {
|
||||
return get_env_end_addr() - get_env_system_addr();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ENV already write bytes.
|
||||
*
|
||||
* @return write bytes
|
||||
*/
|
||||
size_t ef_get_env_write_bytes(void) {
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
return get_env_user_used_size();
|
||||
#else
|
||||
return get_env_user_used_size() * 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an ENV at the end of cache.
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode write_env(const char *key, const char *value) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t key_len = strlen(key), value_len = strlen(value), env_str_len;
|
||||
char *env_cache_bak = (char *)env_cache;
|
||||
|
||||
/* calculate ENV storage length, contain '=' and '\0'. */
|
||||
env_str_len = key_len + value_len + 2;
|
||||
if (env_str_len % 4 != 0) {
|
||||
env_str_len = (env_str_len / 4 + 1) * 4;
|
||||
}
|
||||
/* check capacity of ENV */
|
||||
if (env_str_len + get_env_user_used_size() >= ENV_USER_SETTING_SIZE) {
|
||||
return EF_ENV_FULL;
|
||||
}
|
||||
|
||||
/* calculate current ENV ram cache end address */
|
||||
env_cache_bak += get_env_user_used_size();
|
||||
|
||||
/* copy key name */
|
||||
memcpy(env_cache_bak, key, key_len);
|
||||
env_cache_bak += key_len;
|
||||
/* copy equal sign */
|
||||
*env_cache_bak = '=';
|
||||
env_cache_bak++;
|
||||
/* copy value */
|
||||
memcpy(env_cache_bak, value, value_len);
|
||||
env_cache_bak += value_len;
|
||||
/* fill '\0' for string end sign */
|
||||
*env_cache_bak = '\0';
|
||||
env_cache_bak ++;
|
||||
/* fill '\0' for word alignment */
|
||||
memset(env_cache_bak, 0, env_str_len - (key_len + value_len + 2));
|
||||
set_env_end_addr(get_env_end_addr() + env_str_len);
|
||||
/* ENV ram cache has changed */
|
||||
env_cache_changed = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find ENV.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return found ENV in ram cache
|
||||
*/
|
||||
static char *find_env(const char *key) {
|
||||
char *env_start, *env_end, *env, *found_env = NULL;
|
||||
size_t key_len = strlen(key), env_len;
|
||||
|
||||
if ((key == NULL) || *key == '\0') {
|
||||
EF_INFO("Flash ENV name must be not empty!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* from data section start to data section end */
|
||||
env_start = (char *) ((char *) env_cache + ENV_PARAM_BYTE_SIZE);
|
||||
env_end = (char *) ((char *) env_cache + get_env_user_used_size());
|
||||
|
||||
/* ENV is null */
|
||||
if (env_start == env_end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env = env_start;
|
||||
while (env < env_end) {
|
||||
/* the key length must be equal */
|
||||
if (!strncmp(env, key, key_len) && (env[key_len] == '=')) {
|
||||
found_env = env;
|
||||
break;
|
||||
} else {
|
||||
/* calculate ENV length, contain '\0'. */
|
||||
env_len = strlen(env) + 1;
|
||||
/* next ENV and word alignment */
|
||||
if (env_len % 4 == 0) {
|
||||
env += env_len;
|
||||
} else {
|
||||
env += (env_len / 4 + 1) * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found_env;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the ENV is not exist, create it.
|
||||
* @see flash_write_env
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode create_env(const char *key, const char *value) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
EF_ASSERT(key);
|
||||
EF_ASSERT(value);
|
||||
|
||||
if ((key == NULL) || *key == '\0') {
|
||||
EF_INFO("Flash ENV name must be not empty!\n");
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
|
||||
if (strchr(key, '=')) {
|
||||
EF_INFO("Flash ENV name can't contain '='.\n");
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
|
||||
/* find ENV */
|
||||
if (find_env(key)) {
|
||||
EF_INFO("The name of \"%s\" is already exist.\n", key);
|
||||
return EF_ENV_NAME_EXIST;
|
||||
}
|
||||
/* write ENV at the end of cache */
|
||||
result = write_env(key, value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an ENV in cache.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode del_env(const char *key) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
char *del_env = NULL;
|
||||
size_t del_env_length, remain_env_length;
|
||||
|
||||
EF_ASSERT(key);
|
||||
|
||||
if ((key == NULL) || *key == '\0') {
|
||||
EF_INFO("Flash ENV name must be not NULL!\n");
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
|
||||
if (strchr(key, '=')) {
|
||||
EF_INFO("Flash ENV name or value can't contain '='.\n");
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
|
||||
/* find ENV */
|
||||
del_env = find_env(key);
|
||||
|
||||
if (!del_env) {
|
||||
EF_INFO("Not find \"%s\" in ENV.\n", key);
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
del_env_length = strlen(del_env);
|
||||
/* '\0' also must be as ENV length */
|
||||
del_env_length ++;
|
||||
/* the address must multiple of 4 */
|
||||
if (del_env_length % 4 != 0) {
|
||||
del_env_length = (del_env_length / 4 + 1) * 4;
|
||||
}
|
||||
/* calculate remain ENV length */
|
||||
remain_env_length = get_env_data_size()
|
||||
- (((uint32_t) del_env + del_env_length) - ((uint32_t) env_cache + ENV_PARAM_BYTE_SIZE));
|
||||
/* remain ENV move forward */
|
||||
memcpy(del_env, del_env + del_env_length, remain_env_length);
|
||||
/* reset ENV end address */
|
||||
set_env_end_addr(get_env_end_addr() - del_env_length);
|
||||
/* ENV ram cache has changed */
|
||||
env_cache_changed = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an ENV.If it value is NULL, delete it.
|
||||
* If not find it in ENV table, then create it.
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_set_env(const char *key, const char *value) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
char *old_env, *old_value;
|
||||
|
||||
if (!init_ok) {
|
||||
EF_INFO("ENV isn't initialize OK.\n");
|
||||
return EF_ENV_INIT_FAILED;
|
||||
}
|
||||
|
||||
/* lock the ENV cache */
|
||||
ef_port_env_lock();
|
||||
|
||||
/* if ENV value is NULL, delete it */
|
||||
if (value == NULL) {
|
||||
result = del_env(key);
|
||||
} else {
|
||||
old_env = find_env(key);
|
||||
/* If find this ENV, then compare the new value and old value. */
|
||||
if (old_env) {
|
||||
/* find the old value address */
|
||||
old_env = strchr(old_env, '=');
|
||||
old_value = old_env + 1;
|
||||
/* If it is changed then delete it and recreate it */
|
||||
if (strcmp(old_value, value)) {
|
||||
result = del_env(key);
|
||||
if (result == EF_NO_ERR) {
|
||||
result = create_env(key, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = create_env(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock the ENV cache */
|
||||
ef_port_env_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Del an ENV.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_del_env(const char *key) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
if (!init_ok) {
|
||||
EF_INFO("ENV isn't initialize OK.\n");
|
||||
return EF_ENV_INIT_FAILED;
|
||||
}
|
||||
|
||||
/* lock the ENV cache */
|
||||
ef_port_env_lock();
|
||||
|
||||
result = del_env(key);
|
||||
|
||||
/* unlock the ENV cache */
|
||||
ef_port_env_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ENV value by key name.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return value
|
||||
*/
|
||||
char *ef_get_env(const char *key) {
|
||||
char *env = NULL, *value = NULL;
|
||||
|
||||
if (!init_ok) {
|
||||
EF_INFO("ENV isn't initialize OK.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find ENV */
|
||||
env = find_env(key);
|
||||
|
||||
if (env == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/* get value address */
|
||||
value = strchr(env, '=');
|
||||
if (value != NULL) {
|
||||
/* the equal sign next character is value */
|
||||
value++;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Print ENV.
|
||||
*/
|
||||
void ef_print_env(void) {
|
||||
uint32_t *env_cache_data_addr = env_cache + ENV_PARAM_WORD_SIZE,
|
||||
*env_cache_end_addr =
|
||||
(uint32_t *) (env_cache + ENV_PARAM_WORD_SIZE + get_env_data_size() / 4);
|
||||
uint8_t j;
|
||||
char c;
|
||||
|
||||
if (!init_ok) {
|
||||
EF_INFO("ENV isn't initialize OK.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (; env_cache_data_addr < env_cache_end_addr; env_cache_data_addr += 1) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
c = (*env_cache_data_addr) >> (8 * j);
|
||||
ef_print("%c", c);
|
||||
if (c == '\0') {
|
||||
ef_print("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
ef_print("\nmode: normal\n");
|
||||
ef_print("size: %ld/%ld bytes.\n", get_env_user_used_size(), ENV_USER_SETTING_SIZE);
|
||||
#else
|
||||
ef_print("\nmode: power fail safeguard\n");
|
||||
ef_print("size: %ld/%ld bytes, write bytes %ld/%ld.\n", get_env_user_used_size(),
|
||||
ENV_USER_SETTING_SIZE, ef_get_env_write_bytes(), ENV_AREA_SIZE);
|
||||
ef_print("saved count: %ld\n", env_cache[ENV_PARAM_INDEX_SAVED_COUNT]);
|
||||
#endif
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
ef_print("ver num: %d\n", env_cache[ENV_PARAM_INDEX_VER_NUM]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Load flash ENV to ram.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
EfErrCode ef_load_env(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
uint32_t *env_cache_bak, env_end_addr;
|
||||
|
||||
/* read ENV end address from flash */
|
||||
ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_END_ADDR * 4, &env_end_addr, 4);
|
||||
/* if ENV is not initialize or flash has dirty data, set default for it */
|
||||
if ((env_end_addr == 0xFFFFFFFF) || (env_end_addr < env_start_addr)
|
||||
|| (env_end_addr > env_start_addr + ENV_USER_SETTING_SIZE)) {
|
||||
result = ef_env_set_default();
|
||||
} else {
|
||||
/* set ENV end address */
|
||||
set_env_end_addr(env_end_addr);
|
||||
|
||||
env_cache_bak = env_cache + ENV_PARAM_WORD_SIZE;
|
||||
/* read all ENV from flash */
|
||||
ef_port_read(get_env_data_addr(), env_cache_bak, get_env_data_size());
|
||||
/* read ENV CRC code from flash */
|
||||
ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_DATA_CRC * 4,
|
||||
&env_cache[ENV_PARAM_INDEX_DATA_CRC] , 4);
|
||||
/* if ENV CRC32 check is fault, set default for it */
|
||||
if (!env_crc_is_ok()) {
|
||||
EF_INFO("Warning: ENV CRC check failed. Set it to default.\n");
|
||||
result = ef_env_set_default();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
EfErrCode ef_load_env(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
uint32_t area0_start_address = env_start_addr, area1_start_address = env_start_addr
|
||||
+ ENV_AREA_SIZE / 2;
|
||||
uint32_t area0_end_addr, area1_end_addr, area0_crc, area1_crc, area0_saved_count, area1_saved_count;
|
||||
bool area0_is_valid = true, area1_is_valid = true;
|
||||
/* read ENV area end address from flash */
|
||||
ef_port_read(area0_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area0_end_addr, 4);
|
||||
ef_port_read(area1_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area1_end_addr, 4);
|
||||
if ((area0_end_addr == 0xFFFFFFFF) || (area0_end_addr < area0_start_address)
|
||||
|| (area0_end_addr > area0_start_address + ENV_USER_SETTING_SIZE)) {
|
||||
area0_is_valid = false;
|
||||
}
|
||||
if ((area1_end_addr == 0xFFFFFFFF) || (area1_end_addr < area1_start_address)
|
||||
|| (area1_end_addr > area1_start_address + ENV_USER_SETTING_SIZE)) {
|
||||
area1_is_valid = false;
|
||||
}
|
||||
/* check area0 CRC when it is valid */
|
||||
if (area0_is_valid) {
|
||||
/* read ENV area0 crc32 code from flash */
|
||||
ef_port_read(area0_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area0_crc, 4);
|
||||
/* read ENV from ENV area0 */
|
||||
ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address);
|
||||
/* current load ENV area address is area0 start address */
|
||||
cur_load_area_addr = area0_start_address;
|
||||
if (!env_crc_is_ok()) {
|
||||
area0_is_valid = false;
|
||||
}
|
||||
}
|
||||
/* check area1 CRC when it is valid */
|
||||
if (area1_is_valid) {
|
||||
/* read ENV area1 crc32 code from flash */
|
||||
ef_port_read(area1_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area1_crc, 4);
|
||||
/* read ENV from ENV area1 */
|
||||
ef_port_read(area1_start_address, env_cache, area1_end_addr - area1_start_address);
|
||||
/* current load ENV area address is area1 start address */
|
||||
cur_load_area_addr = area1_start_address;
|
||||
if (!env_crc_is_ok()) {
|
||||
area1_is_valid = false;
|
||||
}
|
||||
}
|
||||
/* all ENV area CRC is OK then compare saved count */
|
||||
if (area0_is_valid && area1_is_valid) {
|
||||
/* read ENV area saved count from flash */
|
||||
ef_port_read(area0_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4,
|
||||
&area0_saved_count, 4);
|
||||
ef_port_read(area1_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4,
|
||||
&area1_saved_count, 4);
|
||||
/* the bigger saved count area is valid */
|
||||
if ((area0_saved_count > area1_saved_count) || ((area0_saved_count == 0) && (area1_saved_count == 0xFFFFFFFF))) {
|
||||
area1_is_valid = false;
|
||||
} else {
|
||||
area0_is_valid = false;
|
||||
}
|
||||
}
|
||||
if (area0_is_valid) {
|
||||
/* current load ENV area address is area0 start address */
|
||||
cur_load_area_addr = area0_start_address;
|
||||
/* next save ENV area address is area1 start address */
|
||||
next_save_area_addr = area1_start_address;
|
||||
/* read all ENV from area0 */
|
||||
ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address);
|
||||
} else if (area1_is_valid) {
|
||||
/* next save ENV area address is area0 start address */
|
||||
next_save_area_addr = area0_start_address;
|
||||
} else {
|
||||
/* current load ENV area address is area1 start address */
|
||||
cur_load_area_addr = area1_start_address;
|
||||
/* next save ENV area address is area0 start address */
|
||||
next_save_area_addr = area0_start_address;
|
||||
/* set the ENV to default */
|
||||
result = ef_env_set_default();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Save ENV to flash.
|
||||
*/
|
||||
EfErrCode ef_save_env(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
uint32_t write_addr, write_size;
|
||||
|
||||
/* ENV ram cache has not changed don't need to save */
|
||||
if (!env_cache_changed) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
write_addr = get_env_system_addr();
|
||||
write_size = get_env_user_used_size();
|
||||
/* calculate and cache CRC32 code */
|
||||
env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc();
|
||||
#else
|
||||
write_addr = next_save_area_addr;
|
||||
write_size = get_env_user_used_size();
|
||||
/* replace next_save_area_addr with cur_load_area_addr */
|
||||
next_save_area_addr = cur_load_area_addr;
|
||||
cur_load_area_addr = write_addr;
|
||||
/* change the ENV end address to next save area address */
|
||||
set_env_end_addr(write_addr + write_size);
|
||||
/* ENV area saved count +1 */
|
||||
env_cache[ENV_PARAM_INDEX_SAVED_COUNT]++;
|
||||
/* calculate and cache CRC32 code */
|
||||
env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc();
|
||||
#endif
|
||||
|
||||
/* erase ENV */
|
||||
result = ef_port_erase(write_addr, write_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_DEBUG("Erased ENV OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_ERASE_ERR: {
|
||||
EF_INFO("Error: Erased ENV fault! Start address is 0x%08X, size is %ld.\n", write_addr, write_size);
|
||||
/* will return when erase fault */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* write ENV to flash */
|
||||
result = ef_port_write(write_addr, env_cache, write_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_DEBUG("Saved ENV OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_WRITE_ERR: {
|
||||
EF_INFO("Error: Saved ENV fault! Start address is 0x%08X, size is %ld.\n", write_addr, write_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
env_cache_changed = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the cached ENV CRC32 value.
|
||||
*
|
||||
* @return CRC32 value
|
||||
*/
|
||||
static uint32_t calc_env_crc(void) {
|
||||
uint32_t crc32 = 0;
|
||||
|
||||
/* Calculate the ENV end address CRC32. The 4 is ENV end address bytes size. */
|
||||
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_END_ADDR], 4);
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* Calculate the ENV area saved count CRC32. */
|
||||
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_SAVED_COUNT], 4);
|
||||
#endif
|
||||
|
||||
/* Calculate the all ENV data CRC32. */
|
||||
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_WORD_SIZE], get_env_data_size());
|
||||
|
||||
EF_DEBUG("Calculate ENV CRC32 number is 0x%08X.\n", crc32);
|
||||
|
||||
return crc32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the ENV CRC32
|
||||
*
|
||||
* @return true is ok
|
||||
*/
|
||||
static bool env_crc_is_ok(void) {
|
||||
if (calc_env_crc() == env_cache[ENV_PARAM_INDEX_DATA_CRC]) {
|
||||
EF_DEBUG("Verify ENV CRC32 result is OK.\n");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set and save an ENV. If set ENV is success then will save it.
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_set_and_save_env(const char *key, const char *value) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = ef_set_env(key, value);
|
||||
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_save_env();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Del and save an ENV. If del ENV is success then will save it.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_del_and_save_env(const char *key) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = ef_del_env(key);
|
||||
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_save_env();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
/**
|
||||
* Auto update ENV to latest default when current EF_ENV_VER is changed.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode env_auto_update(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* lock the ENV cache */
|
||||
ef_port_env_lock();
|
||||
|
||||
/* read ENV version number from flash*/
|
||||
ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_VER_NUM * 4,
|
||||
&env_cache[ENV_PARAM_INDEX_VER_NUM] , 4);
|
||||
|
||||
/* check version number */
|
||||
if (env_cache[ENV_PARAM_INDEX_VER_NUM] != EF_ENV_VER_NUM) {
|
||||
env_cache_changed = true;
|
||||
/* update version number */
|
||||
env_cache[ENV_PARAM_INDEX_VER_NUM] = EF_ENV_VER_NUM;
|
||||
/* add a new ENV when it's not found */
|
||||
for (i = 0; i < default_env_set_size; i++) {
|
||||
if (find_env(default_env_set[i].key) == NULL) {
|
||||
create_env(default_env_set[i].key, default_env_set[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock the ENV cache */
|
||||
ef_port_env_unlock();
|
||||
|
||||
return ef_save_env();
|
||||
}
|
||||
#endif /* EF_ENV_AUTO_UPDATE */
|
||||
|
||||
#endif /* EF_ENV_USING_WL_MODE */
|
||||
|
||||
#endif /* defined(EF_USING_ENV) && defined(EF_ENV_USING_LEGACY_MODE) */
|
1082
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_env_legacy_wl.c
Normal file
1082
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_env_legacy_wl.c
Normal file
File diff suppressed because it is too large
Load Diff
289
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_iap.c
Normal file
289
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_iap.c
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2017, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: IAP(In-Application Programming) operating interface.
|
||||
* Created on: 2015-01-05
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
|
||||
#ifdef EF_USING_IAP
|
||||
|
||||
/* IAP section backup application section start address in flash */
|
||||
static uint32_t bak_app_start_addr = 0;
|
||||
|
||||
/**
|
||||
* Flash IAP function initialize.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_iap_init(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
bak_app_start_addr = EF_START_ADDR ;
|
||||
|
||||
#if defined(EF_USING_ENV)
|
||||
bak_app_start_addr += ENV_AREA_SIZE;
|
||||
#endif
|
||||
|
||||
#if defined(EF_USING_LOG)
|
||||
bak_app_start_addr += LOG_AREA_SIZE;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase backup area application data.
|
||||
*
|
||||
* @param app_size application size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_erase_bak_app(size_t app_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = ef_port_erase(ef_get_bak_app_start_addr(), app_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Erased backup area application OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_ERASE_ERR: {
|
||||
EF_INFO("Warning: Erase backup area application fault!\n");
|
||||
/* will return when erase fault */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase user old application by using specified erase function.
|
||||
*
|
||||
* @param user_app_addr application entry address
|
||||
* @param app_size application size
|
||||
* @param app_erase user specified application erase function
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_erase_spec_user_app(uint32_t user_app_addr, size_t app_size,
|
||||
EfErrCode (*app_erase)(uint32_t addr, size_t size)) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = app_erase(user_app_addr, app_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Erased user application OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_ERASE_ERR: {
|
||||
EF_INFO("Warning: Erase user application fault!\n");
|
||||
/* will return when erase fault */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase user old application by using default `ef_port_erase` function.
|
||||
*
|
||||
* @param user_app_addr application entry address
|
||||
* @param app_size application size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_erase_user_app(uint32_t user_app_addr, size_t app_size) {
|
||||
return ef_erase_spec_user_app(user_app_addr, app_size, ef_port_erase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase old bootloader
|
||||
*
|
||||
* @param bl_addr bootloader entry address
|
||||
* @param bl_size bootloader size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_erase_bl(uint32_t bl_addr, size_t bl_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = ef_port_erase(bl_addr, bl_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Erased bootloader OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_ERASE_ERR: {
|
||||
EF_INFO("Warning: Erase bootloader fault!\n");
|
||||
/* will return when erase fault */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data of application to backup area.
|
||||
*
|
||||
* @param data a part of application
|
||||
* @param size data size
|
||||
* @param cur_size current write application size
|
||||
* @param total_size application total size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_write_data_to_bak(uint8_t *data, size_t size, size_t *cur_size,
|
||||
size_t total_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
/* make sure don't write excess data */
|
||||
if (*cur_size + size > total_size) {
|
||||
size = total_size - *cur_size;
|
||||
}
|
||||
|
||||
result = ef_port_write(ef_get_bak_app_start_addr() + *cur_size, (uint32_t *) data, size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
*cur_size += size;
|
||||
EF_DEBUG("Write data to backup area OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_WRITE_ERR: {
|
||||
EF_INFO("Warning: Write data to backup area fault!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy backup area application to application entry by using specified write function.
|
||||
*
|
||||
* @param user_app_addr application entry address
|
||||
* @param app_size application size
|
||||
* @param app_write user specified application write function
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_copy_spec_app_from_bak(uint32_t user_app_addr, size_t app_size,
|
||||
EfErrCode (*app_write)(uint32_t addr, const uint32_t *buf, size_t size)) {
|
||||
size_t cur_size;
|
||||
uint32_t app_cur_addr, bak_cur_addr;
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
/* 32 words size buffer */
|
||||
uint32_t buff[32];
|
||||
|
||||
/* cycle copy data */
|
||||
for (cur_size = 0; cur_size < app_size; cur_size += sizeof(buff)) {
|
||||
app_cur_addr = user_app_addr + cur_size;
|
||||
bak_cur_addr = ef_get_bak_app_start_addr() + cur_size;
|
||||
ef_port_read(bak_cur_addr, buff, sizeof(buff));
|
||||
result = app_write(app_cur_addr, buff, sizeof(buff));
|
||||
if (result != EF_NO_ERR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Write data to application entry OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_WRITE_ERR: {
|
||||
EF_INFO("Warning: Write data to application entry fault!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy backup area application to application entry by using default `ef_port_write` function.
|
||||
*
|
||||
* @param user_app_addr application entry address
|
||||
* @param app_size application size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_copy_app_from_bak(uint32_t user_app_addr, size_t app_size) {
|
||||
return ef_copy_spec_app_from_bak(user_app_addr, app_size, ef_port_write);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy backup area bootloader to bootloader entry.
|
||||
*
|
||||
* @param bl_addr bootloader entry address
|
||||
* @param bl_size bootloader size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_copy_bl_from_bak(uint32_t bl_addr, size_t bl_size) {
|
||||
size_t cur_size;
|
||||
uint32_t bl_cur_addr, bak_cur_addr;
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
/* 32 words buffer */
|
||||
uint32_t buff[32];
|
||||
|
||||
/* cycle copy data by 32bytes buffer */
|
||||
for (cur_size = 0; cur_size < bl_size; cur_size += sizeof(buff)) {
|
||||
bl_cur_addr = bl_addr + cur_size;
|
||||
bak_cur_addr = ef_get_bak_app_start_addr() + cur_size;
|
||||
ef_port_read(bak_cur_addr, buff, sizeof(buff));
|
||||
result = ef_port_write(bl_cur_addr, buff, sizeof(buff));
|
||||
if (result != EF_NO_ERR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Write data to bootloader entry OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_WRITE_ERR: {
|
||||
EF_INFO("Warning: Write data to bootloader entry fault!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IAP section start address in flash.
|
||||
*
|
||||
* @return size
|
||||
*/
|
||||
uint32_t ef_get_bak_app_start_addr(void) {
|
||||
return bak_app_start_addr;
|
||||
}
|
||||
|
||||
#endif /* EF_USING_IAP */
|
731
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_log.c
Normal file
731
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_log.c
Normal file
@ -0,0 +1,731 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2019, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Save logs to flash.
|
||||
* Created on: 2015-06-04
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
|
||||
#ifdef EF_USING_LOG
|
||||
|
||||
#if defined(EF_USING_LOG) && !defined(LOG_AREA_SIZE)
|
||||
#error "Please configure log area size (in ef_cfg.h)"
|
||||
#endif
|
||||
|
||||
/* magic code on every sector header. 'EF' is 0xEF30EF30 */
|
||||
#define LOG_SECTOR_MAGIC 0xEF30EF30
|
||||
/* sector header size, includes the sector magic code and status magic code */
|
||||
#define LOG_SECTOR_HEADER_SIZE 12
|
||||
/* sector header word size,what is equivalent to the total number of sectors header index */
|
||||
#define LOG_SECTOR_HEADER_WORD_SIZE 3
|
||||
|
||||
/**
|
||||
* Sector status magic code
|
||||
* The sector status is 8B after LOG_SECTOR_MAGIC at every sector header.
|
||||
* ==============================================
|
||||
* | header(12B) | status |
|
||||
* ----------------------------------------------
|
||||
* | 0xEF30EF30 0xFFFFFFFF 0xFFFFFFFF | empty |
|
||||
* | 0xEF30EF30 0xFEFEFEFE 0xFFFFFFFF | using |
|
||||
* | 0xEF30EF30 0xFEFEFEFE 0xFCFCFCFC | full |
|
||||
* ==============================================
|
||||
*
|
||||
* State transition relationship: empty->using->full
|
||||
* The FULL status will change to EMPTY after sector clean.
|
||||
*/
|
||||
#define SECTOR_STATUS_MAGIC_EMPUT 0xFFFFFFFF
|
||||
#define SECTOR_STATUS_MAGIC_USING 0xFEFEFEFE
|
||||
#define SECTOR_STATUS_MAGIC_FULL 0xFCFCFCFC
|
||||
|
||||
typedef enum {
|
||||
SECTOR_STATUS_EMPUT,
|
||||
SECTOR_STATUS_USING,
|
||||
SECTOR_STATUS_FULL,
|
||||
SECTOR_STATUS_HEADER_ERROR,
|
||||
} SectorStatus;
|
||||
|
||||
typedef enum {
|
||||
SECTOR_HEADER_MAGIC_INDEX,
|
||||
SECTOR_HEADER_USING_INDEX,
|
||||
SECTOR_HEADER_FULL_INDEX,
|
||||
} SectorHeaderIndex;
|
||||
|
||||
/* the stored logs start address and end address. It's like a ring buffer implemented on flash. */
|
||||
static uint32_t log_start_addr = 0, log_end_addr = 0;
|
||||
/* saved log area address for flash */
|
||||
static uint32_t log_area_start_addr = 0;
|
||||
/* initialize OK flag */
|
||||
static bool init_ok = false;
|
||||
|
||||
static void find_start_and_end_addr(void);
|
||||
static uint32_t get_next_flash_sec_addr(uint32_t cur_addr);
|
||||
|
||||
/**
|
||||
* The flash save log function initialize.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_log_init(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
EF_ASSERT(LOG_AREA_SIZE);
|
||||
EF_ASSERT(EF_ERASE_MIN_SIZE);
|
||||
/* the log area size must be an integral multiple of erase minimum size. */
|
||||
EF_ASSERT(LOG_AREA_SIZE % EF_ERASE_MIN_SIZE == 0);
|
||||
/* the log area size must be more than twice of EF_ERASE_MIN_SIZE */
|
||||
EF_ASSERT(LOG_AREA_SIZE / EF_ERASE_MIN_SIZE >= 2);
|
||||
|
||||
#ifdef EF_USING_ENV
|
||||
log_area_start_addr = EF_START_ADDR + ENV_AREA_SIZE;
|
||||
#else
|
||||
log_area_start_addr = EF_START_ADDR;
|
||||
#endif
|
||||
|
||||
/* find the log store start address and end address */
|
||||
find_start_and_end_addr();
|
||||
/* initialize OK */
|
||||
init_ok = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get flash sector current status.
|
||||
*
|
||||
* @param addr sector address, this function will auto calculate the sector header address by this address.
|
||||
*
|
||||
* @return the flash sector current status
|
||||
*/
|
||||
static SectorStatus get_sector_status(uint32_t addr) {
|
||||
uint32_t header_buf[LOG_SECTOR_HEADER_WORD_SIZE] = {0}, header_addr = 0;
|
||||
uint32_t sector_header_magic = 0;
|
||||
uint32_t status_full_magic = 0, status_use_magic = 0;
|
||||
|
||||
/* calculate the sector header address */
|
||||
header_addr = addr & (~(EF_ERASE_MIN_SIZE - 1));
|
||||
|
||||
if (ef_port_read(header_addr, header_buf, sizeof(header_buf)) == EF_NO_ERR) {
|
||||
sector_header_magic = header_buf[SECTOR_HEADER_MAGIC_INDEX];
|
||||
status_use_magic = header_buf[SECTOR_HEADER_USING_INDEX];
|
||||
status_full_magic = header_buf[SECTOR_HEADER_FULL_INDEX];
|
||||
} else {
|
||||
EF_DEBUG("Error: Read sector header data error.\n");
|
||||
return SECTOR_STATUS_HEADER_ERROR;
|
||||
}
|
||||
|
||||
/* compare header magic code */
|
||||
if(sector_header_magic == LOG_SECTOR_MAGIC){
|
||||
if((status_use_magic == SECTOR_STATUS_MAGIC_EMPUT) && (status_full_magic == SECTOR_STATUS_MAGIC_EMPUT)) {
|
||||
return SECTOR_STATUS_EMPUT;
|
||||
} else if((status_use_magic == SECTOR_STATUS_MAGIC_USING) && (status_full_magic == SECTOR_STATUS_MAGIC_EMPUT)) {
|
||||
return SECTOR_STATUS_USING;
|
||||
} else if((status_use_magic == SECTOR_STATUS_MAGIC_USING) && (status_full_magic == SECTOR_STATUS_MAGIC_FULL)) {
|
||||
return SECTOR_STATUS_FULL;
|
||||
} else {
|
||||
return SECTOR_STATUS_HEADER_ERROR;
|
||||
}
|
||||
} else {
|
||||
return SECTOR_STATUS_HEADER_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write flash sector current status.
|
||||
*
|
||||
* @param addr sector address, this function will auto calculate the sector header address by this address.
|
||||
* @param status sector cur status
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode write_sector_status(uint32_t addr, SectorStatus status) {
|
||||
uint32_t header, header_addr = 0;
|
||||
|
||||
/* calculate the sector header address */
|
||||
header_addr = addr & (~(EF_ERASE_MIN_SIZE - 1));
|
||||
|
||||
/* calculate the sector staus magic */
|
||||
switch (status) {
|
||||
case SECTOR_STATUS_EMPUT: {
|
||||
header = LOG_SECTOR_MAGIC;
|
||||
return ef_port_write(header_addr, &header, sizeof(header));
|
||||
}
|
||||
case SECTOR_STATUS_USING: {
|
||||
header = SECTOR_STATUS_MAGIC_USING;
|
||||
return ef_port_write(header_addr + sizeof(header), &header, sizeof(header));
|
||||
}
|
||||
case SECTOR_STATUS_FULL: {
|
||||
header = SECTOR_STATUS_MAGIC_FULL;
|
||||
return ef_port_write(header_addr + sizeof(header) * 2, &header, sizeof(header));
|
||||
}
|
||||
default:
|
||||
return EF_WRITE_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the current flash sector using end address by continuous 0xFF.
|
||||
*
|
||||
* @param addr sector address
|
||||
*
|
||||
* @return current flash sector using end address
|
||||
*/
|
||||
static uint32_t find_sec_using_end_addr(uint32_t addr) {
|
||||
/* read section data buffer size */
|
||||
#define READ_BUF_SIZE 32
|
||||
|
||||
uint32_t sector_start = addr, data_start = addr, continue_ff = 0, read_buf_size = 0, i;
|
||||
uint8_t buf[READ_BUF_SIZE];
|
||||
|
||||
EF_ASSERT(READ_BUF_SIZE % 4 == 0);
|
||||
/* calculate the sector start and data start address */
|
||||
sector_start = addr & (~(EF_ERASE_MIN_SIZE - 1));
|
||||
data_start = sector_start + LOG_SECTOR_HEADER_SIZE;
|
||||
|
||||
/* counts continuous 0xFF which is end of sector */
|
||||
while (data_start < sector_start + EF_ERASE_MIN_SIZE) {
|
||||
if (data_start + READ_BUF_SIZE < sector_start + EF_ERASE_MIN_SIZE) {
|
||||
read_buf_size = READ_BUF_SIZE;
|
||||
} else {
|
||||
read_buf_size = sector_start + EF_ERASE_MIN_SIZE - data_start;
|
||||
}
|
||||
ef_port_read(data_start, (uint32_t *)buf, read_buf_size);
|
||||
for (i = 0; i < read_buf_size; i++) {
|
||||
if (buf[i] == 0xFF) {
|
||||
continue_ff++;
|
||||
} else {
|
||||
continue_ff = 0;
|
||||
}
|
||||
}
|
||||
data_start += read_buf_size;
|
||||
}
|
||||
/* calculate current flash sector using end address */
|
||||
if (continue_ff >= EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) {
|
||||
/* from 0 to sec_size all sector is 0xFF, so the sector is empty */
|
||||
return sector_start + LOG_SECTOR_HEADER_SIZE;
|
||||
} else if (continue_ff >= 4) {
|
||||
/* form end_addr - 4 to sec_size length all area is 0xFF, so it's used part of the sector.
|
||||
* the address must be word alignment. */
|
||||
if (continue_ff % 4 != 0) {
|
||||
continue_ff = (continue_ff / 4 + 1) * 4;
|
||||
}
|
||||
return sector_start + EF_ERASE_MIN_SIZE - continue_ff;
|
||||
} else {
|
||||
/* all sector not has continuous 0xFF, so the sector is full */
|
||||
return sector_start + EF_ERASE_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the log store start address and end address.
|
||||
* It's like a ring buffer implemented on flash.
|
||||
* The flash log area can be in two states depending on start address and end address:
|
||||
* state 1 state 2
|
||||
* |============| |============|
|
||||
* log area start--> |############| <-- start address |############| <-- end address
|
||||
* |############| | empty |
|
||||
* |------------| |------------|
|
||||
* |############| |############| <-- start address
|
||||
* |############| |############|
|
||||
* |------------| |------------|
|
||||
* | . | | . |
|
||||
* | . | | . |
|
||||
* | . | | . |
|
||||
* |------------| |------------|
|
||||
* |############| <-- end address |############|
|
||||
* | empty | |############|
|
||||
* log area end --> |============| |============|
|
||||
*
|
||||
* LOG_AREA_SIZE = log area end - log area star
|
||||
*
|
||||
*/
|
||||
static void find_start_and_end_addr(void) {
|
||||
size_t cur_size = 0;
|
||||
SectorStatus cur_sec_status, last_sec_status;
|
||||
uint32_t cur_using_sec_addr = 0;
|
||||
/* all status sector counts */
|
||||
size_t empty_sec_counts = 0, using_sec_counts = 0, full_sector_counts = 0;
|
||||
/* total sector number */
|
||||
size_t total_sec_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
|
||||
/* see comment of find_start_and_end_addr function */
|
||||
uint8_t cur_log_sec_state = 0;
|
||||
|
||||
/* get the first sector status */
|
||||
cur_sec_status = get_sector_status(log_area_start_addr);
|
||||
last_sec_status = cur_sec_status;
|
||||
|
||||
for (cur_size = EF_ERASE_MIN_SIZE; cur_size < LOG_AREA_SIZE; cur_size += EF_ERASE_MIN_SIZE) {
|
||||
/* get current sector status */
|
||||
cur_sec_status = get_sector_status(log_area_start_addr + cur_size);
|
||||
/* compare last and current status */
|
||||
switch (last_sec_status) {
|
||||
case SECTOR_STATUS_EMPUT: {
|
||||
switch (cur_sec_status) {
|
||||
case SECTOR_STATUS_EMPUT:
|
||||
break;
|
||||
case SECTOR_STATUS_USING:
|
||||
EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
case SECTOR_STATUS_FULL:
|
||||
EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
}
|
||||
empty_sec_counts++;
|
||||
break;
|
||||
}
|
||||
case SECTOR_STATUS_USING: {
|
||||
switch (cur_sec_status) {
|
||||
case SECTOR_STATUS_EMPUT:
|
||||
/* like state 1 */
|
||||
cur_log_sec_state = 1;
|
||||
log_start_addr = log_area_start_addr;
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
|
||||
break;
|
||||
case SECTOR_STATUS_USING:
|
||||
EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
case SECTOR_STATUS_FULL:
|
||||
/* like state 2 */
|
||||
cur_log_sec_state = 2;
|
||||
log_start_addr = log_area_start_addr + cur_size;
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
|
||||
break;
|
||||
}
|
||||
using_sec_counts++;
|
||||
break;
|
||||
}
|
||||
case SECTOR_STATUS_FULL: {
|
||||
switch (cur_sec_status) {
|
||||
case SECTOR_STATUS_EMPUT:
|
||||
/* like state 1 */
|
||||
if (cur_log_sec_state == 2) {
|
||||
EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
} else {
|
||||
cur_log_sec_state = 1;
|
||||
log_start_addr = log_area_start_addr;
|
||||
log_end_addr = log_area_start_addr + cur_size;
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
|
||||
}
|
||||
break;
|
||||
case SECTOR_STATUS_USING:
|
||||
if(total_sec_num <= 2) {
|
||||
/* like state 1 */
|
||||
cur_log_sec_state = 1;
|
||||
log_start_addr = log_area_start_addr;
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size;
|
||||
} else {
|
||||
/* like state 2 when the sector is the last one */
|
||||
if (cur_size + EF_ERASE_MIN_SIZE >= LOG_AREA_SIZE) {
|
||||
cur_log_sec_state = 2;
|
||||
log_start_addr = get_next_flash_sec_addr(log_area_start_addr + cur_size);
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SECTOR_STATUS_FULL:
|
||||
break;
|
||||
}
|
||||
full_sector_counts++;
|
||||
break;
|
||||
}
|
||||
case SECTOR_STATUS_HEADER_ERROR:
|
||||
EF_DEBUG("Error: Log sector header error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
}
|
||||
last_sec_status = cur_sec_status;
|
||||
}
|
||||
|
||||
/* the last sector status counts */
|
||||
if (cur_sec_status == SECTOR_STATUS_EMPUT) {
|
||||
empty_sec_counts++;
|
||||
} else if (cur_sec_status == SECTOR_STATUS_USING) {
|
||||
using_sec_counts++;
|
||||
} else if (cur_sec_status == SECTOR_STATUS_FULL) {
|
||||
full_sector_counts++;
|
||||
} else if (cur_sec_status == SECTOR_STATUS_HEADER_ERROR) {
|
||||
EF_DEBUG("Error: Log sector header error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
}
|
||||
|
||||
if (using_sec_counts != 1) {
|
||||
/* this state is almost impossible */
|
||||
EF_DEBUG("Error: There must be only one sector status is USING! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
} else {
|
||||
/* find the end address */
|
||||
log_end_addr = find_sec_using_end_addr(cur_using_sec_addr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get log used flash total size.
|
||||
*
|
||||
* @return log used flash total size. @note NOT contain sector headers
|
||||
*/
|
||||
size_t ef_log_get_used_size(void) {
|
||||
size_t header_total_num = 0, physical_size = 0;
|
||||
/* must be call this function after initialize OK */
|
||||
if (!init_ok) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (log_start_addr < log_end_addr) {
|
||||
physical_size = log_end_addr - log_start_addr;
|
||||
} else {
|
||||
physical_size = LOG_AREA_SIZE - (log_start_addr - log_end_addr);
|
||||
}
|
||||
|
||||
header_total_num = physical_size / EF_ERASE_MIN_SIZE + 1;
|
||||
|
||||
return physical_size - header_total_num * LOG_SECTOR_HEADER_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sequential reading log data. It will ignore sector headers.
|
||||
*
|
||||
* @param addr address
|
||||
* @param log log buffer
|
||||
* @param size log size, not contain sector headers.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode log_seq_read(uint32_t addr, uint32_t *log, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t read_size = 0, read_size_temp = 0;
|
||||
|
||||
while (size) {
|
||||
/* move to sector data address */
|
||||
if ((addr + read_size) % EF_ERASE_MIN_SIZE == 0) {
|
||||
addr += LOG_SECTOR_HEADER_SIZE;
|
||||
}
|
||||
/* calculate current sector last data size */
|
||||
read_size_temp = EF_ERASE_MIN_SIZE - (addr % EF_ERASE_MIN_SIZE);
|
||||
if (size < read_size_temp) {
|
||||
read_size_temp = size;
|
||||
}
|
||||
result = ef_port_read(addr + read_size, log + read_size / 4, read_size_temp);
|
||||
if (result != EF_NO_ERR) {
|
||||
return result;
|
||||
}
|
||||
read_size += read_size_temp;
|
||||
size -= read_size_temp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate flash physical address by log index.
|
||||
*
|
||||
* @param index log index
|
||||
*
|
||||
* @return flash physical address
|
||||
*/
|
||||
static uint32_t log_index2addr(size_t index) {
|
||||
size_t header_total_offset = 0;
|
||||
/* total include sector number */
|
||||
size_t sector_num = index / (EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) + 1;
|
||||
|
||||
header_total_offset = sector_num * LOG_SECTOR_HEADER_SIZE;
|
||||
if (log_start_addr < log_end_addr) {
|
||||
return log_start_addr + index + header_total_offset;
|
||||
} else {
|
||||
if (log_start_addr + index + header_total_offset < log_area_start_addr + LOG_AREA_SIZE) {
|
||||
return log_start_addr + index + header_total_offset;
|
||||
} else {
|
||||
return log_start_addr + index + header_total_offset - LOG_AREA_SIZE;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read log from flash.
|
||||
*
|
||||
* @param index index for saved log.
|
||||
* Minimum index is 0.
|
||||
* Maximum index is ef_log_get_used_size() - 1.
|
||||
* @param log the log which will read from flash
|
||||
* @param size read bytes size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t cur_using_size = ef_log_get_used_size();
|
||||
size_t read_size_temp = 0;
|
||||
size_t header_total_num = 0;
|
||||
|
||||
if (!size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
EF_ASSERT(size % 4 == 0);
|
||||
EF_ASSERT(index < cur_using_size);
|
||||
|
||||
if (index + size > cur_using_size) {
|
||||
EF_DEBUG("Warning: Log read size out of bound. Cut read size.\n");
|
||||
size = cur_using_size - index;
|
||||
}
|
||||
/* must be call this function after initialize OK */
|
||||
if (!init_ok) {
|
||||
return EF_ENV_INIT_FAILED;
|
||||
}
|
||||
|
||||
if (log_start_addr < log_end_addr) {
|
||||
log_seq_read(log_index2addr(index), log, size);
|
||||
} else {
|
||||
if (log_index2addr(index) + size <= log_area_start_addr + LOG_AREA_SIZE) {
|
||||
/* Flash log area
|
||||
* |--------------|
|
||||
* log_area_start_addr --> |##############|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |--------------|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |##############| <-- log_end_addr
|
||||
* |--------------|
|
||||
* log_start_addr --> |##############|
|
||||
* read start --> |**************| <-- read end
|
||||
* |##############|
|
||||
* |--------------|
|
||||
*
|
||||
* read from (log_start_addr + log_index2addr(index)) to (log_start_addr + index + log_index2addr(index))
|
||||
*/
|
||||
result = log_seq_read(log_index2addr(index), log, size);
|
||||
} else if (log_index2addr(index) < log_area_start_addr + LOG_AREA_SIZE) {
|
||||
/* Flash log area
|
||||
* |--------------|
|
||||
* log_area_start_addr --> |**************| <-- read end
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |--------------|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |##############| <-- log_end_addr
|
||||
* |--------------|
|
||||
* log_start_addr --> |##############|
|
||||
* read start --> |**************|
|
||||
* |**************|
|
||||
* |--------------|
|
||||
* read will by 2 steps
|
||||
* step1: read from (log_start_addr + log_index2addr(index)) to flash log area end address
|
||||
* step2: read from flash log area start address to read size's end address
|
||||
*/
|
||||
read_size_temp = (log_area_start_addr + LOG_AREA_SIZE) - log_index2addr(index);
|
||||
header_total_num = read_size_temp / EF_ERASE_MIN_SIZE;
|
||||
/* Minus some ignored bytes */
|
||||
read_size_temp -= header_total_num * LOG_SECTOR_HEADER_SIZE;
|
||||
result = log_seq_read(log_index2addr(index), log, read_size_temp);
|
||||
if (result == EF_NO_ERR) {
|
||||
result = log_seq_read(log_area_start_addr, log + read_size_temp / 4, size - read_size_temp);
|
||||
}
|
||||
} else {
|
||||
/* Flash log area
|
||||
* |--------------|
|
||||
* log_area_start_addr --> |##############|
|
||||
* read start --> |**************|
|
||||
* |**************| <-- read end
|
||||
* |--------------|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |##############| <-- log_end_addr
|
||||
* |--------------|
|
||||
* log_start_addr --> |##############|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |--------------|
|
||||
* read from (log_start_addr + log_index2addr(index) - LOG_AREA_SIZE) to read size's end address
|
||||
*/
|
||||
result = log_seq_read(log_index2addr(index) - LOG_AREA_SIZE, log, size);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write log to flash.
|
||||
*
|
||||
* @param log the log which will be write to flash
|
||||
* @param size write bytes size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_log_write(const uint32_t *log, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t write_size = 0, writable_size = 0;
|
||||
uint32_t write_addr = log_end_addr, erase_addr;
|
||||
SectorStatus sector_status;
|
||||
|
||||
EF_ASSERT(size % 4 == 0);
|
||||
/* must be call this function after initialize OK */
|
||||
if (!init_ok) {
|
||||
return EF_ENV_INIT_FAILED;
|
||||
}
|
||||
|
||||
if ((sector_status = get_sector_status(write_addr)) == SECTOR_STATUS_HEADER_ERROR) {
|
||||
return EF_WRITE_ERR;
|
||||
}
|
||||
/* write some log when current sector status is USING and EMPTY */
|
||||
if ((sector_status == SECTOR_STATUS_USING) || (sector_status == SECTOR_STATUS_EMPUT)) {
|
||||
/* write the already erased but not used area */
|
||||
writable_size = EF_ERASE_MIN_SIZE - ((write_addr - log_area_start_addr) % EF_ERASE_MIN_SIZE);
|
||||
if (size >= writable_size) {
|
||||
result = ef_port_write(write_addr, log, writable_size);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
/* change the current sector status to FULL */
|
||||
result = write_sector_status(write_addr, SECTOR_STATUS_FULL);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
write_size += writable_size;
|
||||
} else {
|
||||
result = ef_port_write(write_addr, log, size);
|
||||
log_end_addr = write_addr + size;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
/* erase and write remain log */
|
||||
while (true) {
|
||||
/* calculate next available sector address */
|
||||
erase_addr = write_addr = get_next_flash_sec_addr(write_addr - 4);
|
||||
/* move the flash log start address to next available sector address */
|
||||
if (log_start_addr == erase_addr) {
|
||||
log_start_addr = get_next_flash_sec_addr(log_start_addr);
|
||||
}
|
||||
/* erase sector */
|
||||
result = ef_port_erase(erase_addr, EF_ERASE_MIN_SIZE);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
/* change the sector status to EMPTY and USING when write begin sector start address */
|
||||
result = write_sector_status(write_addr, SECTOR_STATUS_EMPUT);
|
||||
result = write_sector_status(write_addr, SECTOR_STATUS_USING);
|
||||
if (result == EF_NO_ERR) {
|
||||
write_addr += LOG_SECTOR_HEADER_SIZE;
|
||||
} else {
|
||||
goto exit;
|
||||
}
|
||||
/* calculate current sector writable data size */
|
||||
writable_size = EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE;
|
||||
if (size - write_size >= writable_size) {
|
||||
result = ef_port_write(write_addr, log + write_size / 4, writable_size);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
/* change the current sector status to FULL */
|
||||
result = write_sector_status(write_addr, SECTOR_STATUS_FULL);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
log_end_addr = write_addr + writable_size;
|
||||
write_size += writable_size;
|
||||
write_addr += writable_size;
|
||||
} else {
|
||||
result = ef_port_write(write_addr, log + write_size / 4, size - write_size);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
log_end_addr = write_addr + (size - write_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next flash sector address.The log total sector like ring buffer which implement by flash.
|
||||
*
|
||||
* @param cur_addr cur flash address
|
||||
*
|
||||
* @return next flash sector address
|
||||
*/
|
||||
static uint32_t get_next_flash_sec_addr(uint32_t cur_addr) {
|
||||
size_t cur_sec_id = (cur_addr - log_area_start_addr) / EF_ERASE_MIN_SIZE;
|
||||
size_t sec_total_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
|
||||
|
||||
if (cur_sec_id + 1 >= sec_total_num) {
|
||||
/* return to ring head */
|
||||
return log_area_start_addr;
|
||||
} else {
|
||||
return log_area_start_addr + (cur_sec_id + 1) * EF_ERASE_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean all log which in flash.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_log_clean(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
uint32_t write_addr = log_area_start_addr;
|
||||
|
||||
/* clean address */
|
||||
log_start_addr = log_area_start_addr;
|
||||
log_end_addr = log_start_addr + LOG_SECTOR_HEADER_SIZE;
|
||||
/* erase log flash area */
|
||||
result = ef_port_erase(log_area_start_addr, LOG_AREA_SIZE);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
/* setting first sector is EMPTY to USING */
|
||||
write_sector_status(write_addr, SECTOR_STATUS_EMPUT);
|
||||
write_sector_status(write_addr, SECTOR_STATUS_USING);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
write_addr += EF_ERASE_MIN_SIZE;
|
||||
/* add sector header */
|
||||
while (true) {
|
||||
write_sector_status(write_addr, SECTOR_STATUS_EMPUT);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
write_addr += EF_ERASE_MIN_SIZE;
|
||||
if (write_addr >= log_area_start_addr + LOG_AREA_SIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* EF_USING_LOG */
|
99
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_utils.c
Normal file
99
demo/os/nuttx-spiflash/apps/system/easyflash/src/ef_utils.c
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2017, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Some utils for this library.
|
||||
* Created on: 2015-01-14
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
|
||||
static const uint32_t crc32_table[] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the CRC32 value of a memory buffer.
|
||||
*
|
||||
* @param crc accumulated CRC32 value, must be 0 on first call
|
||||
* @param buf buffer to calculate CRC32 value for
|
||||
* @param size bytes in buffer
|
||||
*
|
||||
* @return calculated CRC32 value
|
||||
*/
|
||||
uint32_t ef_calc_crc32(uint32_t crc, const void *buf, size_t size)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
p = (const uint8_t *)buf;
|
||||
crc = crc ^ ~0U;
|
||||
|
||||
while (size--) {
|
||||
crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ ~0U;
|
||||
}
|
27
demo/os/nuttx-spiflash/apps/system/easylogger/Kconfig
Normal file
27
demo/os/nuttx-spiflash/apps/system/easylogger/Kconfig
Normal file
@ -0,0 +1,27 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
menuconfig SYSTEM_EASYLOGGER
|
||||
tristate "Easylogger"
|
||||
default n
|
||||
---help---
|
||||
Enable support for the Easylogger
|
||||
|
||||
if SYSTEM_EASYLOGGER
|
||||
|
||||
config SYSTEM_EASYLOGGER_FILE
|
||||
bool "Enable EasyLogger File"
|
||||
default n
|
||||
---help---
|
||||
Add EasyLogger File support.
|
||||
|
||||
config SYSTEM_EASYLOGGER_FLASH
|
||||
bool "Enable EasyLogger Flash"
|
||||
default n
|
||||
select SYSTEM_EASYFLASH
|
||||
---help---
|
||||
Add EasyLogger Flash support.
|
||||
|
||||
endif # SYSTEM_EASYLOGGER
|
23
demo/os/nuttx-spiflash/apps/system/easylogger/Make.defs
Normal file
23
demo/os/nuttx-spiflash/apps/system/easylogger/Make.defs
Normal file
@ -0,0 +1,23 @@
|
||||
############################################################################
|
||||
# apps/system/easylogger/Make.defs
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_SYSTEM_EASYLOGGER),)
|
||||
CONFIGURED_APPS += $(APPDIR)/system/easylogger
|
||||
endif
|
45
demo/os/nuttx-spiflash/apps/system/easylogger/Makefile
Normal file
45
demo/os/nuttx-spiflash/apps/system/easylogger/Makefile
Normal file
@ -0,0 +1,45 @@
|
||||
############################################################################
|
||||
# apps/system/easylogger/Makefile
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
# easylogger Application
|
||||
|
||||
CSRCS = elog_port.c elog.c elog_utils.c
|
||||
CSRCS += elog_async.c elog_buf.c
|
||||
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/system/easylogger/inc}
|
||||
|
||||
VPATH += :src port
|
||||
|
||||
ifeq ($(CONFIG_SYSTEM_EASYLOGGER_FILE),y)
|
||||
CSRCS += elog_file.c elog_file_port.c
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/system/easylogger/plugins/file}
|
||||
VPATH += :plugins/file
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SYSTEM_EASYLOGGER_FLASH),y)
|
||||
CSRCS += elog_flash.c elog_flash_port.c
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/system/easylogger/plugins/flash}
|
||||
VPATH += :plugins/flash
|
||||
CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/system/easyflash/inc}
|
||||
endif
|
||||
|
||||
include $(APPDIR)/Application.mk
|
86
demo/os/nuttx-spiflash/apps/system/easylogger/inc/elog_cfg.h
Normal file
86
demo/os/nuttx-spiflash/apps/system/easylogger/inc/elog_cfg.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is part of the EasyLogger Library.
|
||||
*
|
||||
* Copyright (c) 2015-2016, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is the configure head file for this library.
|
||||
* Created on: 2015-07-30
|
||||
*/
|
||||
|
||||
#ifndef _ELOG_CFG_H_
|
||||
#define _ELOG_CFG_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* enable log output. */
|
||||
#define ELOG_OUTPUT_ENABLE
|
||||
/* enable terminal output. default open this macro */
|
||||
#define ELOG_TERMINAL_ENABLE
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* enable log write file. default open this macro */
|
||||
// #define ELOG_FILE_ENABLE
|
||||
/* enable flush file cache. default open this macro */
|
||||
// #define ELOG_FILE_FLUSH_CACHE_ENABLE
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* setting static output log level. range: from ELOG_LVL_ASSERT to ELOG_LVL_VERBOSE */
|
||||
#define ELOG_OUTPUT_LVL ELOG_LVL_VERBOSE
|
||||
/* enable assert check */
|
||||
#define ELOG_ASSERT_ENABLE
|
||||
/* buffer size for every line's log */
|
||||
#define ELOG_LINE_BUF_SIZE 160
|
||||
/* output line number max length */
|
||||
#define ELOG_LINE_NUM_MAX_LEN 5
|
||||
/* output filter's tag max length */
|
||||
#define ELOG_FILTER_TAG_MAX_LEN 16
|
||||
/* output filter's keyword max length */
|
||||
#define ELOG_FILTER_KW_MAX_LEN 16
|
||||
/* output filter's tag level max num */
|
||||
#define ELOG_FILTER_TAG_LVL_MAX_NUM 5
|
||||
/* output newline sign */
|
||||
#define ELOG_NEWLINE_SIGN "\n"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* enable log color */
|
||||
// #define ELOG_COLOR_ENABLE
|
||||
/* change the some level logs to not default color if you want */
|
||||
#define ELOG_COLOR_ASSERT (F_MAGENTA B_NULL S_NORMAL)
|
||||
#define ELOG_COLOR_ERROR (F_RED B_NULL S_NORMAL)
|
||||
#define ELOG_COLOR_WARN (F_YELLOW B_NULL S_NORMAL)
|
||||
#define ELOG_COLOR_INFO (F_CYAN B_NULL S_NORMAL)
|
||||
#define ELOG_COLOR_DEBUG (F_GREEN B_NULL S_NORMAL)
|
||||
#define ELOG_COLOR_VERBOSE (F_BLUE B_NULL S_NORMAL)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* enable asynchronous output mode */
|
||||
#define ELOG_ASYNC_OUTPUT_ENABLE
|
||||
/* the highest output level for async mode, other level will sync output */
|
||||
#define ELOG_ASYNC_OUTPUT_LVL ELOG_LVL_DEBUG
|
||||
/* buffer size for asynchronous output mode */
|
||||
#define ELOG_ASYNC_OUTPUT_BUF_SIZE (ELOG_LINE_BUF_SIZE * 10)
|
||||
/* each asynchronous output's log which must end with newline sign */
|
||||
//#define ELOG_ASYNC_LINE_OUTPUT
|
||||
/* asynchronous output mode using POSIX pthread implementation */
|
||||
#define ELOG_ASYNC_OUTPUT_USING_PTHREAD
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* enable buffered output mode */
|
||||
// #define ELOG_BUF_OUTPUT_ENABLE
|
||||
/* buffer size for buffered output mode */
|
||||
// #define ELOG_BUF_OUTPUT_BUF_SIZE (ELOG_LINE_BUF_SIZE * 10)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* _ELOG_CFG_H_ */
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the EasyLogger Library.
|
||||
*
|
||||
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is the configure head file for this flash log plugin.
|
||||
* Created on: 2015-07-30
|
||||
*/
|
||||
|
||||
#ifndef _ELOG_FLASH_CFG_H_
|
||||
#define _ELOG_FLASH_CFG_H_
|
||||
|
||||
/* EasyLogger flash log plugin's using buffer mode */
|
||||
#define ELOG_FLASH_USING_BUF_MODE
|
||||
/* EasyLogger flash log plugin's RAM buffer size */
|
||||
#define ELOG_FLASH_BUF_SIZE 1024 /* @note you must define it for a value */
|
||||
|
||||
#endif /* _ELOG_FLASH_CFG_H_ */
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of the EasyLogger Library.
|
||||
*
|
||||
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Portable interface for EasyLogger's flash log pulgin.
|
||||
* Created on: 2015-07-28
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "elog_flash.h"
|
||||
|
||||
static pthread_mutex_t flash_log_lock;
|
||||
|
||||
/**
|
||||
* EasyLogger flash log pulgin port initialize
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
ElogErrCode elog_flash_port_init(void) {
|
||||
ElogErrCode result = ELOG_NO_ERR;
|
||||
|
||||
/* add your code here */
|
||||
pthread_mutex_init(&flash_log_lock, NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* output flash saved log port interface
|
||||
*
|
||||
* @param log flash saved log
|
||||
* @param size log size
|
||||
*/
|
||||
void elog_flash_port_output(const char *log, size_t size) {
|
||||
|
||||
/* add your code here */
|
||||
printf("%.*s", size, log);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* flash log lock
|
||||
*/
|
||||
void elog_flash_port_lock(void) {
|
||||
|
||||
/* add your code here */
|
||||
pthread_mutex_lock(&flash_log_lock);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* flash log unlock
|
||||
*/
|
||||
void elog_flash_port_unlock(void) {
|
||||
|
||||
/* add your code here */
|
||||
pthread_mutex_unlock(&flash_log_lock);
|
||||
|
||||
}
|
168
demo/os/nuttx-spiflash/apps/system/easylogger/port/elog_port.c
Normal file
168
demo/os/nuttx-spiflash/apps/system/easylogger/port/elog_port.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* This file is part of the EasyLogger Library.
|
||||
*
|
||||
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Portable interface for linux.
|
||||
* Created on: 2015-04-28
|
||||
*/
|
||||
|
||||
#include <elog.h>
|
||||
#include <nuttx/config.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef ELOG_FILE_ENABLE
|
||||
#include <elog_file.h>
|
||||
#endif
|
||||
|
||||
static pthread_mutex_t output_lock;
|
||||
|
||||
/**
|
||||
* EasyLogger port initialize
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
ElogErrCode elog_port_init(void) {
|
||||
ElogErrCode result = ELOG_NO_ERR;
|
||||
|
||||
/* add your code here */
|
||||
pthread_mutex_init(&output_lock, NULL);
|
||||
|
||||
#ifdef ELOG_FILE_ENABLE
|
||||
elog_file_init();
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* EasyLogger port deinitialize
|
||||
*
|
||||
*/
|
||||
void elog_port_deinit(void) {
|
||||
|
||||
/* add your code here */
|
||||
|
||||
#ifdef ELOG_FILE_ENABLE
|
||||
elog_file_deinit();
|
||||
#endif
|
||||
|
||||
pthread_mutex_destroy(&output_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* output log port interface
|
||||
*
|
||||
* @param log output of log
|
||||
* @param size log size
|
||||
*/
|
||||
void elog_port_output(const char *log, size_t size) {
|
||||
|
||||
/* add your code here */
|
||||
|
||||
/* output to terminal */
|
||||
#ifdef ELOG_TERMINAL_ENABLE
|
||||
printf("%.*s", (int)size, log);
|
||||
#endif
|
||||
|
||||
#ifdef ELOG_FILE_ENABLE
|
||||
/* write the file */
|
||||
elog_file_write(log, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* output lock
|
||||
*/
|
||||
void elog_port_output_lock(void) {
|
||||
|
||||
/* add your code here */
|
||||
|
||||
pthread_mutex_lock(&output_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* output unlock
|
||||
*/
|
||||
void elog_port_output_unlock(void) {
|
||||
|
||||
/* add your code here */
|
||||
|
||||
pthread_mutex_unlock(&output_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* get current time interface
|
||||
*
|
||||
* @return current time
|
||||
*/
|
||||
const char *elog_port_get_time(void) {
|
||||
|
||||
/* add your code here */
|
||||
|
||||
static char cur_system_time[24] = { 0 };
|
||||
|
||||
time_t cur_t;
|
||||
struct tm cur_tm;
|
||||
|
||||
time(&cur_t);
|
||||
localtime_r(&cur_t, &cur_tm);
|
||||
|
||||
strftime(cur_system_time, sizeof(cur_system_time), "%Y-%m-%d %T", &cur_tm);
|
||||
|
||||
return cur_system_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current process name interface
|
||||
*
|
||||
* @return current process name
|
||||
*/
|
||||
const char *elog_port_get_p_info(void) {
|
||||
|
||||
/* add your code here */
|
||||
|
||||
static char cur_process_info[10] = { 0 };
|
||||
|
||||
snprintf(cur_process_info, 10, "pid:%04d", getpid());
|
||||
|
||||
return cur_process_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current thread name interface
|
||||
*
|
||||
* @return current thread name
|
||||
*/
|
||||
const char *elog_port_get_t_info(void) {
|
||||
|
||||
/* add your code here */
|
||||
|
||||
static char cur_thread_info[10] = { 0 };
|
||||
|
||||
snprintf(cur_thread_info, 10, "tid:%04d", gettid());
|
||||
|
||||
return cur_thread_info;
|
||||
}
|
BIN
docs/zh/images/ElogNuttxSpiFlashDemo.png
Normal file
BIN
docs/zh/images/ElogNuttxSpiFlashDemo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
Loading…
x
Reference in New Issue
Block a user