1
0
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:
zohar 2023-02-15 17:03:01 +08:00
parent 4fecb2b478
commit f39726143e
37 changed files with 8375 additions and 1 deletions

View File

@ -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**
- 支持按 **标签****级别****关键词** 进行动态过滤;
- 各级别日志支持不同颜色显示;

View 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>

View 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

View 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

View 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

View 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;
}

View 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

View 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

View 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

View 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_ */

View 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_ */

View 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_ */

View File

@ -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);
```

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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

View File

@ -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. */
}

View File

@ -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;
}
}

View 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);
}

View 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;
}

File diff suppressed because it is too large Load Diff

View 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) */

File diff suppressed because it is too large Load Diff

View 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 */

View 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 */

View 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;
}

View 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

View 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

View 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

View 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_ */

View File

@ -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_ */

View File

@ -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);
}

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB