提交全部资料
This commit is contained in:
315
1.主程序源代码/User/FreeRTOSConfig.h
Normal file
315
1.主程序源代码/User/FreeRTOSConfig.h
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
|
||||
#include "stm32f10x.h"
|
||||
#include "bsp_usart.h"
|
||||
|
||||
|
||||
//针对不同的编译器调用不同的stdint.h文件
|
||||
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
|
||||
#include <stdint.h>
|
||||
extern uint32_t SystemCoreClock;
|
||||
#endif
|
||||
|
||||
//断言
|
||||
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
|
||||
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)
|
||||
|
||||
/************************************************************************
|
||||
* FreeRTOS基础配置配置选项
|
||||
*********************************************************************/
|
||||
/* 置1:RTOS使用抢占式调度器;置0:RTOS使用协作式调度器(时间片)
|
||||
*
|
||||
* 注:在多任务管理机制上,操作系统可以分为抢占式和协作式两种。
|
||||
* 协作式操作系统是任务主动释放CPU后,切换到下一个任务。
|
||||
* 任务切换的时机完全取决于正在运行的任务。
|
||||
*/
|
||||
#define configUSE_PREEMPTION 1
|
||||
|
||||
//1使能时间片调度(默认式使能的)
|
||||
#define configUSE_TIME_SLICING 1
|
||||
|
||||
/* 某些运行FreeRTOS的硬件有两种方法选择下一个要执行的任务:
|
||||
* 通用方法和特定于硬件的方法(以下简称“特殊方法”)。
|
||||
*
|
||||
* 通用方法:
|
||||
* 1.configUSE_PORT_OPTIMISED_TASK_SELECTION 为 0 或者硬件不支持这种特殊方法。
|
||||
* 2.可以用于所有FreeRTOS支持的硬件
|
||||
* 3.完全用C实现,效率略低于特殊方法。
|
||||
* 4.不强制要求限制最大可用优先级数目
|
||||
* 特殊方法:
|
||||
* 1.必须将configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1。
|
||||
* 2.依赖一个或多个特定架构的汇编指令(一般是类似计算前导零[CLZ]指令)。
|
||||
* 3.比通用方法更高效
|
||||
* 4.一般强制限定最大可用优先级数目为32
|
||||
* 一般是硬件计算前导零指令,如果所使用的,MCU没有这些硬件指令的话此宏应该设置为0!
|
||||
*/
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||
|
||||
/* 置1:使能低功耗tickless模式;置0:保持系统节拍(tick)中断一直运行
|
||||
* 假设开启低功耗的话可能会导致下载出现问题,因为程序在睡眠中,可用以下办法解决
|
||||
*
|
||||
* 下载方法:
|
||||
* 1.将开发版正常连接好
|
||||
* 2.按住复位按键,点击下载瞬间松开复位按键
|
||||
*
|
||||
* 1.通过跳线帽将 BOOT 0 接高电平(3.3V)
|
||||
* 2.重新上电,下载
|
||||
*
|
||||
* 1.使用FlyMcu擦除一下芯片,然后进行下载
|
||||
* STMISP -> 清除芯片(z)
|
||||
*/
|
||||
#define configUSE_TICKLESS_IDLE 0
|
||||
|
||||
/*
|
||||
* 写入实际的CPU内核时钟频率,也就是CPU指令执行频率,通常称为Fclk
|
||||
* Fclk为供给CPU内核的时钟信号,我们所说的cpu主频为 XX MHz,
|
||||
* 就是指的这个时钟信号,相应的,1/Fclk即为cpu时钟周期;
|
||||
*/
|
||||
#define configCPU_CLOCK_HZ (SystemCoreClock)
|
||||
|
||||
//RTOS系统节拍中断的频率。即一秒中断的次数,每次中断RTOS都会进行任务调度
|
||||
#define configTICK_RATE_HZ (( TickType_t )1000)
|
||||
|
||||
//可使用的最大优先级
|
||||
#define configMAX_PRIORITIES (32)
|
||||
|
||||
//空闲任务使用的堆栈大小
|
||||
#define configMINIMAL_STACK_SIZE ((unsigned short)128)
|
||||
|
||||
//任务名字字符串长度
|
||||
#define configMAX_TASK_NAME_LEN (16)
|
||||
|
||||
//系统节拍计数器变量数据类型,1表示为16位无符号整形,0表示为32位无符号整形
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
|
||||
//空闲任务放弃CPU使用权给其他同优先级的用户任务
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
|
||||
//启用队列
|
||||
#define configUSE_QUEUE_SETS 0
|
||||
|
||||
//开启任务通知功能,默认开启
|
||||
#define configUSE_TASK_NOTIFICATIONS 1
|
||||
|
||||
//使用互斥信号量
|
||||
#define configUSE_MUTEXES 1
|
||||
|
||||
//使用递归互斥信号量
|
||||
#define configUSE_RECURSIVE_MUTEXES 0
|
||||
|
||||
//为1时使用计数信号量
|
||||
#define configUSE_COUNTING_SEMAPHORES 0
|
||||
|
||||
/* 设置可以注册的信号量和消息队列个数 */
|
||||
#define configQUEUE_REGISTRY_SIZE 10
|
||||
|
||||
#define configUSE_APPLICATION_TASK_TAG 0
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
FreeRTOS与内存申请有关配置选项
|
||||
*****************************************************************/
|
||||
//支持动态内存申请
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
//支持静态内存
|
||||
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||
//系统所有总的堆大小
|
||||
#define configTOTAL_HEAP_SIZE ((size_t)(10*1024))
|
||||
|
||||
|
||||
/***************************************************************
|
||||
FreeRTOS与钩子函数有关的配置选项
|
||||
**************************************************************/
|
||||
/* 置1:使用空闲钩子(Idle Hook类似于回调函数);置0:忽略空闲钩子
|
||||
*
|
||||
* 空闲任务钩子是一个函数,这个函数由用户来实现,
|
||||
* FreeRTOS规定了函数的名字和参数:void vApplicationIdleHook(void ),
|
||||
* 这个函数在每个空闲任务周期都会被调用
|
||||
* 对于已经删除的RTOS任务,空闲任务可以释放分配给它们的堆栈内存。
|
||||
* 因此必须保证空闲任务可以被CPU执行
|
||||
* 使用空闲钩子函数设置CPU进入省电模式是很常见的
|
||||
* 不可以调用会引起空闲任务阻塞的API函数
|
||||
*/
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
|
||||
/* 置1:使用时间片钩子(Tick Hook);置0:忽略时间片钩子
|
||||
*
|
||||
*
|
||||
* 时间片钩子是一个函数,这个函数由用户来实现,
|
||||
* FreeRTOS规定了函数的名字和参数:void vApplicationTickHook(void )
|
||||
* 时间片中断可以周期性的调用
|
||||
* 函数必须非常短小,不能大量使用堆栈,
|
||||
* 不能调用以”FromISR" 或 "FROM_ISR”结尾的API函数
|
||||
*/
|
||||
/*xTaskIncrementTick函数是在xPortSysTickHandler中断函数中被调用的。因此,vApplicationTickHook()函数执行的时间必须很短才行*/
|
||||
#define configUSE_TICK_HOOK 0
|
||||
|
||||
//使用内存申请失败钩子函数
|
||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||
|
||||
/*
|
||||
* 大于0时启用堆栈溢出检测功能,如果使用此功能
|
||||
* 用户必须提供一个栈溢出钩子函数,如果使用的话
|
||||
* 此值可以为1或者2,因为有两种栈溢出检测方法 */
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||
|
||||
|
||||
/********************************************************************
|
||||
FreeRTOS与运行时间和任务状态收集有关的配置选项
|
||||
**********************************************************************/
|
||||
//启用运行时间统计功能
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
//启用可视化跟踪调试
|
||||
#define configUSE_TRACE_FACILITY 0
|
||||
/* 与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数
|
||||
* prvWriteNameToBuffer()
|
||||
* vTaskList(),
|
||||
* vTaskGetRunTimeStats()
|
||||
*/
|
||||
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
|
||||
|
||||
|
||||
/********************************************************************
|
||||
FreeRTOS与协程有关的配置选项
|
||||
*********************************************************************/
|
||||
//启用协程,启用协程以后必须添加文件croutine.c
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
//协程的有效优先级数目
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
FreeRTOS与软件定时器有关的配置选项
|
||||
**********************************************************************/
|
||||
//启用软件定时器
|
||||
#define configUSE_TIMERS 1
|
||||
//软件定时器优先级
|
||||
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1)
|
||||
//软件定时器队列长度
|
||||
#define configTIMER_QUEUE_LENGTH 10
|
||||
//软件定时器任务堆栈大小
|
||||
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*1)
|
||||
|
||||
/************************************************************
|
||||
FreeRTOS可选函数配置选项
|
||||
************************************************************/
|
||||
#define INCLUDE_xTaskGetSchedulerState 1
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskCleanUpResources 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_eTaskGetState 1
|
||||
#define INCLUDE_xTimerPendFunctionCall 0
|
||||
//#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||
//#define INCLUDE_uxTaskGetStackHighWaterMark 0
|
||||
//#define INCLUDE_xTaskGetIdleTaskHandle 0
|
||||
|
||||
|
||||
/******************************************************************
|
||||
FreeRTOS与中断有关的配置选项
|
||||
******************************************************************/
|
||||
#ifdef __NVIC_PRIO_BITS
|
||||
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||
#else
|
||||
#define configPRIO_BITS 4
|
||||
#endif
|
||||
//中断最低优先级
|
||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
|
||||
|
||||
//系统可管理的最高中断优先级
|
||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
||||
|
||||
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) /* 240 */
|
||||
|
||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||
|
||||
|
||||
/****************************************************************
|
||||
FreeRTOS与中断服务函数有关的配置选项
|
||||
****************************************************************/
|
||||
#define xPortPendSVHandler PendSV_Handler
|
||||
#define vPortSVCHandler SVC_Handler
|
||||
|
||||
|
||||
/* 以下为使用Percepio Tracealyzer需要的东西,不需要时将 configUSE_TRACE_FACILITY 定义为 0 */
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
#include "trcRecorder.h"
|
||||
#define INCLUDE_xTaskGetCurrentTaskHandle 1 // 启用一个可选函数(该函数被 Trace源码使用,默认该值为0 表示不用)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
||||
|
||||
107
1.主程序源代码/User/easydb/inc/easyflash.h
Normal file
107
1.主程序源代码/User/easydb/inc/easyflash.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2014-2019, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is an head file for this library. You can see all be called functions.
|
||||
* Created on: 2014-09-10
|
||||
*/
|
||||
|
||||
|
||||
#ifndef EASYFLASH_H_
|
||||
#define EASYFLASH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <ef_cfg.h>
|
||||
#include <ef_def.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* easyflash.c */
|
||||
EfErrCode easyflash_init(void);
|
||||
|
||||
#ifdef EF_USING_ENV
|
||||
/* only supported on ef_env.c */
|
||||
size_t ef_get_env_blob(const char *key, void *value_buf, size_t buf_len, size_t *saved_value_len);
|
||||
bool ef_get_env_obj(const char *key, env_node_obj_t env);
|
||||
size_t ef_read_env_value(env_node_obj_t env, uint8_t *value_buf, size_t buf_len);
|
||||
EfErrCode ef_set_env_blob(const char *key, const void *value_buf, size_t buf_len);
|
||||
|
||||
/* ef_env.c, ef_env_legacy_wl.c and ef_env_legacy.c */
|
||||
EfErrCode ef_load_env(void);
|
||||
void ef_print_env(void);
|
||||
char *ef_get_env(const char *key);
|
||||
EfErrCode ef_set_env(const char *key, const char *value);
|
||||
EfErrCode ef_del_env(const char *key);
|
||||
EfErrCode ef_save_env(void);
|
||||
EfErrCode ef_env_set_default(void);
|
||||
size_t ef_get_env_write_bytes(void);
|
||||
EfErrCode ef_set_and_save_env(const char *key, const char *value);
|
||||
EfErrCode ef_del_and_save_env(const char *key);
|
||||
#endif
|
||||
|
||||
#ifdef EF_USING_IAP
|
||||
/* ef_iap.c */
|
||||
EfErrCode ef_erase_bak_app(size_t app_size);
|
||||
EfErrCode ef_erase_user_app(uint32_t user_app_addr, size_t user_app_size);
|
||||
EfErrCode ef_erase_spec_user_app(uint32_t user_app_addr, size_t app_size,
|
||||
EfErrCode (*app_erase)(uint32_t addr, size_t size));
|
||||
EfErrCode ef_erase_bl(uint32_t bl_addr, size_t bl_size);
|
||||
EfErrCode ef_write_data_to_bak(uint8_t *data, size_t size, size_t *cur_size,
|
||||
size_t total_size);
|
||||
EfErrCode ef_copy_app_from_bak(uint32_t user_app_addr, size_t app_size);
|
||||
EfErrCode ef_copy_spec_app_from_bak(uint32_t user_app_addr, size_t app_size,
|
||||
EfErrCode (*app_write)(uint32_t addr, const uint32_t *buf, size_t size));
|
||||
EfErrCode ef_copy_bl_from_bak(uint32_t bl_addr, size_t bl_size);
|
||||
uint32_t ef_get_bak_app_start_addr(void);
|
||||
#endif
|
||||
|
||||
#ifdef EF_USING_LOG
|
||||
/* ef_log.c */
|
||||
EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size);
|
||||
EfErrCode ef_log_write(const uint32_t *log, size_t size);
|
||||
EfErrCode ef_log_clean(void);
|
||||
size_t ef_log_get_used_size(void);
|
||||
#endif
|
||||
|
||||
/* ef_utils.c */
|
||||
uint32_t ef_calc_crc32(uint32_t crc, const void *buf, size_t size);
|
||||
|
||||
/* ef_port.c */
|
||||
EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size);
|
||||
EfErrCode ef_port_erase(uint32_t addr, size_t size);
|
||||
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size);
|
||||
void ef_port_env_lock(void);
|
||||
void ef_port_env_unlock(void);
|
||||
void ef_log_debug(const char *file, const long line, const char *format, ...);
|
||||
void ef_log_info(const char *format, ...);
|
||||
void ef_print(const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EASYFLASH_H_ */
|
||||
89
1.主程序源代码/User/easydb/inc/ef_cfg.h
Normal file
89
1.主程序源代码/User/easydb/inc/ef_cfg.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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_
|
||||
|
||||
#include <stm32f10x_conf.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
|
||||
|
||||
/* page size for stm32 flash */
|
||||
#if defined(STM32F10X_LD) || defined(STM32F10X_LD_VL) || defined (STM32F10X_MD) || defined (STM32F10X_MD_VL)
|
||||
#define PAGE_SIZE 1024
|
||||
#else
|
||||
#define PAGE_SIZE 2048
|
||||
#endif
|
||||
|
||||
/* the minimum size of flash erasure */
|
||||
#define EF_ERASE_MIN_SIZE PAGE_SIZE /* it is one page for STM3210x */
|
||||
|
||||
/* the flash write granularity, unit: bit
|
||||
* only support 1(nor flash)/ 8(stm32f4)/ 32(stm32f1)/ 64(stm32l4) */
|
||||
#define EF_WRITE_GRAN 32
|
||||
|
||||
/*
|
||||
*
|
||||
* 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 (FLASH_BASE + 55 * 1024) /* from the chip position: 100KB */
|
||||
/* 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 (5 * EF_ERASE_MIN_SIZE) /* 20K */
|
||||
|
||||
/* print debug information of flash */
|
||||
#define PRINT_DEBUG
|
||||
|
||||
#endif /* EF_CFG_H_ */
|
||||
124
1.主程序源代码/User/easydb/inc/ef_def.h
Normal file
124
1.主程序源代码/User/easydb/inc/ef_def.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2019-2020, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: It is the definitions head file for this library.
|
||||
* Created on: 2019-11-20
|
||||
*/
|
||||
|
||||
#ifndef EF_DEF_H_
|
||||
#define EF_DEF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* EasyFlash software version number */
|
||||
#define EF_SW_VERSION "4.1.99"
|
||||
#define EF_SW_VERSION_NUM 0x40199
|
||||
|
||||
/*
|
||||
* ENV version number defined by user.
|
||||
* Please change it when your firmware add a new ENV to default_env_set.
|
||||
*/
|
||||
#ifndef EF_ENV_VER_NUM
|
||||
#define EF_ENV_VER_NUM 0
|
||||
#endif
|
||||
|
||||
/* the ENV max name length must less then it */
|
||||
#ifndef EF_ENV_NAME_MAX
|
||||
#define EF_ENV_NAME_MAX 32
|
||||
#endif
|
||||
|
||||
/* EasyFlash debug print function. Must be implement by user. */
|
||||
#ifdef PRINT_DEBUG
|
||||
#define EF_DEBUG(...) ef_log_debug(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define EF_DEBUG(...)
|
||||
#endif
|
||||
/* EasyFlash routine print function. Must be implement by user. */
|
||||
#define EF_INFO(...) ef_log_info(__VA_ARGS__)
|
||||
/* EasyFlash assert for developer. */
|
||||
#define EF_ASSERT(EXPR) \
|
||||
if (!(EXPR)) \
|
||||
{ \
|
||||
EF_DEBUG("(%s) has assert failed at %s.\n", #EXPR, __FUNCTION__); \
|
||||
while (1); \
|
||||
}
|
||||
|
||||
typedef struct _ef_env {
|
||||
char *key;
|
||||
void *value;
|
||||
size_t value_len;
|
||||
} ef_env, *ef_env_t;
|
||||
|
||||
/* EasyFlash error code */
|
||||
typedef enum {
|
||||
EF_NO_ERR,
|
||||
EF_ERASE_ERR,
|
||||
EF_READ_ERR,
|
||||
EF_WRITE_ERR,
|
||||
EF_ENV_NAME_ERR,
|
||||
EF_ENV_NAME_EXIST,
|
||||
EF_ENV_FULL,
|
||||
EF_ENV_INIT_FAILED,
|
||||
} EfErrCode;
|
||||
|
||||
/* the flash sector current status */
|
||||
typedef enum {
|
||||
EF_SECTOR_EMPTY,
|
||||
EF_SECTOR_USING,
|
||||
EF_SECTOR_FULL,
|
||||
} EfSecrorStatus;
|
||||
|
||||
enum env_status {
|
||||
ENV_UNUSED,
|
||||
ENV_PRE_WRITE,
|
||||
ENV_WRITE,
|
||||
ENV_PRE_DELETE,
|
||||
ENV_DELETED,
|
||||
ENV_ERR_HDR,
|
||||
ENV_STATUS_NUM,
|
||||
};
|
||||
typedef enum env_status env_status_t;
|
||||
|
||||
struct env_node_obj {
|
||||
env_status_t status; /**< ENV node status, @see node_status_t */
|
||||
bool crc_is_ok; /**< ENV node CRC32 check is OK */
|
||||
uint8_t name_len; /**< name length */
|
||||
uint32_t magic; /**< magic word(`K`, `V`, `4`, `0`) */
|
||||
uint32_t len; /**< ENV node total length (header + name + value), must align by EF_WRITE_GRAN */
|
||||
uint32_t value_len; /**< value length */
|
||||
char name[EF_ENV_NAME_MAX]; /**< name */
|
||||
struct {
|
||||
uint32_t start; /**< ENV node start address */
|
||||
uint32_t value; /**< value start address */
|
||||
} addr;
|
||||
};
|
||||
typedef struct env_node_obj *env_node_obj_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EF_DEF_H_ */
|
||||
152
1.主程序源代码/User/easydb/plugins/types/README.md
Normal file
152
1.主程序源代码/User/easydb/plugins/types/README.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# EasyFlash Types 插件(plugin)
|
||||
|
||||
---
|
||||
|
||||
## 1、介绍
|
||||
|
||||
目前 EasyFlash 会将环境变量以字符串形式存储于 Flash 中,在这种模式下,对于非字符串类型的环境变量在使用时,就必须得增加额外的字符串转换代码。设计 Types 插件就是为了方便用户在使用 EasyFlash 时,以更加简单的方式去操作各种类型的环境变量。
|
||||
|
||||
主要支持的类型包括:C 的 **基本类型** 、 **数组类型** 以及 **结构体类型** 。对于结构体类型, Types 插件内部采用 [struct2json](https://github.com/armink/struct2json) 库进行转换,所以项目中需要依赖 [struct2json](https://github.com/armink/struct2json) 库。
|
||||
|
||||
## 2、使用
|
||||
|
||||
### 2.1 源码导入
|
||||
|
||||
导入之前需要确认自己的项目中已包含 EasyFlash 核心源码,即包括 "\easyflash\inc"、"\easyflash\port" 及 "\easyflash\src" 下相关文件(导入方法可以参考这个移植文档:[点击打开](https://github.com/armink/EasyFlash/blob/master/docs/zh/port.md))。再将 Types 插件源码导入到项目中,最好连同 "plugins\types" 文件夹一起拷贝至项目中已有的 easyflash 文件夹下。然后需要添加 `easyflash\plugins\types\struct2json\inc` 及 `easyflash\plugins\types` 两个文件夹路径到项目头文件路径中即可。
|
||||
|
||||
### 2.2 初始化
|
||||
|
||||
```C
|
||||
void ef_types_init(S2jHook *hook)
|
||||
```
|
||||
|
||||
这个方法为 Types 插件的初始化方法,主要初始化 struct2json 库所需的内存管理方法。默认使用的 malloc 及 free 作为内存管理方法,如果使用默认内存管理方式,则无需初始化。例如如果使用 RT-Thread 操作系统自带的内存管理方法,则可以参考下面的初始化代码:
|
||||
|
||||
```C
|
||||
S2jHook s2jHook = {
|
||||
.free_fn = rt_free,
|
||||
.malloc_fn = (void *(*)(size_t))rt_malloc,
|
||||
};
|
||||
ef_types_init(&s2jHook);
|
||||
```
|
||||
|
||||
### 2.3 操作环境变量
|
||||
|
||||
#### 2.3.1 基本类型
|
||||
|
||||
对于基本类型的环境变量操作方法与 EasyFlash 原有的 API 一致,只是修改了入参及出参的类型,所有可用的 API 如下:
|
||||
|
||||
```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 数组类型
|
||||
|
||||
与基本类型的操作方法大体一致,不同点在于:获取到的环境变量需通过指针类型的入参进行返回。所有可用的 API 如下:
|
||||
|
||||
```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 结构体类型
|
||||
|
||||
对于结构体类型,这里首先需要使用 struct2json 库来编写与该结构体对应的 JSON 互转方法,再将编写好的互转方法作为入参进行使用。结构体类型环境变量操作的 API 如下:
|
||||
|
||||
```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);
|
||||
```
|
||||
|
||||
具体使用流程及结构体与 JSON 之间的互转方法可以参考下面的 Demo:
|
||||
|
||||
```C
|
||||
/* 定义结构体 */
|
||||
typedef struct {
|
||||
char name[16];
|
||||
} Hometown;
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
double weight;
|
||||
uint8_t score[8];
|
||||
char name[16];
|
||||
Hometown hometown;
|
||||
} Student;
|
||||
|
||||
/* 定义结构体转 JSON 的方法 */
|
||||
static cJSON *stu_set_cb(void* struct_obj) {
|
||||
Student *struct_student = (Student *)struct_obj;
|
||||
/* 创建 Student JSON 对象 */
|
||||
s2j_create_json_obj(json_student);
|
||||
/* 序列化数据到 Student JSON 对象 */
|
||||
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);
|
||||
/* 序列化数据到 Student.Hometown JSON 对象 */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 定义 JSON 转结构体的方法 */
|
||||
static void *stu_get_cb(cJSON* json_obj) {
|
||||
/* 创建 Student 结构体对象(提示: s2j_ 开头的方法是 struct2json 库提供的) */
|
||||
s2j_create_struct_obj(struct_student, Student);
|
||||
/* 反序列化数据到 Student 结构体对象 */
|
||||
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);
|
||||
/* 反序列化数据到 Student.Hometown 结构体对象 */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 设置结构体类型环境变量 */
|
||||
Student orignal_student = {
|
||||
.id = 24,
|
||||
.weight = 71.2,
|
||||
.score = {1, 2, 3, 4, 5, 6, 7, 8},
|
||||
.name = "张三",
|
||||
.hometown.name = "北京",
|
||||
};
|
||||
ef_set_struct("张三学生", &orignal_student, stu_set_cb);
|
||||
|
||||
/* 获取结构体类型环境变量 */
|
||||
Student *student;
|
||||
ef_get_struct("张三学生", student, stu_get_cb);
|
||||
|
||||
/* 打印获取到的结构体内容 */
|
||||
printf("姓名:%s 籍贯:%s \n", student->name, student->hometown.name);
|
||||
|
||||
/* 释放获取结构体类型环境变量过程中开辟的动态内存 */
|
||||
s2jHook.free_fn(student);
|
||||
```
|
||||
395
1.主程序源代码/User/easydb/plugins/types/ef_types.c
Normal file
395
1.主程序源代码/User/easydb/plugins/types/ef_types.c
Normal 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;
|
||||
}
|
||||
76
1.主程序源代码/User/easydb/plugins/types/ef_types.h
Normal file
76
1.主程序源代码/User/easydb/plugins/types/ef_types.h
Normal 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_ */
|
||||
154
1.主程序源代码/User/easydb/plugins/types/struct2json/inc/cJSON.h
Normal file
154
1.主程序源代码/User/easydb/plugins/types/struct2json/inc/cJSON.h
Normal 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
|
||||
91
1.主程序源代码/User/easydb/plugins/types/struct2json/inc/s2j.h
Normal file
91
1.主程序源代码/User/easydb/plugins/types/struct2json/inc/s2j.h
Normal 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__ */
|
||||
150
1.主程序源代码/User/easydb/plugins/types/struct2json/inc/s2jdef.h
Normal file
150
1.主程序源代码/User/easydb/plugins/types/struct2json/inc/s2jdef.h
Normal 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__ */
|
||||
61
1.主程序源代码/User/easydb/plugins/types/struct2json/readme.md
Normal file
61
1.主程序源代码/User/easydb/plugins/types/struct2json/readme.md
Normal 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://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))|
|
||||
|:-----:|:-----:|
|
||||
|| |
|
||||
|
||||
欢迎大家 **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
|
||||
762
1.主程序源代码/User/easydb/plugins/types/struct2json/src/cJSON.c
Normal file
762
1.主程序源代码/User/easydb/plugins/types/struct2json/src/cJSON.c
Normal 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. */
|
||||
}
|
||||
52
1.主程序源代码/User/easydb/plugins/types/struct2json/src/s2j.c
Normal file
52
1.主程序源代码/User/easydb/plugins/types/struct2json/src/s2j.c
Normal 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;
|
||||
}
|
||||
}
|
||||
228
1.主程序源代码/User/easydb/port/ef_port.c
Normal file
228
1.主程序源代码/User/easydb/port/ef_port.c
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* default environment variables set for user */
|
||||
static const ef_env default_env_set[] = {
|
||||
{"boot_times","0"},
|
||||
};
|
||||
|
||||
static char log_buf[128];
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
*default_env = default_env_set;
|
||||
*default_env_size = sizeof(default_env_set) / sizeof(default_env_set[0]);
|
||||
|
||||
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;
|
||||
uint8_t *buf_8 = (uint8_t *)buf;
|
||||
size_t i;
|
||||
|
||||
/*copy from flash to ram */
|
||||
for (i = 0; i < size; i++, addr ++, buf_8++) {
|
||||
*buf_8 = *(uint8_t *) addr;
|
||||
}
|
||||
|
||||
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;
|
||||
FLASH_Status flash_status;
|
||||
size_t erase_pages, i;
|
||||
|
||||
/* make sure the start address is a multiple of FLASH_ERASE_MIN_SIZE */
|
||||
EF_ASSERT(addr % EF_ERASE_MIN_SIZE == 0);
|
||||
|
||||
/* calculate pages */
|
||||
erase_pages = size / PAGE_SIZE;
|
||||
if (size % PAGE_SIZE != 0) {
|
||||
erase_pages++;
|
||||
}
|
||||
|
||||
/* start erase */
|
||||
FLASH_Unlock();
|
||||
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
|
||||
for (i = 0; i < erase_pages; i++) {
|
||||
flash_status = FLASH_ErasePage(addr + (PAGE_SIZE * i));
|
||||
if (flash_status != FLASH_COMPLETE) {
|
||||
result = EF_ERASE_ERR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
FLASH_Lock();
|
||||
|
||||
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;
|
||||
size_t i;
|
||||
uint32_t read_data;
|
||||
|
||||
FLASH_Unlock();
|
||||
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
|
||||
for (i = 0; i < size; i += 4, buf++, addr += 4) {
|
||||
/* write data */
|
||||
FLASH_ProgramWord(addr, *buf);
|
||||
read_data = *(uint32_t *)addr;
|
||||
/* check data */
|
||||
if (read_data != *buf) {
|
||||
result = EF_WRITE_ERR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
FLASH_Lock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* lock the ENV ram cache
|
||||
*/
|
||||
void ef_port_env_lock(void) {
|
||||
__disable_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* unlock the ENV ram cache
|
||||
*/
|
||||
void ef_port_env_unlock(void) {
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
ef_print("[Flash](%s:%ld) ", file, line);
|
||||
/* must use vprintf to print */
|
||||
vsprintf(log_buf, format, args);
|
||||
ef_print("%s", log_buf);
|
||||
printf("\r");
|
||||
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);
|
||||
ef_print("[Flash]");
|
||||
/* must use vprintf to print */
|
||||
vsprintf(log_buf, format, args);
|
||||
ef_print("%s", log_buf);
|
||||
printf("\r");
|
||||
va_end(args);
|
||||
}
|
||||
/**
|
||||
* This function is print flash non-package info.
|
||||
*
|
||||
* @param format output format
|
||||
* @param ... args
|
||||
*/
|
||||
void ef_print(const char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
/* args point to the first variable parameter */
|
||||
va_start(args, format);
|
||||
/* must use vprintf to print */
|
||||
vsprintf(log_buf, format, args);
|
||||
printf("%s", log_buf);
|
||||
va_end(args);
|
||||
}
|
||||
109
1.主程序源代码/User/easydb/src/easyflash.c
Normal file
109
1.主程序源代码/User/easydb/src/easyflash.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2014-2019, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Initialize interface for this library.
|
||||
* Created on: 2014-09-09
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* This all Backup Area Flash storage index. All used flash area configure is under here.
|
||||
* |----------------------------| Storage Size
|
||||
* | Environment variables area | ENV area size @see ENV_AREA_SIZE
|
||||
* |----------------------------|
|
||||
* | Saved log area | Log area size @see LOG_AREA_SIZE
|
||||
* |----------------------------|
|
||||
* |(IAP)Downloaded application | IAP already downloaded application, unfixed size
|
||||
* |----------------------------|
|
||||
*
|
||||
* @note all area sizes must be aligned with EF_ERASE_MIN_SIZE
|
||||
*
|
||||
* The EasyFlash add the NG (Next Generation) mode start from V4.0. All old mode before V4.0, called LEGACY mode.
|
||||
*
|
||||
* - NG (Next Generation) mode is default mode from V4.0. It's easy to settings, only defined the ENV_AREA_SIZE.
|
||||
* - The LEGACY mode has been DEPRECATED. It is NOT RECOMMENDED to continue using.
|
||||
* Beacuse it will use ram to buffer the ENV and spend more flash erase times.
|
||||
* If you want use it please using the V3.X version.
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
|
||||
#if !defined(EF_START_ADDR)
|
||||
#error "Please configure backup area start address (in ef_cfg.h)"
|
||||
#endif
|
||||
|
||||
#if !defined(EF_ERASE_MIN_SIZE)
|
||||
#error "Please configure minimum size of flash erasure (in ef_cfg.h)"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* EasyFlash system initialize.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode easyflash_init(void) {
|
||||
extern EfErrCode ef_port_init(ef_env const **default_env, size_t *default_env_size);
|
||||
extern EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size);
|
||||
// extern EfErrCode ef_iap_init(void);
|
||||
extern EfErrCode ef_log_init(void);
|
||||
|
||||
size_t default_env_set_size = 0;
|
||||
const ef_env *default_env_set;
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
static bool init_ok = false;
|
||||
|
||||
if (init_ok) {
|
||||
return EF_NO_ERR;
|
||||
}
|
||||
|
||||
result = ef_port_init(&default_env_set, &default_env_set_size);
|
||||
|
||||
#ifdef EF_USING_ENV
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_env_init(default_env_set, default_env_set_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EF_USING_IAP
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_iap_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EF_USING_LOG
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_log_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (result == EF_NO_ERR) {
|
||||
init_ok = true;
|
||||
EF_INFO("EasyFlash V%s is initialize success.\n", EF_SW_VERSION);
|
||||
} else {
|
||||
EF_INFO("EasyFlash V%s is initialize fail.\n", EF_SW_VERSION);
|
||||
}
|
||||
// EF_INFO("You can get the latest version on https://github.com/armink/EasyFlash .\n");
|
||||
|
||||
return result;
|
||||
}
|
||||
1841
1.主程序源代码/User/easydb/src/ef_env.c
Normal file
1841
1.主程序源代码/User/easydb/src/ef_env.c
Normal file
File diff suppressed because it is too large
Load Diff
922
1.主程序源代码/User/easydb/src/ef_env_legacy.c
Normal file
922
1.主程序源代码/User/easydb/src/ef_env_legacy.c
Normal file
@@ -0,0 +1,922 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2014-2018, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Environment variables operating interface. (normal mode)
|
||||
* Created on: 2014-10-06
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(EF_USING_ENV) && defined(EF_ENV_USING_LEGACY_MODE)
|
||||
|
||||
#ifndef EF_ENV_USING_WL_MODE
|
||||
|
||||
#if defined(EF_USING_ENV) && (!defined(ENV_USER_SETTING_SIZE) || !defined(ENV_AREA_SIZE))
|
||||
#error "Please configure user setting ENV size or ENV area size (in ef_cfg.h)"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ENV area has 2 sections
|
||||
* 1. System section
|
||||
* It storages ENV parameters. (Units: Word)
|
||||
* 2. Data section
|
||||
* It storages all ENV. Storage format is key=value\0.
|
||||
* All ENV must be 4 bytes alignment. The remaining part must fill '\0'.
|
||||
*
|
||||
* @note Word = 4 Bytes in this file
|
||||
* @note When using power fail safeguard mode, it has two ENV areas(Area0, Area1).
|
||||
*/
|
||||
|
||||
/* flash ENV parameters index and size in system section */
|
||||
enum {
|
||||
/* data section ENV end address index in system section */
|
||||
ENV_PARAM_INDEX_END_ADDR = 0,
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* saved count for ENV area */
|
||||
ENV_PARAM_INDEX_SAVED_COUNT,
|
||||
#endif
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
/* current version number for ENV */
|
||||
ENV_PARAM_INDEX_VER_NUM,
|
||||
#endif
|
||||
|
||||
/* data section CRC32 code index in system section */
|
||||
ENV_PARAM_INDEX_DATA_CRC,
|
||||
/* flash ENV parameters word size */
|
||||
ENV_PARAM_WORD_SIZE,
|
||||
/* flash ENV parameters byte size */
|
||||
ENV_PARAM_BYTE_SIZE = ENV_PARAM_WORD_SIZE * 4,
|
||||
};
|
||||
|
||||
/* default ENV set, must be initialized by user */
|
||||
static ef_env const *default_env_set;
|
||||
/* default ENV set size, must be initialized by user */
|
||||
static size_t default_env_set_size = 0;
|
||||
/* ENV ram cache */
|
||||
static uint32_t env_cache[ENV_USER_SETTING_SIZE / 4] = { 0 };
|
||||
/* ENV start address in flash */
|
||||
static uint32_t env_start_addr = 0;
|
||||
/* ENV ram cache has changed when ENV created, deleted and changed value. */
|
||||
static bool env_cache_changed = false;
|
||||
/* initialize OK flag */
|
||||
static bool init_ok = false;
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* current load ENV area address */
|
||||
static uint32_t cur_load_area_addr = 0;
|
||||
/* next save ENV area address */
|
||||
static uint32_t next_save_area_addr = 0;
|
||||
#endif
|
||||
|
||||
static uint32_t get_env_system_addr(void);
|
||||
static uint32_t get_env_data_addr(void);
|
||||
static uint32_t get_env_end_addr(void);
|
||||
static void set_env_end_addr(uint32_t end_addr);
|
||||
static EfErrCode write_env(const char *key, const char *value);
|
||||
static char *find_env(const char *key);
|
||||
static EfErrCode del_env(const char *key);
|
||||
static size_t get_env_data_size(void);
|
||||
static size_t get_env_user_used_size(void);
|
||||
static EfErrCode create_env(const char *key, const char *value);
|
||||
static uint32_t calc_env_crc(void);
|
||||
static bool env_crc_is_ok(void);
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
static EfErrCode env_auto_update(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Flash ENV initialize.
|
||||
*
|
||||
* @param default_env default ENV set for user
|
||||
* @param default_env_size default ENV set size
|
||||
*
|
||||
* @note user_size must equal with total_size in normal mode
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
EF_ASSERT(ENV_AREA_SIZE);
|
||||
EF_ASSERT(ENV_USER_SETTING_SIZE);
|
||||
EF_ASSERT(EF_ERASE_MIN_SIZE);
|
||||
/* must be word alignment for ENV */
|
||||
EF_ASSERT(ENV_USER_SETTING_SIZE % 4 == 0);
|
||||
EF_ASSERT(ENV_AREA_SIZE % 4 == 0);
|
||||
EF_ASSERT(default_env);
|
||||
EF_ASSERT(default_env_size < ENV_USER_SETTING_SIZE);
|
||||
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
/* total_size must be aligned with erase_min_size */
|
||||
if (ENV_USER_SETTING_SIZE % EF_ERASE_MIN_SIZE == 0) {
|
||||
EF_ASSERT(ENV_USER_SETTING_SIZE == ENV_AREA_SIZE);
|
||||
} else {
|
||||
EF_ASSERT((ENV_USER_SETTING_SIZE / EF_ERASE_MIN_SIZE + 1)*EF_ERASE_MIN_SIZE == ENV_AREA_SIZE);
|
||||
}
|
||||
#else
|
||||
/* total_size must be aligned with erase_min_size */
|
||||
if (ENV_USER_SETTING_SIZE % EF_ERASE_MIN_SIZE == 0) {
|
||||
/* it has double area when used power fail safeguard mode */
|
||||
EF_ASSERT(2 * ENV_USER_SETTING_SIZE == ENV_AREA_SIZE);
|
||||
} else {
|
||||
/* it has double area when used power fail safeguard mode */
|
||||
EF_ASSERT(2 * (ENV_USER_SETTING_SIZE / EF_ERASE_MIN_SIZE + 1)*EF_ERASE_MIN_SIZE == ENV_AREA_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
env_start_addr = EF_START_ADDR;
|
||||
default_env_set = default_env;
|
||||
default_env_set_size = default_env_size;
|
||||
|
||||
EF_DEBUG("ENV start address is 0x%08X, size is %d bytes.\n", EF_START_ADDR, ENV_AREA_SIZE);
|
||||
|
||||
result = ef_load_env();
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
if (result == EF_NO_ERR) {
|
||||
env_auto_update();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (result == EF_NO_ERR) {
|
||||
init_ok = true;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ENV set default.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_env_set_default(void) {
|
||||
extern EfErrCode ef_env_ver_num_set_default(void);
|
||||
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t i;
|
||||
|
||||
EF_ASSERT(default_env_set);
|
||||
EF_ASSERT(default_env_set_size);
|
||||
|
||||
/* lock the ENV cache */
|
||||
ef_port_env_lock();
|
||||
|
||||
/* set environment end address is at data section start address */
|
||||
set_env_end_addr(get_env_data_addr());
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* set saved count to default 0 */
|
||||
env_cache[ENV_PARAM_INDEX_SAVED_COUNT] = 0;
|
||||
#endif
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
/* initialize version number */
|
||||
env_cache[ENV_PARAM_INDEX_VER_NUM] = EF_ENV_VER_NUM;
|
||||
#endif
|
||||
|
||||
/* create default ENV */
|
||||
for (i = 0; i < default_env_set_size; i++) {
|
||||
create_env(default_env_set[i].key, default_env_set[i].value);
|
||||
}
|
||||
|
||||
/* unlock the ENV cache */
|
||||
ef_port_env_unlock();
|
||||
|
||||
result = ef_save_env();
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* reset other PFS area's data */
|
||||
if (result == EF_NO_ERR) {
|
||||
env_cache_changed = true;
|
||||
result = ef_save_env();
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ENV system section start address.
|
||||
*
|
||||
* @return system section start address
|
||||
*/
|
||||
static uint32_t get_env_system_addr(void) {
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
return env_start_addr;
|
||||
#else
|
||||
return cur_load_area_addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ENV data section start address.
|
||||
*
|
||||
* @return data section start address
|
||||
*/
|
||||
static uint32_t get_env_data_addr(void) {
|
||||
return get_env_system_addr() + ENV_PARAM_BYTE_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ENV end address.
|
||||
* It's the first word in ENV.
|
||||
*
|
||||
* @return ENV end address
|
||||
*/
|
||||
static uint32_t get_env_end_addr(void) {
|
||||
/* it is the first word */
|
||||
return env_cache[ENV_PARAM_INDEX_END_ADDR];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ENV end address.
|
||||
* It's the first word in ENV.
|
||||
*
|
||||
* @param end_addr ENV end address
|
||||
*/
|
||||
static void set_env_end_addr(uint32_t end_addr) {
|
||||
env_cache[ENV_PARAM_INDEX_END_ADDR] = end_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ENV data section size.
|
||||
*
|
||||
* @return size
|
||||
*/
|
||||
static size_t get_env_data_size(void) {
|
||||
if (get_env_end_addr() > get_env_data_addr()) {
|
||||
return get_env_end_addr() - get_env_data_addr();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user used ENV size.
|
||||
*
|
||||
* @return bytes
|
||||
*/
|
||||
static size_t get_env_user_used_size(void) {
|
||||
if (get_env_end_addr() > get_env_system_addr()) {
|
||||
return get_env_end_addr() - get_env_system_addr();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ENV already write bytes.
|
||||
*
|
||||
* @return write bytes
|
||||
*/
|
||||
size_t ef_get_env_write_bytes(void) {
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
return get_env_user_used_size();
|
||||
#else
|
||||
return get_env_user_used_size() * 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an ENV at the end of cache.
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode write_env(const char *key, const char *value) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t key_len = strlen(key), value_len = strlen(value), env_str_len;
|
||||
char *env_cache_bak = (char *)env_cache;
|
||||
|
||||
/* calculate ENV storage length, contain '=' and '\0'. */
|
||||
env_str_len = key_len + value_len + 2;
|
||||
if (env_str_len % 4 != 0) {
|
||||
env_str_len = (env_str_len / 4 + 1) * 4;
|
||||
}
|
||||
/* check capacity of ENV */
|
||||
if (env_str_len + get_env_user_used_size() >= ENV_USER_SETTING_SIZE) {
|
||||
return EF_ENV_FULL;
|
||||
}
|
||||
|
||||
/* calculate current ENV ram cache end address */
|
||||
env_cache_bak += get_env_user_used_size();
|
||||
|
||||
/* copy key name */
|
||||
memcpy(env_cache_bak, key, key_len);
|
||||
env_cache_bak += key_len;
|
||||
/* copy equal sign */
|
||||
*env_cache_bak = '=';
|
||||
env_cache_bak++;
|
||||
/* copy value */
|
||||
memcpy(env_cache_bak, value, value_len);
|
||||
env_cache_bak += value_len;
|
||||
/* fill '\0' for string end sign */
|
||||
*env_cache_bak = '\0';
|
||||
env_cache_bak ++;
|
||||
/* fill '\0' for word alignment */
|
||||
memset(env_cache_bak, 0, env_str_len - (key_len + value_len + 2));
|
||||
set_env_end_addr(get_env_end_addr() + env_str_len);
|
||||
/* ENV ram cache has changed */
|
||||
env_cache_changed = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find ENV.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return found ENV in ram cache
|
||||
*/
|
||||
static char *find_env(const char *key) {
|
||||
char *env_start, *env_end, *env, *found_env = NULL;
|
||||
size_t key_len = strlen(key), env_len;
|
||||
|
||||
if ((key == NULL) || *key == '\0') {
|
||||
EF_INFO("Flash ENV name must be not empty!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* from data section start to data section end */
|
||||
env_start = (char *) ((char *) env_cache + ENV_PARAM_BYTE_SIZE);
|
||||
env_end = (char *) ((char *) env_cache + get_env_user_used_size());
|
||||
|
||||
/* ENV is null */
|
||||
if (env_start == env_end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env = env_start;
|
||||
while (env < env_end) {
|
||||
/* the key length must be equal */
|
||||
if (!strncmp(env, key, key_len) && (env[key_len] == '=')) {
|
||||
found_env = env;
|
||||
break;
|
||||
} else {
|
||||
/* calculate ENV length, contain '\0'. */
|
||||
env_len = strlen(env) + 1;
|
||||
/* next ENV and word alignment */
|
||||
if (env_len % 4 == 0) {
|
||||
env += env_len;
|
||||
} else {
|
||||
env += (env_len / 4 + 1) * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found_env;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the ENV is not exist, create it.
|
||||
* @see flash_write_env
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode create_env(const char *key, const char *value) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
EF_ASSERT(key);
|
||||
EF_ASSERT(value);
|
||||
|
||||
if ((key == NULL) || *key == '\0') {
|
||||
EF_INFO("Flash ENV name must be not empty!\n");
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
|
||||
if (strchr(key, '=')) {
|
||||
EF_INFO("Flash ENV name can't contain '='.\n");
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
|
||||
/* find ENV */
|
||||
if (find_env(key)) {
|
||||
EF_INFO("The name of \"%s\" is already exist.\n", key);
|
||||
return EF_ENV_NAME_EXIST;
|
||||
}
|
||||
/* write ENV at the end of cache */
|
||||
result = write_env(key, value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an ENV in cache.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode del_env(const char *key) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
char *del_env = NULL;
|
||||
size_t del_env_length, remain_env_length;
|
||||
|
||||
EF_ASSERT(key);
|
||||
|
||||
if ((key == NULL) || *key == '\0') {
|
||||
EF_INFO("Flash ENV name must be not NULL!\n");
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
|
||||
if (strchr(key, '=')) {
|
||||
EF_INFO("Flash ENV name or value can't contain '='.\n");
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
|
||||
/* find ENV */
|
||||
del_env = find_env(key);
|
||||
|
||||
if (!del_env) {
|
||||
EF_INFO("Not find \"%s\" in ENV.\n", key);
|
||||
return EF_ENV_NAME_ERR;
|
||||
}
|
||||
del_env_length = strlen(del_env);
|
||||
/* '\0' also must be as ENV length */
|
||||
del_env_length ++;
|
||||
/* the address must multiple of 4 */
|
||||
if (del_env_length % 4 != 0) {
|
||||
del_env_length = (del_env_length / 4 + 1) * 4;
|
||||
}
|
||||
/* calculate remain ENV length */
|
||||
remain_env_length = get_env_data_size()
|
||||
- (((uint32_t) del_env + del_env_length) - ((uint32_t) env_cache + ENV_PARAM_BYTE_SIZE));
|
||||
/* remain ENV move forward */
|
||||
memcpy(del_env, del_env + del_env_length, remain_env_length);
|
||||
/* reset ENV end address */
|
||||
set_env_end_addr(get_env_end_addr() - del_env_length);
|
||||
/* ENV ram cache has changed */
|
||||
env_cache_changed = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an ENV.If it value is NULL, delete it.
|
||||
* If not find it in ENV table, then create it.
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_set_env(const char *key, const char *value) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
char *old_env, *old_value;
|
||||
|
||||
if (!init_ok) {
|
||||
EF_INFO("ENV isn't initialize OK.\n");
|
||||
return EF_ENV_INIT_FAILED;
|
||||
}
|
||||
|
||||
/* lock the ENV cache */
|
||||
ef_port_env_lock();
|
||||
|
||||
/* if ENV value is NULL, delete it */
|
||||
if (value == NULL) {
|
||||
result = del_env(key);
|
||||
} else {
|
||||
old_env = find_env(key);
|
||||
/* If find this ENV, then compare the new value and old value. */
|
||||
if (old_env) {
|
||||
/* find the old value address */
|
||||
old_env = strchr(old_env, '=');
|
||||
old_value = old_env + 1;
|
||||
/* If it is changed then delete it and recreate it */
|
||||
if (strcmp(old_value, value)) {
|
||||
result = del_env(key);
|
||||
if (result == EF_NO_ERR) {
|
||||
result = create_env(key, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = create_env(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock the ENV cache */
|
||||
ef_port_env_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Del an ENV.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_del_env(const char *key) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
if (!init_ok) {
|
||||
EF_INFO("ENV isn't initialize OK.\n");
|
||||
return EF_ENV_INIT_FAILED;
|
||||
}
|
||||
|
||||
/* lock the ENV cache */
|
||||
ef_port_env_lock();
|
||||
|
||||
result = del_env(key);
|
||||
|
||||
/* unlock the ENV cache */
|
||||
ef_port_env_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ENV value by key name.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return value
|
||||
*/
|
||||
char *ef_get_env(const char *key) {
|
||||
char *env = NULL, *value = NULL;
|
||||
|
||||
if (!init_ok) {
|
||||
EF_INFO("ENV isn't initialize OK.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find ENV */
|
||||
env = find_env(key);
|
||||
|
||||
if (env == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/* get value address */
|
||||
value = strchr(env, '=');
|
||||
if (value != NULL) {
|
||||
/* the equal sign next character is value */
|
||||
value++;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Print ENV.
|
||||
*/
|
||||
void ef_print_env(void) {
|
||||
uint32_t *env_cache_data_addr = env_cache + ENV_PARAM_WORD_SIZE,
|
||||
*env_cache_end_addr =
|
||||
(uint32_t *) (env_cache + ENV_PARAM_WORD_SIZE + get_env_data_size() / 4);
|
||||
uint8_t j;
|
||||
char c;
|
||||
|
||||
if (!init_ok) {
|
||||
EF_INFO("ENV isn't initialize OK.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (; env_cache_data_addr < env_cache_end_addr; env_cache_data_addr += 1) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
c = (*env_cache_data_addr) >> (8 * j);
|
||||
ef_print("%c", c);
|
||||
if (c == '\0') {
|
||||
ef_print("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
ef_print("\nmode: normal\n");
|
||||
ef_print("size: %ld/%ld bytes.\n", get_env_user_used_size(), ENV_USER_SETTING_SIZE);
|
||||
#else
|
||||
ef_print("\nmode: power fail safeguard\n");
|
||||
ef_print("size: %ld/%ld bytes, write bytes %ld/%ld.\n", get_env_user_used_size(),
|
||||
ENV_USER_SETTING_SIZE, ef_get_env_write_bytes(), ENV_AREA_SIZE);
|
||||
ef_print("saved count: %ld\n", env_cache[ENV_PARAM_INDEX_SAVED_COUNT]);
|
||||
#endif
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
ef_print("ver num: %d\n", env_cache[ENV_PARAM_INDEX_VER_NUM]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Load flash ENV to ram.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
EfErrCode ef_load_env(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
uint32_t *env_cache_bak, env_end_addr;
|
||||
|
||||
/* read ENV end address from flash */
|
||||
ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_END_ADDR * 4, &env_end_addr, 4);
|
||||
/* if ENV is not initialize or flash has dirty data, set default for it */
|
||||
if ((env_end_addr == 0xFFFFFFFF) || (env_end_addr < env_start_addr)
|
||||
|| (env_end_addr > env_start_addr + ENV_USER_SETTING_SIZE)) {
|
||||
result = ef_env_set_default();
|
||||
} else {
|
||||
/* set ENV end address */
|
||||
set_env_end_addr(env_end_addr);
|
||||
|
||||
env_cache_bak = env_cache + ENV_PARAM_WORD_SIZE;
|
||||
/* read all ENV from flash */
|
||||
ef_port_read(get_env_data_addr(), env_cache_bak, get_env_data_size());
|
||||
/* read ENV CRC code from flash */
|
||||
ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_DATA_CRC * 4,
|
||||
&env_cache[ENV_PARAM_INDEX_DATA_CRC] , 4);
|
||||
/* if ENV CRC32 check is fault, set default for it */
|
||||
if (!env_crc_is_ok()) {
|
||||
EF_INFO("Warning: ENV CRC check failed. Set it to default.\n");
|
||||
result = ef_env_set_default();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
EfErrCode ef_load_env(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
uint32_t area0_start_address = env_start_addr, area1_start_address = env_start_addr
|
||||
+ ENV_AREA_SIZE / 2;
|
||||
uint32_t area0_end_addr, area1_end_addr, area0_crc, area1_crc, area0_saved_count, area1_saved_count;
|
||||
bool area0_is_valid = true, area1_is_valid = true;
|
||||
/* read ENV area end address from flash */
|
||||
ef_port_read(area0_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area0_end_addr, 4);
|
||||
ef_port_read(area1_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area1_end_addr, 4);
|
||||
if ((area0_end_addr == 0xFFFFFFFF) || (area0_end_addr < area0_start_address)
|
||||
|| (area0_end_addr > area0_start_address + ENV_USER_SETTING_SIZE)) {
|
||||
area0_is_valid = false;
|
||||
}
|
||||
if ((area1_end_addr == 0xFFFFFFFF) || (area1_end_addr < area1_start_address)
|
||||
|| (area1_end_addr > area1_start_address + ENV_USER_SETTING_SIZE)) {
|
||||
area1_is_valid = false;
|
||||
}
|
||||
/* check area0 CRC when it is valid */
|
||||
if (area0_is_valid) {
|
||||
/* read ENV area0 crc32 code from flash */
|
||||
ef_port_read(area0_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area0_crc, 4);
|
||||
/* read ENV from ENV area0 */
|
||||
ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address);
|
||||
/* current load ENV area address is area0 start address */
|
||||
cur_load_area_addr = area0_start_address;
|
||||
if (!env_crc_is_ok()) {
|
||||
area0_is_valid = false;
|
||||
}
|
||||
}
|
||||
/* check area1 CRC when it is valid */
|
||||
if (area1_is_valid) {
|
||||
/* read ENV area1 crc32 code from flash */
|
||||
ef_port_read(area1_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area1_crc, 4);
|
||||
/* read ENV from ENV area1 */
|
||||
ef_port_read(area1_start_address, env_cache, area1_end_addr - area1_start_address);
|
||||
/* current load ENV area address is area1 start address */
|
||||
cur_load_area_addr = area1_start_address;
|
||||
if (!env_crc_is_ok()) {
|
||||
area1_is_valid = false;
|
||||
}
|
||||
}
|
||||
/* all ENV area CRC is OK then compare saved count */
|
||||
if (area0_is_valid && area1_is_valid) {
|
||||
/* read ENV area saved count from flash */
|
||||
ef_port_read(area0_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4,
|
||||
&area0_saved_count, 4);
|
||||
ef_port_read(area1_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4,
|
||||
&area1_saved_count, 4);
|
||||
/* the bigger saved count area is valid */
|
||||
if ((area0_saved_count > area1_saved_count) || ((area0_saved_count == 0) && (area1_saved_count == 0xFFFFFFFF))) {
|
||||
area1_is_valid = false;
|
||||
} else {
|
||||
area0_is_valid = false;
|
||||
}
|
||||
}
|
||||
if (area0_is_valid) {
|
||||
/* current load ENV area address is area0 start address */
|
||||
cur_load_area_addr = area0_start_address;
|
||||
/* next save ENV area address is area1 start address */
|
||||
next_save_area_addr = area1_start_address;
|
||||
/* read all ENV from area0 */
|
||||
ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address);
|
||||
} else if (area1_is_valid) {
|
||||
/* next save ENV area address is area0 start address */
|
||||
next_save_area_addr = area0_start_address;
|
||||
} else {
|
||||
/* current load ENV area address is area1 start address */
|
||||
cur_load_area_addr = area1_start_address;
|
||||
/* next save ENV area address is area0 start address */
|
||||
next_save_area_addr = area0_start_address;
|
||||
/* set the ENV to default */
|
||||
result = ef_env_set_default();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Save ENV to flash.
|
||||
*/
|
||||
EfErrCode ef_save_env(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
uint32_t write_addr, write_size;
|
||||
|
||||
/* ENV ram cache has not changed don't need to save */
|
||||
if (!env_cache_changed) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef EF_ENV_USING_PFS_MODE
|
||||
write_addr = get_env_system_addr();
|
||||
write_size = get_env_user_used_size();
|
||||
/* calculate and cache CRC32 code */
|
||||
env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc();
|
||||
#else
|
||||
write_addr = next_save_area_addr;
|
||||
write_size = get_env_user_used_size();
|
||||
/* replace next_save_area_addr with cur_load_area_addr */
|
||||
next_save_area_addr = cur_load_area_addr;
|
||||
cur_load_area_addr = write_addr;
|
||||
/* change the ENV end address to next save area address */
|
||||
set_env_end_addr(write_addr + write_size);
|
||||
/* ENV area saved count +1 */
|
||||
env_cache[ENV_PARAM_INDEX_SAVED_COUNT]++;
|
||||
/* calculate and cache CRC32 code */
|
||||
env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc();
|
||||
#endif
|
||||
|
||||
/* erase ENV */
|
||||
result = ef_port_erase(write_addr, write_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_DEBUG("Erased ENV OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_ERASE_ERR: {
|
||||
EF_INFO("Error: Erased ENV fault! Start address is 0x%08X, size is %ld.\n", write_addr, write_size);
|
||||
/* will return when erase fault */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* write ENV to flash */
|
||||
result = ef_port_write(write_addr, env_cache, write_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_DEBUG("Saved ENV OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_WRITE_ERR: {
|
||||
EF_INFO("Error: Saved ENV fault! Start address is 0x%08X, size is %ld.\n", write_addr, write_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
env_cache_changed = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the cached ENV CRC32 value.
|
||||
*
|
||||
* @return CRC32 value
|
||||
*/
|
||||
static uint32_t calc_env_crc(void) {
|
||||
uint32_t crc32 = 0;
|
||||
|
||||
/* Calculate the ENV end address CRC32. The 4 is ENV end address bytes size. */
|
||||
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_END_ADDR], 4);
|
||||
|
||||
#ifdef EF_ENV_USING_PFS_MODE
|
||||
/* Calculate the ENV area saved count CRC32. */
|
||||
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_SAVED_COUNT], 4);
|
||||
#endif
|
||||
|
||||
/* Calculate the all ENV data CRC32. */
|
||||
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_WORD_SIZE], get_env_data_size());
|
||||
|
||||
EF_DEBUG("Calculate ENV CRC32 number is 0x%08X.\n", crc32);
|
||||
|
||||
return crc32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the ENV CRC32
|
||||
*
|
||||
* @return true is ok
|
||||
*/
|
||||
static bool env_crc_is_ok(void) {
|
||||
if (calc_env_crc() == env_cache[ENV_PARAM_INDEX_DATA_CRC]) {
|
||||
EF_DEBUG("Verify ENV CRC32 result is OK.\n");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set and save an ENV. If set ENV is success then will save it.
|
||||
*
|
||||
* @param key ENV name
|
||||
* @param value ENV value
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_set_and_save_env(const char *key, const char *value) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = ef_set_env(key, value);
|
||||
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_save_env();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Del and save an ENV. If del ENV is success then will save it.
|
||||
*
|
||||
* @param key ENV name
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_del_and_save_env(const char *key) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = ef_del_env(key);
|
||||
|
||||
if (result == EF_NO_ERR) {
|
||||
result = ef_save_env();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef EF_ENV_AUTO_UPDATE
|
||||
/**
|
||||
* Auto update ENV to latest default when current EF_ENV_VER is changed.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode env_auto_update(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* lock the ENV cache */
|
||||
ef_port_env_lock();
|
||||
|
||||
/* read ENV version number from flash*/
|
||||
ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_VER_NUM * 4,
|
||||
&env_cache[ENV_PARAM_INDEX_VER_NUM] , 4);
|
||||
|
||||
/* check version number */
|
||||
if (env_cache[ENV_PARAM_INDEX_VER_NUM] != EF_ENV_VER_NUM) {
|
||||
env_cache_changed = true;
|
||||
/* update version number */
|
||||
env_cache[ENV_PARAM_INDEX_VER_NUM] = EF_ENV_VER_NUM;
|
||||
/* add a new ENV when it's not found */
|
||||
for (i = 0; i < default_env_set_size; i++) {
|
||||
if (find_env(default_env_set[i].key) == NULL) {
|
||||
create_env(default_env_set[i].key, default_env_set[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock the ENV cache */
|
||||
ef_port_env_unlock();
|
||||
|
||||
return ef_save_env();
|
||||
}
|
||||
#endif /* EF_ENV_AUTO_UPDATE */
|
||||
|
||||
#endif /* EF_ENV_USING_WL_MODE */
|
||||
|
||||
#endif /* defined(EF_USING_ENV) && defined(EF_ENV_USING_LEGACY_MODE) */
|
||||
1082
1.主程序源代码/User/easydb/src/ef_env_legacy_wl.c
Normal file
1082
1.主程序源代码/User/easydb/src/ef_env_legacy_wl.c
Normal file
File diff suppressed because it is too large
Load Diff
289
1.主程序源代码/User/easydb/src/ef_iap.c
Normal file
289
1.主程序源代码/User/easydb/src/ef_iap.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2017, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: IAP(In-Application Programming) operating interface.
|
||||
* Created on: 2015-01-05
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
|
||||
#ifdef EF_USING_IAP
|
||||
|
||||
/* IAP section backup application section start address in flash */
|
||||
static uint32_t bak_app_start_addr = 0;
|
||||
|
||||
/**
|
||||
* Flash IAP function initialize.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_iap_init(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
bak_app_start_addr = EF_START_ADDR ;
|
||||
|
||||
#if defined(EF_USING_ENV)
|
||||
bak_app_start_addr += ENV_AREA_SIZE;
|
||||
#endif
|
||||
|
||||
#if defined(EF_USING_LOG)
|
||||
bak_app_start_addr += LOG_AREA_SIZE;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase backup area application data.
|
||||
*
|
||||
* @param app_size application size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_erase_bak_app(size_t app_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = ef_port_erase(ef_get_bak_app_start_addr(), app_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Erased backup area application OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_ERASE_ERR: {
|
||||
EF_INFO("Warning: Erase backup area application fault!\n");
|
||||
/* will return when erase fault */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase user old application by using specified erase function.
|
||||
*
|
||||
* @param user_app_addr application entry address
|
||||
* @param app_size application size
|
||||
* @param app_erase user specified application erase function
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_erase_spec_user_app(uint32_t user_app_addr, size_t app_size,
|
||||
EfErrCode (*app_erase)(uint32_t addr, size_t size)) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = app_erase(user_app_addr, app_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Erased user application OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_ERASE_ERR: {
|
||||
EF_INFO("Warning: Erase user application fault!\n");
|
||||
/* will return when erase fault */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase user old application by using default `ef_port_erase` function.
|
||||
*
|
||||
* @param user_app_addr application entry address
|
||||
* @param app_size application size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_erase_user_app(uint32_t user_app_addr, size_t app_size) {
|
||||
return ef_erase_spec_user_app(user_app_addr, app_size, ef_port_erase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase old bootloader
|
||||
*
|
||||
* @param bl_addr bootloader entry address
|
||||
* @param bl_size bootloader size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_erase_bl(uint32_t bl_addr, size_t bl_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
result = ef_port_erase(bl_addr, bl_size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Erased bootloader OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_ERASE_ERR: {
|
||||
EF_INFO("Warning: Erase bootloader fault!\n");
|
||||
/* will return when erase fault */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data of application to backup area.
|
||||
*
|
||||
* @param data a part of application
|
||||
* @param size data size
|
||||
* @param cur_size current write application size
|
||||
* @param total_size application total size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_write_data_to_bak(uint8_t *data, size_t size, size_t *cur_size,
|
||||
size_t total_size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
/* make sure don't write excess data */
|
||||
if (*cur_size + size > total_size) {
|
||||
size = total_size - *cur_size;
|
||||
}
|
||||
|
||||
result = ef_port_write(ef_get_bak_app_start_addr() + *cur_size, (uint32_t *) data, size);
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
*cur_size += size;
|
||||
EF_DEBUG("Write data to backup area OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_WRITE_ERR: {
|
||||
EF_INFO("Warning: Write data to backup area fault!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy backup area application to application entry by using specified write function.
|
||||
*
|
||||
* @param user_app_addr application entry address
|
||||
* @param app_size application size
|
||||
* @param app_write user specified application write function
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_copy_spec_app_from_bak(uint32_t user_app_addr, size_t app_size,
|
||||
EfErrCode (*app_write)(uint32_t addr, const uint32_t *buf, size_t size)) {
|
||||
size_t cur_size;
|
||||
uint32_t app_cur_addr, bak_cur_addr;
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
/* 32 words size buffer */
|
||||
uint32_t buff[32];
|
||||
|
||||
/* cycle copy data */
|
||||
for (cur_size = 0; cur_size < app_size; cur_size += sizeof(buff)) {
|
||||
app_cur_addr = user_app_addr + cur_size;
|
||||
bak_cur_addr = ef_get_bak_app_start_addr() + cur_size;
|
||||
ef_port_read(bak_cur_addr, buff, sizeof(buff));
|
||||
result = app_write(app_cur_addr, buff, sizeof(buff));
|
||||
if (result != EF_NO_ERR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Write data to application entry OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_WRITE_ERR: {
|
||||
EF_INFO("Warning: Write data to application entry fault!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy backup area application to application entry by using default `ef_port_write` function.
|
||||
*
|
||||
* @param user_app_addr application entry address
|
||||
* @param app_size application size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_copy_app_from_bak(uint32_t user_app_addr, size_t app_size) {
|
||||
return ef_copy_spec_app_from_bak(user_app_addr, app_size, ef_port_write);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy backup area bootloader to bootloader entry.
|
||||
*
|
||||
* @param bl_addr bootloader entry address
|
||||
* @param bl_size bootloader size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_copy_bl_from_bak(uint32_t bl_addr, size_t bl_size) {
|
||||
size_t cur_size;
|
||||
uint32_t bl_cur_addr, bak_cur_addr;
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
/* 32 words buffer */
|
||||
uint32_t buff[32];
|
||||
|
||||
/* cycle copy data by 32bytes buffer */
|
||||
for (cur_size = 0; cur_size < bl_size; cur_size += sizeof(buff)) {
|
||||
bl_cur_addr = bl_addr + cur_size;
|
||||
bak_cur_addr = ef_get_bak_app_start_addr() + cur_size;
|
||||
ef_port_read(bak_cur_addr, buff, sizeof(buff));
|
||||
result = ef_port_write(bl_cur_addr, buff, sizeof(buff));
|
||||
if (result != EF_NO_ERR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case EF_NO_ERR: {
|
||||
EF_INFO("Write data to bootloader entry OK.\n");
|
||||
break;
|
||||
}
|
||||
case EF_WRITE_ERR: {
|
||||
EF_INFO("Warning: Write data to bootloader entry fault!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IAP section start address in flash.
|
||||
*
|
||||
* @return size
|
||||
*/
|
||||
uint32_t ef_get_bak_app_start_addr(void) {
|
||||
return bak_app_start_addr;
|
||||
}
|
||||
|
||||
#endif /* EF_USING_IAP */
|
||||
731
1.主程序源代码/User/easydb/src/ef_log.c
Normal file
731
1.主程序源代码/User/easydb/src/ef_log.c
Normal file
@@ -0,0 +1,731 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2019, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Save logs to flash.
|
||||
* Created on: 2015-06-04
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
|
||||
#ifdef EF_USING_LOG
|
||||
|
||||
#if defined(EF_USING_LOG) && !defined(LOG_AREA_SIZE)
|
||||
#error "Please configure log area size (in ef_cfg.h)"
|
||||
#endif
|
||||
|
||||
/* magic code on every sector header. 'EF' is 0xEF30EF30 */
|
||||
#define LOG_SECTOR_MAGIC 0xEF30EF30
|
||||
/* sector header size, includes the sector magic code and status magic code */
|
||||
#define LOG_SECTOR_HEADER_SIZE 12
|
||||
/* sector header word size,what is equivalent to the total number of sectors header index */
|
||||
#define LOG_SECTOR_HEADER_WORD_SIZE 3
|
||||
|
||||
/**
|
||||
* Sector status magic code
|
||||
* The sector status is 8B after LOG_SECTOR_MAGIC at every sector header.
|
||||
* ==============================================
|
||||
* | header(12B) | status |
|
||||
* ----------------------------------------------
|
||||
* | 0xEF30EF30 0xFFFFFFFF 0xFFFFFFFF | empty |
|
||||
* | 0xEF30EF30 0xFEFEFEFE 0xFFFFFFFF | using |
|
||||
* | 0xEF30EF30 0xFEFEFEFE 0xFCFCFCFC | full |
|
||||
* ==============================================
|
||||
*
|
||||
* State transition relationship: empty->using->full
|
||||
* The FULL status will change to EMPTY after sector clean.
|
||||
*/
|
||||
#define SECTOR_STATUS_MAGIC_EMPUT 0xFFFFFFFF
|
||||
#define SECTOR_STATUS_MAGIC_USING 0xFEFEFEFE
|
||||
#define SECTOR_STATUS_MAGIC_FULL 0xFCFCFCFC
|
||||
|
||||
typedef enum {
|
||||
SECTOR_STATUS_EMPUT,
|
||||
SECTOR_STATUS_USING,
|
||||
SECTOR_STATUS_FULL,
|
||||
SECTOR_STATUS_HEADER_ERROR,
|
||||
} SectorStatus;
|
||||
|
||||
typedef enum {
|
||||
SECTOR_HEADER_MAGIC_INDEX,
|
||||
SECTOR_HEADER_USING_INDEX,
|
||||
SECTOR_HEADER_FULL_INDEX,
|
||||
} SectorHeaderIndex;
|
||||
|
||||
/* the stored logs start address and end address. It's like a ring buffer implemented on flash. */
|
||||
static uint32_t log_start_addr = 0, log_end_addr = 0;
|
||||
/* saved log area address for flash */
|
||||
static uint32_t log_area_start_addr = 0;
|
||||
/* initialize OK flag */
|
||||
static bool init_ok = false;
|
||||
|
||||
static void find_start_and_end_addr(void);
|
||||
static uint32_t get_next_flash_sec_addr(uint32_t cur_addr);
|
||||
|
||||
/**
|
||||
* The flash save log function initialize.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_log_init(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
|
||||
EF_ASSERT(LOG_AREA_SIZE);
|
||||
EF_ASSERT(EF_ERASE_MIN_SIZE);
|
||||
/* the log area size must be an integral multiple of erase minimum size. */
|
||||
EF_ASSERT(LOG_AREA_SIZE % EF_ERASE_MIN_SIZE == 0);
|
||||
/* the log area size must be more than twice of EF_ERASE_MIN_SIZE */
|
||||
EF_ASSERT(LOG_AREA_SIZE / EF_ERASE_MIN_SIZE >= 2);
|
||||
|
||||
#ifdef EF_USING_ENV
|
||||
log_area_start_addr = EF_START_ADDR + ENV_AREA_SIZE;
|
||||
#else
|
||||
log_area_start_addr = EF_START_ADDR;
|
||||
#endif
|
||||
|
||||
/* find the log store start address and end address */
|
||||
find_start_and_end_addr();
|
||||
/* initialize OK */
|
||||
init_ok = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get flash sector current status.
|
||||
*
|
||||
* @param addr sector address, this function will auto calculate the sector header address by this address.
|
||||
*
|
||||
* @return the flash sector current status
|
||||
*/
|
||||
static SectorStatus get_sector_status(uint32_t addr) {
|
||||
uint32_t header_buf[LOG_SECTOR_HEADER_WORD_SIZE] = {0}, header_addr = 0;
|
||||
uint32_t sector_header_magic = 0;
|
||||
uint32_t status_full_magic = 0, status_use_magic = 0;
|
||||
|
||||
/* calculate the sector header address */
|
||||
header_addr = addr & (~(EF_ERASE_MIN_SIZE - 1));
|
||||
|
||||
if (ef_port_read(header_addr, header_buf, sizeof(header_buf)) == EF_NO_ERR) {
|
||||
sector_header_magic = header_buf[SECTOR_HEADER_MAGIC_INDEX];
|
||||
status_use_magic = header_buf[SECTOR_HEADER_USING_INDEX];
|
||||
status_full_magic = header_buf[SECTOR_HEADER_FULL_INDEX];
|
||||
} else {
|
||||
EF_DEBUG("Error: Read sector header data error.\n");
|
||||
return SECTOR_STATUS_HEADER_ERROR;
|
||||
}
|
||||
|
||||
/* compare header magic code */
|
||||
if(sector_header_magic == LOG_SECTOR_MAGIC){
|
||||
if((status_use_magic == SECTOR_STATUS_MAGIC_EMPUT) && (status_full_magic == SECTOR_STATUS_MAGIC_EMPUT)) {
|
||||
return SECTOR_STATUS_EMPUT;
|
||||
} else if((status_use_magic == SECTOR_STATUS_MAGIC_USING) && (status_full_magic == SECTOR_STATUS_MAGIC_EMPUT)) {
|
||||
return SECTOR_STATUS_USING;
|
||||
} else if((status_use_magic == SECTOR_STATUS_MAGIC_USING) && (status_full_magic == SECTOR_STATUS_MAGIC_FULL)) {
|
||||
return SECTOR_STATUS_FULL;
|
||||
} else {
|
||||
return SECTOR_STATUS_HEADER_ERROR;
|
||||
}
|
||||
} else {
|
||||
return SECTOR_STATUS_HEADER_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write flash sector current status.
|
||||
*
|
||||
* @param addr sector address, this function will auto calculate the sector header address by this address.
|
||||
* @param status sector cur status
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode write_sector_status(uint32_t addr, SectorStatus status) {
|
||||
uint32_t header, header_addr = 0;
|
||||
|
||||
/* calculate the sector header address */
|
||||
header_addr = addr & (~(EF_ERASE_MIN_SIZE - 1));
|
||||
|
||||
/* calculate the sector staus magic */
|
||||
switch (status) {
|
||||
case SECTOR_STATUS_EMPUT: {
|
||||
header = LOG_SECTOR_MAGIC;
|
||||
return ef_port_write(header_addr, &header, sizeof(header));
|
||||
}
|
||||
case SECTOR_STATUS_USING: {
|
||||
header = SECTOR_STATUS_MAGIC_USING;
|
||||
return ef_port_write(header_addr + sizeof(header), &header, sizeof(header));
|
||||
}
|
||||
case SECTOR_STATUS_FULL: {
|
||||
header = SECTOR_STATUS_MAGIC_FULL;
|
||||
return ef_port_write(header_addr + sizeof(header) * 2, &header, sizeof(header));
|
||||
}
|
||||
default:
|
||||
return EF_WRITE_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the current flash sector using end address by continuous 0xFF.
|
||||
*
|
||||
* @param addr sector address
|
||||
*
|
||||
* @return current flash sector using end address
|
||||
*/
|
||||
static uint32_t find_sec_using_end_addr(uint32_t addr) {
|
||||
/* read section data buffer size */
|
||||
#define READ_BUF_SIZE 32
|
||||
|
||||
uint32_t sector_start = addr, data_start = addr, continue_ff = 0, read_buf_size = 0, i;
|
||||
uint8_t buf[READ_BUF_SIZE];
|
||||
|
||||
EF_ASSERT(READ_BUF_SIZE % 4 == 0);
|
||||
/* calculate the sector start and data start address */
|
||||
sector_start = addr & (~(EF_ERASE_MIN_SIZE - 1));
|
||||
data_start = sector_start + LOG_SECTOR_HEADER_SIZE;
|
||||
|
||||
/* counts continuous 0xFF which is end of sector */
|
||||
while (data_start < sector_start + EF_ERASE_MIN_SIZE) {
|
||||
if (data_start + READ_BUF_SIZE < sector_start + EF_ERASE_MIN_SIZE) {
|
||||
read_buf_size = READ_BUF_SIZE;
|
||||
} else {
|
||||
read_buf_size = sector_start + EF_ERASE_MIN_SIZE - data_start;
|
||||
}
|
||||
ef_port_read(data_start, (uint32_t *)buf, read_buf_size);
|
||||
for (i = 0; i < read_buf_size; i++) {
|
||||
if (buf[i] == 0xFF) {
|
||||
continue_ff++;
|
||||
} else {
|
||||
continue_ff = 0;
|
||||
}
|
||||
}
|
||||
data_start += read_buf_size;
|
||||
}
|
||||
/* calculate current flash sector using end address */
|
||||
if (continue_ff >= EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) {
|
||||
/* from 0 to sec_size all sector is 0xFF, so the sector is empty */
|
||||
return sector_start + LOG_SECTOR_HEADER_SIZE;
|
||||
} else if (continue_ff >= 4) {
|
||||
/* form end_addr - 4 to sec_size length all area is 0xFF, so it's used part of the sector.
|
||||
* the address must be word alignment. */
|
||||
if (continue_ff % 4 != 0) {
|
||||
continue_ff = (continue_ff / 4 + 1) * 4;
|
||||
}
|
||||
return sector_start + EF_ERASE_MIN_SIZE - continue_ff;
|
||||
} else {
|
||||
/* all sector not has continuous 0xFF, so the sector is full */
|
||||
return sector_start + EF_ERASE_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the log store start address and end address.
|
||||
* It's like a ring buffer implemented on flash.
|
||||
* The flash log area can be in two states depending on start address and end address:
|
||||
* state 1 state 2
|
||||
* |============| |============|
|
||||
* log area start--> |############| <-- start address |############| <-- end address
|
||||
* |############| | empty |
|
||||
* |------------| |------------|
|
||||
* |############| |############| <-- start address
|
||||
* |############| |############|
|
||||
* |------------| |------------|
|
||||
* | . | | . |
|
||||
* | . | | . |
|
||||
* | . | | . |
|
||||
* |------------| |------------|
|
||||
* |############| <-- end address |############|
|
||||
* | empty | |############|
|
||||
* log area end --> |============| |============|
|
||||
*
|
||||
* LOG_AREA_SIZE = log area end - log area star
|
||||
*
|
||||
*/
|
||||
static void find_start_and_end_addr(void) {
|
||||
size_t cur_size = 0;
|
||||
SectorStatus cur_sec_status, last_sec_status;
|
||||
uint32_t cur_using_sec_addr = 0;
|
||||
/* all status sector counts */
|
||||
size_t empty_sec_counts = 0, using_sec_counts = 0, full_sector_counts = 0;
|
||||
/* total sector number */
|
||||
size_t total_sec_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
|
||||
/* see comment of find_start_and_end_addr function */
|
||||
uint8_t cur_log_sec_state = 0;
|
||||
|
||||
/* get the first sector status */
|
||||
cur_sec_status = get_sector_status(log_area_start_addr);
|
||||
last_sec_status = cur_sec_status;
|
||||
|
||||
for (cur_size = EF_ERASE_MIN_SIZE; cur_size < LOG_AREA_SIZE; cur_size += EF_ERASE_MIN_SIZE) {
|
||||
/* get current sector status */
|
||||
cur_sec_status = get_sector_status(log_area_start_addr + cur_size);
|
||||
/* compare last and current status */
|
||||
switch (last_sec_status) {
|
||||
case SECTOR_STATUS_EMPUT: {
|
||||
switch (cur_sec_status) {
|
||||
case SECTOR_STATUS_EMPUT:
|
||||
break;
|
||||
case SECTOR_STATUS_USING:
|
||||
EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
case SECTOR_STATUS_FULL:
|
||||
EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
}
|
||||
empty_sec_counts++;
|
||||
break;
|
||||
}
|
||||
case SECTOR_STATUS_USING: {
|
||||
switch (cur_sec_status) {
|
||||
case SECTOR_STATUS_EMPUT:
|
||||
/* like state 1 */
|
||||
cur_log_sec_state = 1;
|
||||
log_start_addr = log_area_start_addr;
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
|
||||
break;
|
||||
case SECTOR_STATUS_USING:
|
||||
EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
case SECTOR_STATUS_FULL:
|
||||
/* like state 2 */
|
||||
cur_log_sec_state = 2;
|
||||
log_start_addr = log_area_start_addr + cur_size;
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
|
||||
break;
|
||||
}
|
||||
using_sec_counts++;
|
||||
break;
|
||||
}
|
||||
case SECTOR_STATUS_FULL: {
|
||||
switch (cur_sec_status) {
|
||||
case SECTOR_STATUS_EMPUT:
|
||||
/* like state 1 */
|
||||
if (cur_log_sec_state == 2) {
|
||||
EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
} else {
|
||||
cur_log_sec_state = 1;
|
||||
log_start_addr = log_area_start_addr;
|
||||
log_end_addr = log_area_start_addr + cur_size;
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
|
||||
}
|
||||
break;
|
||||
case SECTOR_STATUS_USING:
|
||||
if(total_sec_num <= 2) {
|
||||
/* like state 1 */
|
||||
cur_log_sec_state = 1;
|
||||
log_start_addr = log_area_start_addr;
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size;
|
||||
} else {
|
||||
/* like state 2 when the sector is the last one */
|
||||
if (cur_size + EF_ERASE_MIN_SIZE >= LOG_AREA_SIZE) {
|
||||
cur_log_sec_state = 2;
|
||||
log_start_addr = get_next_flash_sec_addr(log_area_start_addr + cur_size);
|
||||
cur_using_sec_addr = log_area_start_addr + cur_size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SECTOR_STATUS_FULL:
|
||||
break;
|
||||
}
|
||||
full_sector_counts++;
|
||||
break;
|
||||
}
|
||||
case SECTOR_STATUS_HEADER_ERROR:
|
||||
EF_DEBUG("Error: Log sector header error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
}
|
||||
last_sec_status = cur_sec_status;
|
||||
}
|
||||
|
||||
/* the last sector status counts */
|
||||
if (cur_sec_status == SECTOR_STATUS_EMPUT) {
|
||||
empty_sec_counts++;
|
||||
} else if (cur_sec_status == SECTOR_STATUS_USING) {
|
||||
using_sec_counts++;
|
||||
} else if (cur_sec_status == SECTOR_STATUS_FULL) {
|
||||
full_sector_counts++;
|
||||
} else if (cur_sec_status == SECTOR_STATUS_HEADER_ERROR) {
|
||||
EF_DEBUG("Error: Log sector header error! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
return;
|
||||
}
|
||||
|
||||
if (using_sec_counts != 1) {
|
||||
/* this state is almost impossible */
|
||||
EF_DEBUG("Error: There must be only one sector status is USING! Now will clean all log area.\n");
|
||||
ef_log_clean();
|
||||
} else {
|
||||
/* find the end address */
|
||||
log_end_addr = find_sec_using_end_addr(cur_using_sec_addr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get log used flash total size.
|
||||
*
|
||||
* @return log used flash total size. @note NOT contain sector headers
|
||||
*/
|
||||
size_t ef_log_get_used_size(void) {
|
||||
size_t header_total_num = 0, physical_size = 0;
|
||||
/* must be call this function after initialize OK */
|
||||
if (!init_ok) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (log_start_addr < log_end_addr) {
|
||||
physical_size = log_end_addr - log_start_addr;
|
||||
} else {
|
||||
physical_size = LOG_AREA_SIZE - (log_start_addr - log_end_addr);
|
||||
}
|
||||
|
||||
header_total_num = physical_size / EF_ERASE_MIN_SIZE + 1;
|
||||
|
||||
return physical_size - header_total_num * LOG_SECTOR_HEADER_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sequential reading log data. It will ignore sector headers.
|
||||
*
|
||||
* @param addr address
|
||||
* @param log log buffer
|
||||
* @param size log size, not contain sector headers.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
static EfErrCode log_seq_read(uint32_t addr, uint32_t *log, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t read_size = 0, read_size_temp = 0;
|
||||
|
||||
while (size) {
|
||||
/* move to sector data address */
|
||||
if ((addr + read_size) % EF_ERASE_MIN_SIZE == 0) {
|
||||
addr += LOG_SECTOR_HEADER_SIZE;
|
||||
}
|
||||
/* calculate current sector last data size */
|
||||
read_size_temp = EF_ERASE_MIN_SIZE - (addr % EF_ERASE_MIN_SIZE);
|
||||
if (size < read_size_temp) {
|
||||
read_size_temp = size;
|
||||
}
|
||||
result = ef_port_read(addr + read_size, log + read_size / 4, read_size_temp);
|
||||
if (result != EF_NO_ERR) {
|
||||
return result;
|
||||
}
|
||||
read_size += read_size_temp;
|
||||
size -= read_size_temp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate flash physical address by log index.
|
||||
*
|
||||
* @param index log index
|
||||
*
|
||||
* @return flash physical address
|
||||
*/
|
||||
static uint32_t log_index2addr(size_t index) {
|
||||
size_t header_total_offset = 0;
|
||||
/* total include sector number */
|
||||
size_t sector_num = index / (EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) + 1;
|
||||
|
||||
header_total_offset = sector_num * LOG_SECTOR_HEADER_SIZE;
|
||||
if (log_start_addr < log_end_addr) {
|
||||
return log_start_addr + index + header_total_offset;
|
||||
} else {
|
||||
if (log_start_addr + index + header_total_offset < log_area_start_addr + LOG_AREA_SIZE) {
|
||||
return log_start_addr + index + header_total_offset;
|
||||
} else {
|
||||
return log_start_addr + index + header_total_offset - LOG_AREA_SIZE;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read log from flash.
|
||||
*
|
||||
* @param index index for saved log.
|
||||
* Minimum index is 0.
|
||||
* Maximum index is ef_log_get_used_size() - 1.
|
||||
* @param log the log which will read from flash
|
||||
* @param size read bytes size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t cur_using_size = ef_log_get_used_size();
|
||||
size_t read_size_temp = 0;
|
||||
size_t header_total_num = 0;
|
||||
|
||||
if (!size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
EF_ASSERT(size % 4 == 0);
|
||||
EF_ASSERT(index < cur_using_size);
|
||||
|
||||
if (index + size > cur_using_size) {
|
||||
EF_DEBUG("Warning: Log read size out of bound. Cut read size.\n");
|
||||
size = cur_using_size - index;
|
||||
}
|
||||
/* must be call this function after initialize OK */
|
||||
if (!init_ok) {
|
||||
return EF_ENV_INIT_FAILED;
|
||||
}
|
||||
|
||||
if (log_start_addr < log_end_addr) {
|
||||
log_seq_read(log_index2addr(index), log, size);
|
||||
} else {
|
||||
if (log_index2addr(index) + size <= log_area_start_addr + LOG_AREA_SIZE) {
|
||||
/* Flash log area
|
||||
* |--------------|
|
||||
* log_area_start_addr --> |##############|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |--------------|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |##############| <-- log_end_addr
|
||||
* |--------------|
|
||||
* log_start_addr --> |##############|
|
||||
* read start --> |**************| <-- read end
|
||||
* |##############|
|
||||
* |--------------|
|
||||
*
|
||||
* read from (log_start_addr + log_index2addr(index)) to (log_start_addr + index + log_index2addr(index))
|
||||
*/
|
||||
result = log_seq_read(log_index2addr(index), log, size);
|
||||
} else if (log_index2addr(index) < log_area_start_addr + LOG_AREA_SIZE) {
|
||||
/* Flash log area
|
||||
* |--------------|
|
||||
* log_area_start_addr --> |**************| <-- read end
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |--------------|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |##############| <-- log_end_addr
|
||||
* |--------------|
|
||||
* log_start_addr --> |##############|
|
||||
* read start --> |**************|
|
||||
* |**************|
|
||||
* |--------------|
|
||||
* read will by 2 steps
|
||||
* step1: read from (log_start_addr + log_index2addr(index)) to flash log area end address
|
||||
* step2: read from flash log area start address to read size's end address
|
||||
*/
|
||||
read_size_temp = (log_area_start_addr + LOG_AREA_SIZE) - log_index2addr(index);
|
||||
header_total_num = read_size_temp / EF_ERASE_MIN_SIZE;
|
||||
/* Minus some ignored bytes */
|
||||
read_size_temp -= header_total_num * LOG_SECTOR_HEADER_SIZE;
|
||||
result = log_seq_read(log_index2addr(index), log, read_size_temp);
|
||||
if (result == EF_NO_ERR) {
|
||||
result = log_seq_read(log_area_start_addr, log + read_size_temp / 4, size - read_size_temp);
|
||||
}
|
||||
} else {
|
||||
/* Flash log area
|
||||
* |--------------|
|
||||
* log_area_start_addr --> |##############|
|
||||
* read start --> |**************|
|
||||
* |**************| <-- read end
|
||||
* |--------------|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |##############| <-- log_end_addr
|
||||
* |--------------|
|
||||
* log_start_addr --> |##############|
|
||||
* |##############|
|
||||
* |##############|
|
||||
* |--------------|
|
||||
* read from (log_start_addr + log_index2addr(index) - LOG_AREA_SIZE) to read size's end address
|
||||
*/
|
||||
result = log_seq_read(log_index2addr(index) - LOG_AREA_SIZE, log, size);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write log to flash.
|
||||
*
|
||||
* @param log the log which will be write to flash
|
||||
* @param size write bytes size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_log_write(const uint32_t *log, size_t size) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
size_t write_size = 0, writable_size = 0;
|
||||
uint32_t write_addr = log_end_addr, erase_addr;
|
||||
SectorStatus sector_status;
|
||||
|
||||
EF_ASSERT(size % 4 == 0);
|
||||
/* must be call this function after initialize OK */
|
||||
if (!init_ok) {
|
||||
return EF_ENV_INIT_FAILED;
|
||||
}
|
||||
|
||||
if ((sector_status = get_sector_status(write_addr)) == SECTOR_STATUS_HEADER_ERROR) {
|
||||
return EF_WRITE_ERR;
|
||||
}
|
||||
/* write some log when current sector status is USING and EMPTY */
|
||||
if ((sector_status == SECTOR_STATUS_USING) || (sector_status == SECTOR_STATUS_EMPUT)) {
|
||||
/* write the already erased but not used area */
|
||||
writable_size = EF_ERASE_MIN_SIZE - ((write_addr - log_area_start_addr) % EF_ERASE_MIN_SIZE);
|
||||
if (size >= writable_size) {
|
||||
result = ef_port_write(write_addr, log, writable_size);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
/* change the current sector status to FULL */
|
||||
result = write_sector_status(write_addr, SECTOR_STATUS_FULL);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
write_size += writable_size;
|
||||
} else {
|
||||
result = ef_port_write(write_addr, log, size);
|
||||
log_end_addr = write_addr + size;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
/* erase and write remain log */
|
||||
while (true) {
|
||||
/* calculate next available sector address */
|
||||
erase_addr = write_addr = get_next_flash_sec_addr(write_addr - 4);
|
||||
/* move the flash log start address to next available sector address */
|
||||
if (log_start_addr == erase_addr) {
|
||||
log_start_addr = get_next_flash_sec_addr(log_start_addr);
|
||||
}
|
||||
/* erase sector */
|
||||
result = ef_port_erase(erase_addr, EF_ERASE_MIN_SIZE);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
/* change the sector status to EMPTY and USING when write begin sector start address */
|
||||
result = write_sector_status(write_addr, SECTOR_STATUS_EMPUT);
|
||||
result = write_sector_status(write_addr, SECTOR_STATUS_USING);
|
||||
if (result == EF_NO_ERR) {
|
||||
write_addr += LOG_SECTOR_HEADER_SIZE;
|
||||
} else {
|
||||
goto exit;
|
||||
}
|
||||
/* calculate current sector writable data size */
|
||||
writable_size = EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE;
|
||||
if (size - write_size >= writable_size) {
|
||||
result = ef_port_write(write_addr, log + write_size / 4, writable_size);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
/* change the current sector status to FULL */
|
||||
result = write_sector_status(write_addr, SECTOR_STATUS_FULL);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
log_end_addr = write_addr + writable_size;
|
||||
write_size += writable_size;
|
||||
write_addr += writable_size;
|
||||
} else {
|
||||
result = ef_port_write(write_addr, log + write_size / 4, size - write_size);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
log_end_addr = write_addr + (size - write_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next flash sector address.The log total sector like ring buffer which implement by flash.
|
||||
*
|
||||
* @param cur_addr cur flash address
|
||||
*
|
||||
* @return next flash sector address
|
||||
*/
|
||||
static uint32_t get_next_flash_sec_addr(uint32_t cur_addr) {
|
||||
size_t cur_sec_id = (cur_addr - log_area_start_addr) / EF_ERASE_MIN_SIZE;
|
||||
size_t sec_total_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
|
||||
|
||||
if (cur_sec_id + 1 >= sec_total_num) {
|
||||
/* return to ring head */
|
||||
return log_area_start_addr;
|
||||
} else {
|
||||
return log_area_start_addr + (cur_sec_id + 1) * EF_ERASE_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean all log which in flash.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
EfErrCode ef_log_clean(void) {
|
||||
EfErrCode result = EF_NO_ERR;
|
||||
uint32_t write_addr = log_area_start_addr;
|
||||
|
||||
/* clean address */
|
||||
log_start_addr = log_area_start_addr;
|
||||
log_end_addr = log_start_addr + LOG_SECTOR_HEADER_SIZE;
|
||||
/* erase log flash area */
|
||||
result = ef_port_erase(log_area_start_addr, LOG_AREA_SIZE);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
/* setting first sector is EMPTY to USING */
|
||||
write_sector_status(write_addr, SECTOR_STATUS_EMPUT);
|
||||
write_sector_status(write_addr, SECTOR_STATUS_USING);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
write_addr += EF_ERASE_MIN_SIZE;
|
||||
/* add sector header */
|
||||
while (true) {
|
||||
write_sector_status(write_addr, SECTOR_STATUS_EMPUT);
|
||||
if (result != EF_NO_ERR) {
|
||||
goto exit;
|
||||
}
|
||||
write_addr += EF_ERASE_MIN_SIZE;
|
||||
if (write_addr >= log_area_start_addr + LOG_AREA_SIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* EF_USING_LOG */
|
||||
99
1.主程序源代码/User/easydb/src/ef_utils.c
Normal file
99
1.主程序源代码/User/easydb/src/ef_utils.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is part of the EasyFlash Library.
|
||||
*
|
||||
* Copyright (c) 2015-2017, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* 'Software'), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Function: Some utils for this library.
|
||||
* Created on: 2015-01-14
|
||||
*/
|
||||
|
||||
#include <easyflash.h>
|
||||
|
||||
static const uint32_t crc32_table[] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the CRC32 value of a memory buffer.
|
||||
*
|
||||
* @param crc accumulated CRC32 value, must be 0 on first call
|
||||
* @param buf buffer to calculate CRC32 value for
|
||||
* @param size bytes in buffer
|
||||
*
|
||||
* @return calculated CRC32 value
|
||||
*/
|
||||
uint32_t ef_calc_crc32(uint32_t crc, const void *buf, size_t size)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
p = (const uint8_t *)buf;
|
||||
crc = crc ^ ~0U;
|
||||
|
||||
while (size--) {
|
||||
crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ ~0U;
|
||||
}
|
||||
39
1.主程序源代码/User/inc/bsp_bat.h
Normal file
39
1.主程序源代码/User/inc/bsp_bat.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* @Date: 2025-06-26 09:38:45
|
||||
* @LastEditors: 路怀帅
|
||||
* @LastEditTime: 2025-07-05 11:31:57
|
||||
* @FilePath: \RVMDK(uv5)e:\个人项目\零距电子\安灯遥控器\Andon_Remote_Control\Andon_RTOS\User\inc\bsp_bat.h
|
||||
*/
|
||||
#ifndef __BAT_H
|
||||
#define __BAT_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*Init)(void);
|
||||
uint8_t (*Read_State)(void);
|
||||
} BATClassStruct;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BAT_Charging = 0, // 电池充电中
|
||||
BAT_Full, // 电池充满
|
||||
BAT_Low, // 电池低电量
|
||||
BAT_Hight // 电池高电量
|
||||
|
||||
} BAT_State_Enum;
|
||||
|
||||
extern BATClassStruct BATClass;
|
||||
void Power_button_init(void);
|
||||
uint8_t Check_Power_buttun(void);
|
||||
|
||||
|
||||
typedef struct {
|
||||
void (* Init)(void);
|
||||
uint16_t (* GetValue)(uint8_t ADC_channelx);
|
||||
} ADC1ClassStruct;
|
||||
|
||||
extern ADC1ClassStruct ADC1Class;
|
||||
|
||||
#endif
|
||||
18
1.主程序源代码/User/inc/bsp_button.h
Normal file
18
1.主程序源代码/User/inc/bsp_button.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef __BUTTON_H__
|
||||
#define __BUTTON_H__
|
||||
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
void user_button_init(void);
|
||||
extern uint8_t isLEDTog;
|
||||
extern uint8_t isSend;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __FLEXIBLE_BUTTON_H__ */
|
||||
10
1.主程序源代码/User/inc/bsp_chipid.h
Normal file
10
1.主程序源代码/User/inc/bsp_chipid.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef __CHIPID_H
|
||||
#define __CHIPID_H
|
||||
|
||||
|
||||
#include "stm32f10x.h"
|
||||
|
||||
void Get_ChipID(void);
|
||||
void WDOG_Init(void);
|
||||
|
||||
#endif /* __CHIPID_H */
|
||||
69
1.主程序源代码/User/inc/bsp_led.h
Normal file
69
1.主程序源代码/User/inc/bsp_led.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* @Date: 2025-06-26 09:38:45
|
||||
* @LastEditors: 路怀帅
|
||||
* @LastEditTime: 2025-06-26 14:37:29
|
||||
* @FilePath: \Andon_Remote_Control\MDK_PROJECT\Drive\Led.h
|
||||
*/
|
||||
#ifndef __LED_H
|
||||
#define __LED_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*Init)(void);
|
||||
void (*Set)(volatile uint8_t led_x);
|
||||
void (*GREEN_Toggle)(void);
|
||||
void (*RED_Toggle)(void);
|
||||
void (*BLUE_Toggle)(void);
|
||||
void (*YELLOW_Toggle)(void);
|
||||
|
||||
} LEDClassStruct;
|
||||
|
||||
#define RED_ON GPIO_ResetBits(GPIOA, GPIO_Pin_6)
|
||||
#define RED_OFF GPIO_SetBits(GPIOA, GPIO_Pin_6)
|
||||
#define RED_TOG GPIOA->BSRR = ((GPIOA->ODR & GPIO_Pin_6) << 16) | (~GPIOA->ODR & GPIO_Pin_6)
|
||||
#define GREEN_ON GPIO_ResetBits(GPIOA, GPIO_Pin_7)
|
||||
#define GREEN_OFF GPIO_SetBits(GPIOA, GPIO_Pin_7)
|
||||
#define GREEN_TOG GPIOA->BSRR = ((GPIOA->ODR & GPIO_Pin_7) << 16) | (~GPIOA->ODR & GPIO_Pin_7)
|
||||
|
||||
#define BLUE_ON GPIO_ResetBits(GPIOB, GPIO_Pin_0)
|
||||
#define BLUE_OFF GPIO_SetBits(GPIOB, GPIO_Pin_0)
|
||||
#define BLUE_TOG GPIOA->BSRR = ((GPIOB->ODR & GPIO_Pin_0) << 16) | (~GPIOB->ODR & GPIO_Pin_0)
|
||||
|
||||
#define ASR_Power_ON GPIO_SetBits(GPIOB, GPIO_Pin_8)
|
||||
#define ASR_Power_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_8)
|
||||
|
||||
#define BOARD_Power_ON GPIO_SetBits(GPIOA, GPIO_Pin_1)
|
||||
#define BOARD_Power_OFF GPIO_ResetBits(GPIOA, GPIO_Pin_1)
|
||||
|
||||
#define LED_ALL_ON RED_ON;GREEN_ON;BLUE_ON
|
||||
#define LED_ALL_OFF RED_OFF;GREEN_OFF;BLUE_OFF
|
||||
|
||||
typedef enum
|
||||
{
|
||||
None = 0,
|
||||
CHANGE_Ing, // 充电中
|
||||
CHANGE_Full, // 充满
|
||||
UNLOCK_HighBat, // 解锁高电量
|
||||
UNLOCK_LowBat, // 解锁低电量
|
||||
SEND_Success, // 发送成功
|
||||
SEND_Fail, // 发送失败
|
||||
} LED_State_Enum;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BLACK = 0,
|
||||
GREEN,
|
||||
RED,
|
||||
BLUE,
|
||||
YELLOW,
|
||||
WHITE
|
||||
} LED_Color_Enum;
|
||||
|
||||
void ledBlinkTask(void);
|
||||
extern LEDClassStruct LEDClass;
|
||||
void ASR_Power_Init(void);
|
||||
void BOARD_Power_Init(void);
|
||||
|
||||
#endif
|
||||
27
1.主程序源代码/User/inc/bsp_mod.h
Normal file
27
1.主程序源代码/User/inc/bsp_mod.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef __MOD_H
|
||||
#define __MOD_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
typedef void (*ToggleFunc)(void);
|
||||
typedef void (*DelayFunc)(uint32_t);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*Loop)(ToggleFunc toggle, DelayFunc delayFunc, uint8_t iterations, uint32_t delayTime);
|
||||
} MODClassStruct;
|
||||
|
||||
typedef struct {
|
||||
const char *e_val;
|
||||
const char *t_val;
|
||||
const char *r_val;
|
||||
const char *c_val;
|
||||
} LoraCommandParams;
|
||||
|
||||
extern MODClassStruct MODClass;
|
||||
extern LoraCommandParams cmd_params[];
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
0
1.主程序源代码/User/inc/bsp_sleep.h
Normal file
0
1.主程序源代码/User/inc/bsp_sleep.h
Normal file
21
1.主程序源代码/User/inc/bsp_usart.h
Normal file
21
1.主程序源代码/User/inc/bsp_usart.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef __USART_AS_H
|
||||
#define __USART_AS_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
typedef struct {
|
||||
void (* USART1_Init)(uint32_t baudRate);
|
||||
void (* USART2_Init)(uint32_t baudRate);
|
||||
void (* USART3_Init)(uint32_t baudRate);
|
||||
void (* USART_SendString1)(USART_TypeDef *USARTx, uint8_t *str, uint16_t len);
|
||||
void (* USART_SendString2)(USART_TypeDef* USARTx, uint8_t *str);
|
||||
} USARTClassStruct;
|
||||
|
||||
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
|
||||
|
||||
extern USARTClassStruct USARTClass;
|
||||
extern uint8_t Asr_Power_state;
|
||||
|
||||
extern uint8_t g_asrRxFlag;
|
||||
extern uint8_t Asr_recbuff[];
|
||||
#endif
|
||||
38
1.主程序源代码/User/inc/delay.h
Normal file
38
1.主程序源代码/User/inc/delay.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef __DELAY_H
|
||||
#define __DELAY_H
|
||||
#include "stm32f10x.h"
|
||||
|
||||
void delay_init(void);
|
||||
void delay_ms(u16 nms);
|
||||
void delay_us(u32 nus);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
121
1.主程序源代码/User/inc/flexible_button.h
Normal file
121
1.主程序源代码/User/inc/flexible_button.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @File: flexible_button.h
|
||||
* @Author: MurphyZhao
|
||||
* @Date: 2018-09-29
|
||||
*
|
||||
* Copyright (c) 2018-2019 MurphyZhao <d2014zjt@163.com>
|
||||
* https://github.com/murphyzhao
|
||||
* All rights reserved.
|
||||
* License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Change logs:
|
||||
* Date Author Notes
|
||||
* 2018-09-29 MurphyZhao First add
|
||||
* 2019-08-02 MurphyZhao 迁移代码到 murphyzhao 仓库
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __FLEXIBLE_BUTTON_H__
|
||||
#define __FLEXIBLE_BUTTON_H__
|
||||
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
|
||||
typedef void (*flex_button_response_callback)(void *);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FLEX_BTN_PRESS_DOWN = 0,
|
||||
FLEX_BTN_PRESS_CLICK,
|
||||
FLEX_BTN_PRESS_DOUBLE_CLICK,
|
||||
FLEX_BTN_PRESS_SHORT_START,
|
||||
FLEX_BTN_PRESS_SHORT_UP,
|
||||
FLEX_BTN_PRESS_LONG_START,
|
||||
FLEX_BTN_PRESS_LONG_UP,
|
||||
FLEX_BTN_PRESS_LONG_HOLD,
|
||||
FLEX_BTN_PRESS_LONG_HOLD_UP,
|
||||
FLEX_BTN_PRESS_MAX,
|
||||
FLEX_BTN_PRESS_NONE,
|
||||
} flex_button_event_t;
|
||||
|
||||
/**
|
||||
* flex_button_t
|
||||
*
|
||||
* @brief Button data structure
|
||||
* Below are members that need to user init before scan.
|
||||
*
|
||||
* @member pressed_logic_level: Logic level when the button is pressed.
|
||||
* Must be inited by 'flex_button_register' API
|
||||
* before start button scan.
|
||||
* @member debounce_tick: The time of button debounce.
|
||||
* The value is number of button scan cycles.
|
||||
* @member click_start_tick: The time of start click.
|
||||
* The value is number of button scan cycles.
|
||||
* @member short_press_start_tick: The time of short press start tick.
|
||||
* The value is number of button scan cycles.
|
||||
* @member long_press_start_tick: The time of long press start tick.
|
||||
* The value is number of button scan cycles.
|
||||
* @member long_hold_start_tick: The time of hold press start tick.
|
||||
* The value is number of button scan cycles.
|
||||
* @member usr_button_read: Read the logic level value of specified button.
|
||||
* @member cb: Button event callback function.
|
||||
* If use 'flex_button_event_read' api,
|
||||
* you don't need to initialize the 'cb' member.
|
||||
* @member next : Next button struct
|
||||
*/
|
||||
typedef struct flex_button
|
||||
{
|
||||
uint8_t pressed_logic_level : 1; /* need user to init */
|
||||
|
||||
/**
|
||||
* @event
|
||||
* The event of button in flex_button_evnt_t enum list.
|
||||
* Automatically initialized to the default value FLEX_BTN_PRESS_NONE
|
||||
* by 'flex_button_register' API.
|
||||
*/
|
||||
uint8_t event : 4;
|
||||
|
||||
/**
|
||||
* @status
|
||||
* Used to record the status of the button
|
||||
* Automatically initialized to the default value 0.
|
||||
*/
|
||||
uint8_t status : 3;
|
||||
uint16_t scan_cnt; /* default 0. Used to record the number of key scans */
|
||||
uint16_t click_cnt; /* default 0. Used to record the number of key click */
|
||||
|
||||
uint16_t debounce_tick;
|
||||
uint16_t click_start_tick;
|
||||
uint16_t short_press_start_tick;
|
||||
uint16_t long_press_start_tick;
|
||||
uint16_t long_hold_start_tick;
|
||||
|
||||
uint8_t (*usr_button_read)(void);
|
||||
flex_button_response_callback cb;
|
||||
struct flex_button *next;
|
||||
} flex_button_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int8_t flex_button_register(flex_button_t *button);
|
||||
flex_button_event_t flex_button_event_read(flex_button_t *button);
|
||||
void flex_button_scan(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __FLEXIBLE_BUTTON_H__ */
|
||||
328
1.主程序源代码/User/main.c
Normal file
328
1.主程序源代码/User/main.c
Normal file
@@ -0,0 +1,328 @@
|
||||
#include "main.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#include "timers.h"
|
||||
#include "task.h"
|
||||
#include "shell.h"
|
||||
#include "shell_port.h"
|
||||
|
||||
static TaskHandle_t AppTaskCreate_Handle = NULL; // 创建任务句柄
|
||||
static TaskHandle_t Main_Task_Handle = NULL; // Main任务句柄
|
||||
static TaskHandle_t Key_Task_Handle = NULL; // Key任务句柄
|
||||
static TaskHandle_t Wdog_Task_Handle = NULL; // Wdog任务句柄
|
||||
static TaskHandle_t Bat_Task_Handle = NULL; // 电池任务句柄
|
||||
static TimerHandle_t xTimeHandle = NULL; //软件定时器句柄
|
||||
|
||||
static void AppTaskCreate(void); // 用于创建任务
|
||||
static void Main_Task(void *pvParameters); // Main_Task任务实现
|
||||
static void Key_Task(void *pvParameters); // KEY_Task任务实现
|
||||
static void Wdog_Task(void *pvParameters); // Wdog发送任务实现
|
||||
static void Bat_Task(void *pvParameters); // 电池检测任务实现
|
||||
static void timeCallBackTask(void); // 定时锁机任务实现
|
||||
|
||||
|
||||
uint8_t lora_sendbuf[255]; //Lora数据构造数组
|
||||
|
||||
void BSP_Init(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
BSP_Init();
|
||||
|
||||
xReturn = xTaskCreate((TaskFunction_t)AppTaskCreate,
|
||||
(const char *)"AppTaskCreate",
|
||||
(uint16_t)512,
|
||||
(void *)NULL,
|
||||
(UBaseType_t)1,
|
||||
(TaskHandle_t *)&AppTaskCreate_Handle);
|
||||
|
||||
if (pdPASS == xReturn)
|
||||
vTaskStartScheduler();
|
||||
else
|
||||
return -1;
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
static void AppTaskCreate(void)
|
||||
{
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
taskENTER_CRITICAL(); //临界保护
|
||||
/*创建线程*/
|
||||
xReturn = xTaskCreate((TaskFunction_t)Main_Task,
|
||||
(const char *)"Main_Task",
|
||||
(uint16_t)512,
|
||||
(void *)NULL,
|
||||
(UBaseType_t)2,
|
||||
(TaskHandle_t *)&Main_Task_Handle);
|
||||
if (pdPASS != xReturn)
|
||||
printf("创建Main_Task任务失败!\r\n");
|
||||
|
||||
xReturn = xTaskCreate((TaskFunction_t)Key_Task,
|
||||
(const char *)"Key_Task",
|
||||
(uint16_t)64,
|
||||
(void *)NULL,
|
||||
(UBaseType_t)2,
|
||||
(TaskHandle_t *)&Key_Task_Handle);
|
||||
if (pdPASS != xReturn)
|
||||
printf("创建Key_Task任务失败!\r\n");
|
||||
|
||||
xReturn = xTaskCreate((TaskFunction_t)Wdog_Task,
|
||||
(const char *)"Wdog_Task",
|
||||
(uint16_t)512,
|
||||
(void *)NULL,
|
||||
(UBaseType_t)2, Wdog_Task_Handle);
|
||||
if (pdPASS != xReturn)
|
||||
printf("创建Wdog_Task任务失败!\r\n");
|
||||
|
||||
xReturn = xTaskCreate((TaskFunction_t)Bat_Task,
|
||||
(const char *)"Bat_Task",
|
||||
(uint16_t)64,
|
||||
(void *)NULL,
|
||||
(UBaseType_t)2, Bat_Task_Handle);
|
||||
if (pdPASS != xReturn)
|
||||
printf("创建Bat_Task任务失败!\r\n");
|
||||
|
||||
|
||||
/*注册超时模块软件定时器*/
|
||||
xTimeHandle = xTimerCreate(
|
||||
(const char *)"time_lock", // 定时器名字
|
||||
(TickType_t)1000, // 定时器的周期
|
||||
pdTRUE, // 定时器周期执行
|
||||
(void *)1, // 给定时器分配的唯一ID
|
||||
(TimerCallbackFunction_t)timeCallBackTask // 定时器回调函数
|
||||
);
|
||||
if (xTimeHandle)
|
||||
{
|
||||
xTimerStart(xTimeHandle, 0); // 开启定时器
|
||||
}
|
||||
|
||||
vTaskDelete(AppTaskCreate_Handle);
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/*软件定时器回调*/
|
||||
void timeCallBackTask(void)
|
||||
{
|
||||
if (rc_data()->Lock_state == UNLOCK)
|
||||
{
|
||||
rc_data()->Lock_time_tick++;
|
||||
}
|
||||
|
||||
if (rc_data()->Lock_time_tick >= rc_data()->Kv_get.lock_time)
|
||||
{
|
||||
rc_data()->Asr_state = LOCK;
|
||||
rc_data()->Lock_state = LOCK;
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
ASR_Power_OFF;
|
||||
LEDClass.Set(BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
/*主线程函数*/
|
||||
static void Main_Task(void *parameter)
|
||||
{
|
||||
|
||||
while (1)
|
||||
{
|
||||
/*按键控制模式*/
|
||||
if((rc_data()->Lock_state ==UNLOCK)&&(rc_data()->Asr_state == LOCK))
|
||||
{
|
||||
LEDClass.Set(BLACK);
|
||||
ADC1Class.GetValue(0) > 170 ? LEDClass.Set(GREEN) : LEDClass.Set(YELLOW);
|
||||
|
||||
if(rc_data()->isLEDTog == ENABLE)
|
||||
{
|
||||
LEDClass.Set(BLACK);
|
||||
MODClass.Loop(LEDClass.GREEN_Toggle,vTaskDelay,7,50);
|
||||
rc_data()->isLEDTog = 0;
|
||||
}
|
||||
|
||||
if(rc_data()->isSend == ENABLE )
|
||||
{
|
||||
rc_data()->isSend = DISABLE;
|
||||
if ((rc_data()->Key_data[0] == 0 && rc_data()->Key_data[1] == 1) || (rc_data()->Key_data[0] != 0))
|
||||
{
|
||||
sprintf((char *)lora_sendbuf,
|
||||
"AT+LRSEND=85,1,33,\"{\"E\":\"%d\",\"T\":\"%d\",\"R\":\"%d\",\"C\":\"%d\"}\"\r\n",
|
||||
rc_data()->Key_data[0],rc_data()->Key_data[1],
|
||||
//(rc_data()->Key_data[0] != 9 && rc_data()->Key_data[0] != 10) ? rc_data()->Key_data[0] : 0,
|
||||
//(rc_data()->Key_data[0] != 9 && rc_data()->Key_data[0] != 10) ? rc_data()->Key_data[1] : 0,
|
||||
rc_data()->Key_data[2],
|
||||
rc_data()->Key_data[3]);
|
||||
LEDClass.Set(BLACK);
|
||||
USARTClass.USART_SendString1(USART3, lora_sendbuf, 54);
|
||||
MODClass.Loop(LEDClass.GREEN_Toggle,vTaskDelay,4,400);
|
||||
LEDClass.Set(BLACK);
|
||||
rc_data()->Lock_state = LOCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
LEDClass.Set(BLACK);
|
||||
MODClass.Loop(LEDClass.RED_Toggle,vTaskDelay,4,400);
|
||||
}
|
||||
memset(rc_data()->Key_data,0x00,4);
|
||||
}
|
||||
}
|
||||
/*语音控制模式*/
|
||||
if((rc_data()->Lock_state==UNLOCK)&&rc_data()->Asr_state == UNLOCK)
|
||||
{
|
||||
LEDClass.Set(WHITE);
|
||||
if (Asr_recbuff[0] == 0x55 && Asr_recbuff[1] == 0xAA)
|
||||
{
|
||||
rc_data()->Lock_time_tick =0;
|
||||
switch (Asr_recbuff[2])
|
||||
{
|
||||
case 1 ... 12:
|
||||
{
|
||||
const LoraCommandParams *params = &cmd_params[Asr_recbuff[2] - 1];
|
||||
sprintf((char *)lora_sendbuf,
|
||||
"AT+LRSEND=85,1,33,\"{\"E\":\"%s\",\"T\":\"%s\",\"R\":\"%s\",\"C\":\"%s\"}\"\r\n",
|
||||
params->e_val, params->t_val, params->r_val, params->c_val);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
USARTClass.USART_SendString1(USART3, lora_sendbuf, 54);
|
||||
memset(Asr_recbuff, 0x00, 20);
|
||||
LEDClass.Set(BLACK);
|
||||
MODClass.Loop(LEDClass.GREEN_Toggle,vTaskDelay,4,400);
|
||||
LEDClass.Set(BLACK);
|
||||
rc_data()->Lock_state = LOCK;
|
||||
rc_data()->Asr_state = LOCK;
|
||||
vTaskDelay(2000);
|
||||
ASR_Power_OFF;
|
||||
}
|
||||
}
|
||||
if(rc_data()->Lock_state ==LOCK)
|
||||
{
|
||||
BATClass.Read_State();
|
||||
}
|
||||
vTaskDelay(20);
|
||||
}
|
||||
}
|
||||
|
||||
/*看门狗线程函数*/
|
||||
static void Wdog_Task(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
IWDG_ReloadCounter();
|
||||
vTaskDelay(30);
|
||||
}
|
||||
}
|
||||
|
||||
/*电池检测线程函数*/
|
||||
static void Bat_Task(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
|
||||
// printf("bat value:%d\r\n",ADC1Class.GetValue(0));
|
||||
vTaskDelay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
/*按键检测线程函数*/
|
||||
static void Key_Task(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
flex_button_scan();
|
||||
vTaskDelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*用户密码提取kv函数*/
|
||||
//static void read_password(void)
|
||||
//{
|
||||
// char *read_password;
|
||||
// read_password = ef_get_env("ziit_password");
|
||||
// assert_param(read_password);
|
||||
// strcpy(shellPasswordDefaultUser, read_password);
|
||||
// printf("The ziit password is %s \n\r", shellPasswordDefaultUser);
|
||||
//}
|
||||
|
||||
/*锁定时间提取kv函数*/
|
||||
static void read_lock_time(void)
|
||||
{
|
||||
char *keys;
|
||||
keys = ef_get_env("key_s");
|
||||
assert_param(keys); //检查参数合法性
|
||||
rc_data()->Kv_get.lock_time = atol(keys); //str => int
|
||||
printf("锁定时间:%d\r\n", rc_data()->Kv_get.lock_time);
|
||||
}
|
||||
|
||||
/*
|
||||
* 按键使能提取函数 - 使用16位变量存储10个按键状态
|
||||
* 每个按键占用1位,最低位(bit0)表示第1个按键,bit9表示第10个按键
|
||||
* 0表示失能,1表示使能
|
||||
*/
|
||||
static void read_key_en_table(void)
|
||||
{
|
||||
char *key_en_table;
|
||||
uint16_t key_en_bits = 0; // 16位存储按键状态
|
||||
|
||||
// 从环境变量获取键值
|
||||
key_en_table = ef_get_env("key_en_table");
|
||||
assert_param(key_en_table); // 检查参数合法性
|
||||
|
||||
// 将字符串转换为16位数值
|
||||
key_en_bits = (uint16_t)strtoul(key_en_table, NULL, 0);
|
||||
|
||||
// 存储到数据结构中
|
||||
rc_data()->Kv_get.key_en_table = key_en_bits;
|
||||
|
||||
}
|
||||
|
||||
/*BSP初始化函数*/
|
||||
static void BSP_Init(void)
|
||||
{
|
||||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
|
||||
delay_init();
|
||||
LEDClass.Init();
|
||||
ASR_Power_Init();
|
||||
USARTClass.USART1_Init(115200);
|
||||
USARTClass.USART3_Init(9600);
|
||||
USARTClass.USART2_Init(9600);
|
||||
USARTClass.USART_SendString1(USART3, (uint8_t *)"start",5);
|
||||
BATClass.Init();
|
||||
ADC1Class.Init();
|
||||
rc_data()->Lock_state = UNLOCK;
|
||||
rc_data()->Asr_state = LOCK;
|
||||
rc_data()->isSend = DISABLE;
|
||||
rc_data()->isLEDTog = DISABLE;
|
||||
ASR_Power_OFF;
|
||||
delay_ms(700);
|
||||
delay_ms(700);
|
||||
BOARD_Power_Init();
|
||||
LEDClass.Set(GREEN);
|
||||
Power_button_init();
|
||||
if (easyflash_init() == EF_NO_ERR)
|
||||
{
|
||||
// read_password();
|
||||
read_lock_time();
|
||||
read_key_en_table();
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
if (Check_Power_buttun() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
WDOG_Init();
|
||||
userShellInit();
|
||||
user_button_init();
|
||||
}
|
||||
|
||||
57
1.主程序源代码/User/main.h
Normal file
57
1.主程序源代码/User/main.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef __MAIN_H
|
||||
#define __MAIN_H
|
||||
|
||||
// ST lib
|
||||
#include "stm32f10x.h"
|
||||
// C lib
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
// system
|
||||
#include "delay.h"
|
||||
|
||||
// drive
|
||||
#include "flexible_button.h"
|
||||
#include "bsp_led.h"
|
||||
#include "bsp_button.h"
|
||||
#include "bsp_usart.h"
|
||||
#include "bsp_chipid.h"
|
||||
#include "bsp_bat.h"
|
||||
#include "bsp_mod.h"
|
||||
#include "easyflash.h"
|
||||
|
||||
#define LOCK 0
|
||||
#define UNLOCK 1
|
||||
|
||||
extern uint8_t Lora_recbuff[];
|
||||
|
||||
/*整机数据结构体*/
|
||||
typedef struct rc_data
|
||||
{
|
||||
|
||||
uint8_t Lock_state; //整机锁定状态
|
||||
uint8_t Asr_state; //语音锁定状态
|
||||
uint8_t Key_data[4]; //当前键值
|
||||
uint8_t Lock_time_tick; //无操作锁定计时
|
||||
uint8_t isLEDTog; //闪烁信号
|
||||
uint8_t isSend; //发送使能
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
char lock_time; // 数据库读取锁定时间
|
||||
uint8_t password[8]; // 数据库读取密码
|
||||
uint16_t key_en_table; // 按键使能表 10个按键
|
||||
} Kv_get;
|
||||
};
|
||||
} rc_data_t;
|
||||
|
||||
rc_data_t *rc_data(void);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
2146
1.主程序源代码/User/shell/shell.c
Normal file
2146
1.主程序源代码/User/shell/shell.c
Normal file
File diff suppressed because it is too large
Load Diff
557
1.主程序源代码/User/shell/shell.h
Normal file
557
1.主程序源代码/User/shell/shell.h
Normal file
@@ -0,0 +1,557 @@
|
||||
/**
|
||||
* @file shell.h
|
||||
* @author Letter (NevermindZZT@gmail.com)
|
||||
* @brief letter shell
|
||||
* @version 3.0.0
|
||||
* @date 2019-12-30
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_H__
|
||||
#define __SHELL_H__
|
||||
|
||||
#include "shell_cfg.h"
|
||||
|
||||
#define SHELL_VERSION "3.2.4" /**< 版本号 */
|
||||
|
||||
|
||||
/**
|
||||
* @brief shell 断言
|
||||
*
|
||||
* @param expr 表达式
|
||||
* @param action 断言失败操作
|
||||
*/
|
||||
#define SHELL_ASSERT(expr, action) \
|
||||
if (!(expr)) { \
|
||||
action; \
|
||||
}
|
||||
|
||||
#if SHELL_USING_LOCK == 1
|
||||
#define SHELL_LOCK(shell) shell->lock(shell)
|
||||
#define SHELL_UNLOCK(shell) shell->unlock(shell)
|
||||
#else
|
||||
#define SHELL_LOCK(shell)
|
||||
#define SHELL_UNLOCK(shell)
|
||||
#endif /** SHELL_USING_LOCK == 1 */
|
||||
/**
|
||||
* @brief shell 命令权限
|
||||
*
|
||||
* @param permission 权限级别
|
||||
*/
|
||||
#define SHELL_CMD_PERMISSION(permission) \
|
||||
(permission & 0x000000FF)
|
||||
|
||||
/**
|
||||
* @brief shell 命令类型
|
||||
*
|
||||
* @param type 类型
|
||||
*/
|
||||
#define SHELL_CMD_TYPE(type) \
|
||||
((type & 0x0000000F) << 8)
|
||||
|
||||
/**
|
||||
* @brief 使能命令在未校验密码的情况下使用
|
||||
*/
|
||||
#define SHELL_CMD_ENABLE_UNCHECKED \
|
||||
(1 << 12)
|
||||
|
||||
/**
|
||||
* @brief 禁用返回值打印
|
||||
*/
|
||||
#define SHELL_CMD_DISABLE_RETURN \
|
||||
(1 << 13)
|
||||
|
||||
/**
|
||||
* @brief 只读属性(仅对变量生效)
|
||||
*/
|
||||
#define SHELL_CMD_READ_ONLY \
|
||||
(1 << 14)
|
||||
|
||||
/**
|
||||
* @brief 命令参数数量
|
||||
*/
|
||||
#define SHELL_CMD_PARAM_NUM(num) \
|
||||
((num & 0x0000000F)) << 16
|
||||
|
||||
#ifndef SHELL_SECTION
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM)
|
||||
#define SHELL_SECTION(x) __attribute__((section(x), aligned(1)))
|
||||
#elif defined (__IAR_SYSTEMS_ICC__)
|
||||
#define SHELL_SECTION(x) @ x
|
||||
#elif defined(__GNUC__)
|
||||
#define SHELL_SECTION(x) __attribute__((section(x), aligned(1)))
|
||||
#else
|
||||
#define SHELL_SECTION(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_USED
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM)
|
||||
#define SHELL_USED __attribute__((used))
|
||||
#elif defined (__IAR_SYSTEMS_ICC__)
|
||||
#define SHELL_USED __root
|
||||
#elif defined(__GNUC__)
|
||||
#define SHELL_USED __attribute__((used))
|
||||
#else
|
||||
#define SHELL_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief shell float型参数转换
|
||||
*/
|
||||
#define SHELL_PARAM_FLOAT(x) (*(float *)(&x))
|
||||
|
||||
/**
|
||||
* @brief shell 代理函数名
|
||||
*/
|
||||
#define SHELL_AGENCY_FUNC_NAME(_func) agency##_func
|
||||
|
||||
/**
|
||||
* @brief shell代理函数定义
|
||||
*
|
||||
* @param _func 被代理的函数
|
||||
* @param ... 代理参数
|
||||
*/
|
||||
#define SHELL_AGENCY_FUNC(_func, ...) \
|
||||
void SHELL_AGENCY_FUNC_NAME(_func)(int p1, int p2, int p3, int p4, int p5, int p6, int p7) \
|
||||
{ _func(__VA_ARGS__); }
|
||||
|
||||
#if SHELL_USING_CMD_EXPORT == 1
|
||||
|
||||
/**
|
||||
* @brief shell 命令定义
|
||||
*
|
||||
* @param _attr 命令属性
|
||||
* @param _name 命令名
|
||||
* @param _func 命令函数
|
||||
* @param _desc 命令描述
|
||||
* @param ... 其他参数
|
||||
*/
|
||||
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc, ...) \
|
||||
const char shellCmd##_name[] = #_name; \
|
||||
const char shellDesc##_name[] = #_desc; \
|
||||
SHELL_USED const ShellCommand \
|
||||
shellCommand##_name SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
.attr.value = _attr, \
|
||||
.data.cmd.name = shellCmd##_name, \
|
||||
.data.cmd.function = (int (*)())_func, \
|
||||
.data.cmd.desc = shellDesc##_name, \
|
||||
##__VA_ARGS__ \
|
||||
}
|
||||
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
/**
|
||||
* @brief shell 命令定义
|
||||
*
|
||||
* @param _attr 命令属性
|
||||
* @param _name 命令名
|
||||
* @param _func 命令函数
|
||||
* @param _desc 命令描述
|
||||
* @param _sign 命令签名
|
||||
*/
|
||||
#define SHELL_EXPORT_CMD_SIGN(_attr, _name, _func, _desc, _sign) \
|
||||
const char shellCmd##_name[] = #_name; \
|
||||
const char shellDesc##_name[] = #_desc; \
|
||||
const char shellSign##_name[] = #_sign; \
|
||||
SHELL_USED const ShellCommand \
|
||||
shellCommand##_name SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
.attr.value = _attr, \
|
||||
.data.cmd.name = shellCmd##_name, \
|
||||
.data.cmd.function = (int (*)())_func, \
|
||||
.data.cmd.desc = shellDesc##_name, \
|
||||
.data.cmd.signature = shellSign##_name \
|
||||
}
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
|
||||
/**
|
||||
* @brief shell 代理命令定义
|
||||
*
|
||||
* @param _attr 命令属性
|
||||
* @param _name 命令名
|
||||
* @param _func 命令函数
|
||||
* @param _desc 命令描述
|
||||
* @param ... 代理参数
|
||||
*/
|
||||
#define SHELL_EXPORT_CMD_AGENCY(_attr, _name, _func, _desc, ...) \
|
||||
SHELL_AGENCY_FUNC(_func, ##__VA_ARGS__) \
|
||||
SHELL_EXPORT_CMD(_attr, _name, SHELL_AGENCY_FUNC_NAME(_func), _desc)
|
||||
|
||||
/**
|
||||
* @brief shell 变量定义
|
||||
*
|
||||
* @param _attr 变量属性
|
||||
* @param _name 变量名
|
||||
* @param _value 变量值
|
||||
* @param _desc 变量描述
|
||||
*/
|
||||
#define SHELL_EXPORT_VAR(_attr, _name, _value, _desc) \
|
||||
const char shellCmd##_name[] = #_name; \
|
||||
const char shellDesc##_name[] = #_desc; \
|
||||
SHELL_USED const ShellCommand \
|
||||
shellVar##_name SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
.attr.value = _attr, \
|
||||
.data.var.name = shellCmd##_name, \
|
||||
.data.var.value = (void *)_value, \
|
||||
.data.var.desc = shellDesc##_name \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell 用户定义
|
||||
*
|
||||
* @param _attr 用户属性
|
||||
* @param _name 用户名
|
||||
* @param _password 用户密码
|
||||
* @param _desc 用户描述
|
||||
*/
|
||||
#define SHELL_EXPORT_USER(_attr, _name, _password, _desc) \
|
||||
const char shellCmd##_name[] = #_name; \
|
||||
const char shellPassword##_name[] = #_password; \
|
||||
const char shellDesc##_name[] = #_desc; \
|
||||
SHELL_USED const ShellCommand \
|
||||
shellUser##_name SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
|
||||
.data.user.name = shellCmd##_name, \
|
||||
.data.user.password = shellPassword##_name, \
|
||||
.data.user.desc = shellDesc##_name \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell 按键定义
|
||||
*
|
||||
* @param _attr 按键属性
|
||||
* @param _value 按键键值
|
||||
* @param _func 按键函数
|
||||
* @param _desc 按键描述
|
||||
*/
|
||||
#define SHELL_EXPORT_KEY(_attr, _value, _func, _desc) \
|
||||
const char shellDesc##_value[] = #_desc; \
|
||||
SHELL_USED const ShellCommand \
|
||||
shellKey##_value SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
|
||||
.data.key.value = _value, \
|
||||
.data.key.function = (void (*)(Shell *))_func, \
|
||||
.data.key.desc = shellDesc##_value \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell 代理按键定义
|
||||
*
|
||||
* @param _attr 按键属性
|
||||
* @param _value 按键键值
|
||||
* @param _func 按键函数
|
||||
* @param _desc 按键描述
|
||||
* @param ... 代理参数
|
||||
*/
|
||||
#define SHELL_EXPORT_KEY_AGENCY(_attr, _value, _func, _desc, ...) \
|
||||
SHELL_AGENCY_FUNC(_func, ##__VA_ARGS__) \
|
||||
SHELL_EXPORT_KEY(_attr, _value, SHELL_AGENCY_FUNC_NAME(_func), _desc)
|
||||
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
/**
|
||||
* @brief shell 参数解析器定义
|
||||
*
|
||||
* @param _attr 参数解析器属性
|
||||
* @param _type 参数解析器类型
|
||||
* @param _parser 参数解析器函数
|
||||
* @param _cleaner 参数清理器
|
||||
*/
|
||||
#define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _parser, _cleaner) \
|
||||
const char shellDesc##_parser[] = #_type; \
|
||||
SHELL_USED const ShellCommand \
|
||||
shellCommand##_parser SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \
|
||||
.data.paramParser.type = shellDesc##_parser, \
|
||||
.data.paramParser.parser = (int (*)(char *, void **))_parser, \
|
||||
.data.paramParser.cleaner = (int (*)(void *))_cleaner \
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
/**
|
||||
* @brief shell 命令item定义
|
||||
*
|
||||
* @param _attr 命令属性
|
||||
* @param _name 命令名
|
||||
* @param _func 命令函数
|
||||
* @param _desc 命令描述
|
||||
*/
|
||||
#define SHELL_CMD_ITEM(_attr, _name, _func, _desc) \
|
||||
{ \
|
||||
.attr.value = _attr, \
|
||||
.data.cmd.name = #_name, \
|
||||
.data.cmd.function = (int (*)())_func, \
|
||||
.data.cmd.desc = #_desc \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell 变量item定义
|
||||
*
|
||||
* @param _attr 变量属性
|
||||
* @param _name 变量名
|
||||
* @param _value 变量值
|
||||
* @param _desc 变量描述
|
||||
*/
|
||||
#define SHELL_VAR_ITEM(_attr, _name, _value, _desc) \
|
||||
{ \
|
||||
.attr.value = _attr, \
|
||||
.data.var.name = #_name, \
|
||||
.data.var.value = (void *)_value, \
|
||||
.data.var.desc = #_desc \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell 用户item定义
|
||||
*
|
||||
* @param _attr 用户属性
|
||||
* @param _name 用户名
|
||||
* @param _password 用户密码
|
||||
* @param _desc 用户描述
|
||||
*/
|
||||
#define SHELL_USER_ITEM(_attr, _name, _password, _desc) \
|
||||
{ \
|
||||
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
|
||||
.data.user.name = #_name, \
|
||||
.data.user.password = #_password, \
|
||||
.data.user.desc = #_desc \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell 按键item定义
|
||||
*
|
||||
* @param _attr 按键属性
|
||||
* @param _value 按键键值
|
||||
* @param _func 按键函数
|
||||
* @param _desc 按键描述
|
||||
*/
|
||||
#define SHELL_KEY_ITEM(_attr, _value, _func, _desc) \
|
||||
{ \
|
||||
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
|
||||
.data.key.value = _value, \
|
||||
.data.key.function = (void (*)(Shell *))_func, \
|
||||
.data.key.desc = #_desc \
|
||||
}
|
||||
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
/**
|
||||
* @brief shell 参数解析器item定义
|
||||
*
|
||||
* @param _attr 参数解析器属性
|
||||
* @param _type 参数解析器类型
|
||||
* @param _parser 参数解析器函数
|
||||
* @param _cleaner 参数清理器
|
||||
*/
|
||||
#define SHELL_PARAM_PARSER_ITEM(_attr, _type, _parser, _cleaner) \
|
||||
{ \
|
||||
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \
|
||||
.data.paramParser.type = #_type, \
|
||||
.data.paramParser.parser = (int (*)(char *, void **))_parser, \
|
||||
.data.paramParser.cleaner = (int (*)(void *))_cleaner \
|
||||
}
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
|
||||
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc)
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
#define SHELL_EXPORT_CMD_SIGN(_attr, _name, _func, _desc, _sign)
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
#define SHELL_EXPORT_CMD_AGENCY(_attr, _name, _func, _desc, ...)
|
||||
#define SHELL_EXPORT_VAR(_attr, _name, _value, _desc)
|
||||
#define SHELL_EXPORT_USER(_attr, _name, _password, _desc)
|
||||
#define SHELL_EXPORT_KEY(_attr, _value, _func, _desc)
|
||||
#define SHELL_EXPORT_KEY_AGENCY(_attr, _name, _func, _desc, ...)
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
#define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _parser, _cleaner)
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
#endif /** SHELL_USING_CMD_EXPORT == 1 */
|
||||
|
||||
/**
|
||||
* @brief shell command类型
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SHELL_TYPE_CMD_MAIN = 0, /**< main形式命令 */
|
||||
SHELL_TYPE_CMD_FUNC, /**< C函数形式命令 */
|
||||
SHELL_TYPE_VAR_INT, /**< int型变量 */
|
||||
SHELL_TYPE_VAR_SHORT, /**< short型变量 */
|
||||
SHELL_TYPE_VAR_CHAR, /**< char型变量 */
|
||||
SHELL_TYPE_VAR_STRING, /**< string型变量 */
|
||||
SHELL_TYPE_VAR_POINT, /**< 指针型变量 */
|
||||
SHELL_TYPE_VAR_NODE, /**< 节点变量 */
|
||||
SHELL_TYPE_USER, /**< 用户 */
|
||||
SHELL_TYPE_KEY, /**< 按键 */
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
SHELL_TYPE_PARAM_PARSER, /**< 参数解析器 */
|
||||
#endif
|
||||
} ShellCommandType;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Shell定义
|
||||
*/
|
||||
typedef struct shell_def
|
||||
{
|
||||
struct
|
||||
{
|
||||
const struct shell_command *user; /**< 当前用户 */
|
||||
int activeTime; /**< shell激活时间 */
|
||||
char *path; /**< 当前shell路径 */
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
struct shell_companion_object *companions; /**< 伴生对象 */
|
||||
#endif
|
||||
#if SHELL_KEEP_RETURN_VALUE == 1
|
||||
int retVal; /**< 返回值 */
|
||||
#endif
|
||||
} info;
|
||||
struct
|
||||
{
|
||||
unsigned short length; /**< 输入数据长度 */
|
||||
unsigned short cursor; /**< 当前光标位置 */
|
||||
char *buffer; /**< 输入缓冲 */
|
||||
char *param[SHELL_PARAMETER_MAX_NUMBER]; /**< 参数 */
|
||||
unsigned short bufferSize; /**< 输入缓冲大小 */
|
||||
unsigned short paramCount; /**< 参数数量 */
|
||||
int keyValue; /**< 输入按键键值 */
|
||||
} parser;
|
||||
#if SHELL_HISTORY_MAX_NUMBER > 0
|
||||
struct
|
||||
{
|
||||
char *item[SHELL_HISTORY_MAX_NUMBER]; /**< 历史记录 */
|
||||
unsigned short number; /**< 历史记录数 */
|
||||
unsigned short record; /**< 当前记录位置 */
|
||||
signed short offset; /**< 当前历史记录偏移 */
|
||||
} history;
|
||||
#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
|
||||
struct
|
||||
{
|
||||
void *base; /**< 命令表基址 */
|
||||
unsigned short count; /**< 命令数量 */
|
||||
} commandList;
|
||||
struct
|
||||
{
|
||||
unsigned char isChecked : 1; /**< 密码校验通过 */
|
||||
unsigned char isActive : 1; /**< 当前活动Shell */
|
||||
unsigned char tabFlag : 1; /**< tab标志 */
|
||||
} status;
|
||||
signed short (*read)(char *, unsigned short); /**< shell读函数 */
|
||||
signed short (*write)(char *, unsigned short); /**< shell写函数 */
|
||||
#if SHELL_USING_LOCK == 1
|
||||
int (*lock)(struct shell_def *); /**< shell 加锁 */
|
||||
int (*unlock)(struct shell_def *); /**< shell 解锁 */
|
||||
#endif
|
||||
} Shell;
|
||||
|
||||
|
||||
/**
|
||||
* @brief shell command定义
|
||||
*/
|
||||
typedef struct shell_command
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char permission : 8; /**< command权限 */
|
||||
ShellCommandType type : 4; /**< command类型 */
|
||||
unsigned char enableUnchecked : 1; /**< 在未校验密码的情况下可用 */
|
||||
unsigned char disableReturn : 1; /**< 禁用返回值输出 */
|
||||
unsigned char readOnly : 1; /**< 只读 */
|
||||
unsigned char reserve : 1; /**< 保留 */
|
||||
unsigned char paramNum : 4; /**< 参数数量 */
|
||||
} attrs;
|
||||
int value;
|
||||
} attr; /**< 属性 */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
const char *name; /**< 命令名 */
|
||||
int (*function)(); /**< 命令执行函数 */
|
||||
const char *desc; /**< 命令描述 */
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
const char *signature; /**< 函数签名 */
|
||||
#endif
|
||||
} cmd; /**< 命令定义 */
|
||||
struct
|
||||
{
|
||||
const char *name; /**< 变量名 */
|
||||
void *value; /**< 变量值 */
|
||||
const char *desc; /**< 变量描述 */
|
||||
} var; /**< 变量定义 */
|
||||
struct
|
||||
{
|
||||
const char *name; /**< 用户名 */
|
||||
const char *password; /**< 用户密码 */
|
||||
const char *desc; /**< 用户描述 */
|
||||
} user; /**< 用户定义 */
|
||||
struct
|
||||
{
|
||||
int value; /**< 按键键值 */
|
||||
void (*function)(Shell *); /**< 按键执行函数 */
|
||||
const char *desc; /**< 按键描述 */
|
||||
} key; /**< 按键定义 */
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
struct
|
||||
{
|
||||
const char *type; /**< 参数类型 */
|
||||
int (*parser)(char *, void **); /**< 解析函数 */
|
||||
int (*cleaner)(void *); /**< 清理器 */
|
||||
} paramParser; /**< 参数解析器 */
|
||||
#endif
|
||||
} data;
|
||||
} ShellCommand;
|
||||
|
||||
/**
|
||||
* @brief shell节点变量属性
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void *var; /**< 变量引用 */
|
||||
int (*get)(); /**< 变量get方法 */
|
||||
int (*set)(); /**< 变量set方法 */
|
||||
} ShellNodeVarAttr;
|
||||
|
||||
|
||||
#define shellSetPath(_shell, _path) (_shell)->info.path = _path
|
||||
#define shellGetPath(_shell) ((_shell)->info.path)
|
||||
|
||||
#define shellDeInit(shell) shellRemove(shell)
|
||||
|
||||
void shellInit(Shell *shell, char *buffer, unsigned short size);
|
||||
void shellRemove(Shell *shell);
|
||||
unsigned short shellWriteString(Shell *shell, const char *string);
|
||||
void shellPrint(Shell *shell, const char *fmt, ...);
|
||||
void shellScan(Shell *shell, char *fmt, ...);
|
||||
Shell* shellGetCurrent(void);
|
||||
void shellHandler(Shell *shell, char data);
|
||||
void shellWriteEndLine(Shell *shell, char *buffer, int len);
|
||||
void shellTask(void *param);
|
||||
int shellRun(Shell *shell, const char *cmd);
|
||||
|
||||
|
||||
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
/**
|
||||
* @brief shell伴生对象定义
|
||||
*/
|
||||
typedef struct shell_companion_object
|
||||
{
|
||||
int id; /**< 伴生对象ID */
|
||||
void *obj; /**< 伴生对象 */
|
||||
struct shell_companion_object *next; /**< 下一个伴生对象 */
|
||||
} ShellCompanionObj;
|
||||
|
||||
|
||||
signed char shellCompanionAdd(Shell *shell, int id, void *object);
|
||||
signed char shellCompanionDel(Shell *shell, int id);
|
||||
void *shellCompanionGet(Shell *shell, int id);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
182
1.主程序源代码/User/shell/shell_cfg.h
Normal file
182
1.主程序源代码/User/shell/shell_cfg.h
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* @file shell_cfg.h
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief shell config
|
||||
* @version 3.0.0
|
||||
* @date 2019-12-31
|
||||
*
|
||||
* @copyright (c) 2019 Letter
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_CFG_H__
|
||||
#define __SHELL_CFG_H__
|
||||
|
||||
#include "stm32f10x.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "portable.h"
|
||||
|
||||
#define SHELL_GET_TICK() (xTaskGetTickCount() * portTICK_PERIOD_MS)
|
||||
/**
|
||||
* @brief 是否使用默认shell任务while循环,使能宏`SHELL_USING_TASK`后此宏有意义
|
||||
* 使能此宏,则`shellTask()`函数会一直循环读取输入,一般使用操作系统建立shell
|
||||
* 任务时使能此宏,关闭此宏的情况下,一般适用于无操作系统,在主循环中调用`shellTask()`
|
||||
*/
|
||||
#define SHELL_TASK_WHILE 1
|
||||
|
||||
/**
|
||||
* @brief 是否使用命令导出方式
|
||||
* 使能此宏后,可以使用`SHELL_EXPORT_CMD()`等导出命令
|
||||
* 定义shell命令,关闭此宏的情况下,需要使用命令表的方式
|
||||
*/
|
||||
#define SHELL_USING_CMD_EXPORT 1
|
||||
|
||||
/**
|
||||
* @brief 是否使用shell伴生对象
|
||||
* 一些扩展的组件(文件系统支持,日志工具等)需要使用伴生对象
|
||||
*/
|
||||
#define SHELL_USING_COMPANION 0
|
||||
|
||||
|
||||
/**
|
||||
* @brief 支持shell尾行模式
|
||||
*/
|
||||
#define SHELL_SUPPORT_END_LINE 1
|
||||
|
||||
/**
|
||||
* @brief 是否在输出命令列表中列出用户
|
||||
*/
|
||||
#define SHELL_HELP_LIST_USER 1
|
||||
|
||||
/**
|
||||
* @brief 是否在输出命令列表中列出变量
|
||||
*/
|
||||
#define SHELL_HELP_LIST_VAR 0
|
||||
|
||||
/**
|
||||
* @brief 是否在输出命令列表中列出按键
|
||||
*/
|
||||
#define SHELL_HELP_LIST_KEY 0
|
||||
|
||||
/**
|
||||
* @brief 是否在输出命令列表中展示命令权限
|
||||
*/
|
||||
#define SHELL_HELP_SHOW_PERMISSION 0
|
||||
|
||||
/**
|
||||
* @brief 使用LF作为命令行回车触发
|
||||
* 可以和SHELL_ENTER_CR同时开启
|
||||
*/
|
||||
#define SHELL_ENTER_LF 0
|
||||
|
||||
/**
|
||||
* @brief 使用CR作为命令行回车触发
|
||||
* 可以和SHELL_ENTER_LF同时开启
|
||||
*/
|
||||
#define SHELL_ENTER_CR 1
|
||||
|
||||
/**
|
||||
* @brief 使用CRLF作为命令行回车触发
|
||||
* 不可以和SHELL_ENTER_LF或SHELL_ENTER_CR同时开启
|
||||
*/
|
||||
#define SHELL_ENTER_CRLF 0
|
||||
|
||||
/**
|
||||
* @brief 使用执行未导出函数的功能
|
||||
* 启用后,可以通过`exec [addr] [args]`直接执行对应地址的函数
|
||||
* @attention 如果地址错误,可能会直接引起程序崩溃
|
||||
*/
|
||||
#define SHELL_EXEC_UNDEF_FUNC 0
|
||||
|
||||
/**
|
||||
* @brief shell命令参数最大数量
|
||||
* 包含命令名在内,超过16个参数并且使用了参数自动转换的情况下,需要修改源码
|
||||
*/
|
||||
#define SHELL_PARAMETER_MAX_NUMBER 8
|
||||
|
||||
/**
|
||||
* @brief 历史命令记录数量
|
||||
*/
|
||||
#define SHELL_HISTORY_MAX_NUMBER 5
|
||||
|
||||
/**
|
||||
* @brief 双击间隔(ms)
|
||||
* 使能宏`SHELL_LONG_HELP`后此宏生效,定义双击tab补全help的时间间隔
|
||||
*/
|
||||
#define SHELL_DOUBLE_CLICK_TIME 200
|
||||
|
||||
/**
|
||||
* @brief 管理的最大shell数量
|
||||
*/
|
||||
#define SHELL_MAX_NUMBER 10
|
||||
|
||||
/**
|
||||
* @brief shell格式化输出的缓冲大小
|
||||
* 为0时不使用shell格式化输出
|
||||
*/
|
||||
#define SHELL_PRINT_BUFFER 128
|
||||
|
||||
/**
|
||||
* @brief shell格式化输入的缓冲大小
|
||||
* 为0时不使用shell格式化输入
|
||||
* @note shell格式化输入会阻塞shellTask, 仅适用于在有操作系统的情况下使用
|
||||
*/
|
||||
#define SHELL_SCAN_BUFFER 128
|
||||
|
||||
/**
|
||||
* @brief 获取系统时间(ms)
|
||||
* 定义此宏为获取系统Tick,如`HAL_GetTick()`
|
||||
* @note 此宏不定义时无法使用双击tab补全命令help,无法使用shell超时锁定
|
||||
*/
|
||||
#define SHELL_GET_TICK() (xTaskGetTickCount() * portTICK_PERIOD_MS)
|
||||
|
||||
/**
|
||||
* @brief 使用锁
|
||||
* @note 使用shell锁时,需要对加锁和解锁进行实现
|
||||
*/
|
||||
#define SHELL_USING_LOCK 1
|
||||
|
||||
/**
|
||||
* @brief shell内存分配
|
||||
* shell本身不需要此接口,若使用shell伴生对象,需要进行定义
|
||||
*/
|
||||
#define SHELL_MALLOC(size) pvPortMalloc(size)
|
||||
|
||||
/**
|
||||
* @brief shell内存释放
|
||||
* shell本身不需要此接口,若使用shell伴生对象,需要进行定义
|
||||
*/
|
||||
#define SHELL_FREE(obj) vPortFree(obj)
|
||||
|
||||
/**
|
||||
* @brief 是否显示shell信息
|
||||
*/
|
||||
#define SHELL_SHOW_INFO 1
|
||||
|
||||
/**
|
||||
* @brief 是否在登录后清除命令行
|
||||
*/
|
||||
#define SHELL_CLS_WHEN_LOGIN 1
|
||||
|
||||
/**
|
||||
* @brief shell默认用户
|
||||
*/
|
||||
#define SHELL_DEFAULT_USER "ziit"
|
||||
|
||||
/**
|
||||
* @brief shell默认用户密码
|
||||
* 若默认用户不需要密码,设为""
|
||||
*/
|
||||
#define SHELL_DEFAULT_USER_PASSWORD "ZIIT1234"
|
||||
|
||||
/**
|
||||
* @brief shell自动锁定超时
|
||||
* shell当前用户密码有效的时候生效,超时后会自动重新锁定shell
|
||||
* 设置为0时关闭自动锁定功能,时间单位为`SHELL_GET_TICK()`单位
|
||||
* @note 使用超时锁定必须保证`SHELL_GET_TICK()`有效
|
||||
*/
|
||||
#define SHELL_LOCK_TIMEOUT 5 * 60 * 1000
|
||||
|
||||
#endif
|
||||
|
||||
103
1.主程序源代码/User/shell/shell_cmd_list.c
Normal file
103
1.主程序源代码/User/shell/shell_cmd_list.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file shell_cmd_list.c
|
||||
* @author Letter (NevermindZZT@gmail.com)
|
||||
* @brief shell cmd list
|
||||
* @version 3.0.0
|
||||
* @date 2020-01-17
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
#if SHELL_USING_CMD_EXPORT != 1
|
||||
|
||||
extern int shellSetVar(char *name, int value);
|
||||
extern void shellUp(Shell *shell);
|
||||
extern void shellDown(Shell *shell);
|
||||
extern void shellRight(Shell *shell);
|
||||
extern void shellLeft(Shell *shell);
|
||||
extern void shellTab(Shell *shell);
|
||||
extern void shellBackspace(Shell *shell);
|
||||
extern void shellDelete(Shell *shell);
|
||||
extern void shellEnter(Shell *shell);
|
||||
extern void shellHelp(int argc, char *argv[]);
|
||||
extern void shellUsers(void);
|
||||
extern void shellCmds(void);
|
||||
extern void shellVars(void);
|
||||
extern void shellKeys(void);
|
||||
extern void shellClear(void);
|
||||
#if SHELL_EXEC_UNDEF_FUNC == 1
|
||||
extern int shellExecute(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
SHELL_AGENCY_FUNC(shellRun, shellGetCurrent(), (const char *)p1);
|
||||
|
||||
|
||||
/**
|
||||
* @brief shell命令表
|
||||
*
|
||||
*/
|
||||
const ShellCommand shellCommandList[] =
|
||||
{
|
||||
{.attr.value=SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_USER),
|
||||
.data.user.name = SHELL_DEFAULT_USER,
|
||||
.data.user.password = SHELL_DEFAULT_USER_PASSWORD,
|
||||
.data.user.desc = "default user"},
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
|
||||
setVar, shellSetVar, set var),
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x1B5B4100, shellUp, up),
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x1B5B4200, shellDown, down),
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
|
||||
0x1B5B4300, shellRight, right),
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
|
||||
0x1B5B4400, shellLeft, left),
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x09000000, shellTab, tab),
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
|
||||
0x08000000, shellBackspace, backspace),
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
|
||||
0x7F000000, shellDelete, delete),
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
|
||||
0x1B5B337E, shellDelete, delete),
|
||||
#if SHELL_ENTER_LF == 1
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
|
||||
0x0A000000, shellEnter, enter),
|
||||
#endif
|
||||
#if SHELL_ENTER_CR == 1
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
|
||||
0x0D000000, shellEnter, enter),
|
||||
#endif
|
||||
#if SHELL_ENTER_CRLF == 1
|
||||
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
|
||||
0x0D0A0000, shellEnter, enter),
|
||||
#endif
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
|
||||
help, shellHelp, show command info\r\nhelp [cmd]),
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
users, shellUsers, list all user),
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
cmds, shellCmds, list all cmd),
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
vars, shellVars, list all var),
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
keys, shellKeys, list all key),
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
clear, shellClear, clear console),
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
sh, SHELL_AGENCY_FUNC_NAME(shellRun), run command directly),
|
||||
#if SHELL_EXEC_UNDEF_FUNC == 1
|
||||
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
|
||||
exec, shellExecute, execute function undefined),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief shell命令表大小
|
||||
*
|
||||
*/
|
||||
const unsigned short shellCommandCount
|
||||
= sizeof(shellCommandList) / sizeof(ShellCommand);
|
||||
|
||||
#endif
|
||||
87
1.主程序源代码/User/shell/shell_companion.c
Normal file
87
1.主程序源代码/User/shell/shell_companion.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file shell_companion.c
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief shell companion object support
|
||||
* @version 3.0.3
|
||||
* @date 2020-07-22
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#include "shell.h"
|
||||
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
/**
|
||||
* @brief shell添加伴生对象
|
||||
*
|
||||
* @param shell shell对象
|
||||
* @param id 伴生对象ID
|
||||
* @param object 伴生对象
|
||||
* @return signed char 0 添加成功 -1 添加失败
|
||||
*/
|
||||
signed char shellCompanionAdd(Shell *shell, int id, void *object)
|
||||
{
|
||||
ShellCompanionObj *companions = shell->info.companions;
|
||||
ShellCompanionObj *node = SHELL_MALLOC(sizeof(ShellCompanionObj));
|
||||
SHELL_ASSERT(node, return -1);
|
||||
node->id = id;
|
||||
node->obj = object;
|
||||
node->next = companions;
|
||||
shell->info.companions = node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell删除伴生对象
|
||||
*
|
||||
* @param shell shell对象
|
||||
* @param id 伴生对象ID
|
||||
* @return signed char 0 删除成功 -1 无匹配对象
|
||||
*/
|
||||
signed char shellCompanionDel(Shell *shell, int id)
|
||||
{
|
||||
ShellCompanionObj *companions = shell->info.companions;
|
||||
ShellCompanionObj *front = companions;
|
||||
while (companions)
|
||||
{
|
||||
if (companions->id == id)
|
||||
{
|
||||
if (companions == shell->info.companions && !(companions->next))
|
||||
{
|
||||
shell->info.companions = (void *)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
front->next = companions->next;
|
||||
}
|
||||
SHELL_FREE(companions);
|
||||
return 0;
|
||||
}
|
||||
front = companions;
|
||||
companions = companions->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell获取伴生对象
|
||||
*
|
||||
* @param shell shell对象
|
||||
* @param id 伴生对象ID
|
||||
* @return void* 伴生对象,无匹配对象时返回NULL
|
||||
*/
|
||||
void *shellCompanionGet(Shell *shell, int id)
|
||||
{
|
||||
SHELL_ASSERT(shell, return (void *)0);
|
||||
ShellCompanionObj *companions = shell->info.companions;
|
||||
while (companions)
|
||||
{
|
||||
if (companions->id == id)
|
||||
{
|
||||
return companions->obj;
|
||||
}
|
||||
companions = companions->next;
|
||||
}
|
||||
return (void *)0;
|
||||
}
|
||||
#endif /** SHELL_USING_COMPANION == 1 */
|
||||
848
1.主程序源代码/User/shell/shell_ext.c
Normal file
848
1.主程序源代码/User/shell/shell_ext.c
Normal file
@@ -0,0 +1,848 @@
|
||||
/**
|
||||
* @file shell_ext.c
|
||||
* @author Letter (NevermindZZT@gmail.com)
|
||||
* @brief shell extensions
|
||||
* @version 3.0.0
|
||||
* @date 2019-12-31
|
||||
*
|
||||
* @copyright (c) 2019 Letter
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shell_cfg.h"
|
||||
#include "shell.h"
|
||||
#include "shell_ext.h"
|
||||
#include "string.h"
|
||||
|
||||
extern ShellCommand* shellSeekCommand(Shell *shell,
|
||||
const char *cmd,
|
||||
ShellCommand *base,
|
||||
unsigned short compareLength);
|
||||
extern int shellGetVarValue(Shell *shell, ShellCommand *command);
|
||||
|
||||
#if SHELL_SUPPORT_ARRAY_PARAM == 1
|
||||
extern int shellSplit(char *string, unsigned short strLen, char *array[], char splitKey, short maxNum);
|
||||
|
||||
static int shellExtParseArray(Shell *shell, char *string, char *type, size_t *result);
|
||||
static int shellExtCleanerArray(Shell *shell, char *type, void *param);
|
||||
#endif /** SHELL_SUPPORT_ARRAY_PARAM == 1 */
|
||||
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
/**
|
||||
* @brief 获取下一个参数类型
|
||||
*
|
||||
* @param signature 函数签名
|
||||
* @param index 参数遍历在签名中的起始索引
|
||||
* @param type 获取到的参数类型
|
||||
*
|
||||
* @return int 下一个参数在签名中的索引
|
||||
*/
|
||||
static int shellGetNextParamType(const char *signature, int index, char *type)
|
||||
{
|
||||
const char *p = signature + index;
|
||||
#if SHELL_SUPPORT_ARRAY_PARAM == 1
|
||||
if (*p == '[')
|
||||
{
|
||||
*type++ = *p++;
|
||||
index++;
|
||||
}
|
||||
#endif /** SHELL_SUPPORT_ARRAY_PARAM == 1 */
|
||||
if (*p == 'L')
|
||||
{
|
||||
while (*p != ';' && *p != 0)
|
||||
{
|
||||
*type++ = *p++;
|
||||
index++;
|
||||
}
|
||||
*type++ = *p++;
|
||||
index++;
|
||||
}
|
||||
else if (*p != 0)
|
||||
{
|
||||
*type++ = *p;
|
||||
index++;
|
||||
}
|
||||
*type = '\0';
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取期待的参数个数
|
||||
*
|
||||
* @param signature 函数签名
|
||||
*
|
||||
* @return int 参数个数
|
||||
*/
|
||||
static int shellGetParamNumExcept(const char *signature)
|
||||
{
|
||||
int num = 0;
|
||||
const char *p = signature;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
#if SHELL_SUPPORT_ARRAY_PARAM == 1
|
||||
if (*p == '[')
|
||||
{
|
||||
p++;
|
||||
}
|
||||
#endif /** SHELL_SUPPORT_ARRAY_PARAM == 1 */
|
||||
if (*p == 'L')
|
||||
{
|
||||
while (*p != ';' && *p != 0)
|
||||
{
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
else
|
||||
{
|
||||
p++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 判断数字进制
|
||||
*
|
||||
* @param string 参数字符串
|
||||
* @return ShellNumType 进制
|
||||
*/
|
||||
static ShellNumType shellExtNumType(char *string)
|
||||
{
|
||||
char *p = string;
|
||||
ShellNumType type = NUM_TYPE_DEC;
|
||||
|
||||
if ((*p == '0') && ((*(p + 1) == 'x') || (*(p + 1) == 'X')))
|
||||
{
|
||||
type = NUM_TYPE_HEX;
|
||||
}
|
||||
else if ((*p == '0') && ((*(p + 1) == 'b') || (*(p + 1) == 'B')))
|
||||
{
|
||||
type = NUM_TYPE_BIN;
|
||||
}
|
||||
else if (*p == '0')
|
||||
{
|
||||
type = NUM_TYPE_OCT;
|
||||
}
|
||||
|
||||
while (*p++)
|
||||
{
|
||||
if (*p == '.' && *(p + 1) != 0)
|
||||
{
|
||||
type = NUM_TYPE_FLOAT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 字符转数字
|
||||
*
|
||||
* @param code 字符
|
||||
* @return char 数字
|
||||
*/
|
||||
static char shellExtToNum(char code)
|
||||
{
|
||||
if ((code >= '0') && (code <= '9'))
|
||||
{
|
||||
return code -'0';
|
||||
}
|
||||
else if ((code >= 'a') && (code <= 'f'))
|
||||
{
|
||||
return code - 'a' + 10;
|
||||
}
|
||||
else if ((code >= 'A') && (code <= 'F'))
|
||||
{
|
||||
return code - 'A' + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 解析字符参数
|
||||
*
|
||||
* @param string 字符串参数
|
||||
* @return char 解析出的字符
|
||||
*/
|
||||
static char shellExtParseChar(char *string)
|
||||
{
|
||||
char *p = (*string == '\'') ? (string + 1) : string;
|
||||
char value = 0;
|
||||
|
||||
if (*p == '\\')
|
||||
{
|
||||
switch (*(p + 1))
|
||||
{
|
||||
case 'b':
|
||||
value = '\b';
|
||||
break;
|
||||
case 'r':
|
||||
value = '\r';
|
||||
break;
|
||||
case 'n':
|
||||
value = '\n';
|
||||
break;
|
||||
case 't':
|
||||
value = '\t';
|
||||
break;
|
||||
case '0':
|
||||
value = 0;
|
||||
break;
|
||||
default:
|
||||
value = *(p + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = *p;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 解析字符串参数
|
||||
*
|
||||
* @param string 字符串参数
|
||||
* @return char* 解析出的字符串
|
||||
*/
|
||||
static char* shellExtParseString(char *string)
|
||||
{
|
||||
char *p = string;
|
||||
unsigned short index = 0;
|
||||
|
||||
if (*string == '\"')
|
||||
{
|
||||
p = ++string;
|
||||
}
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '\\')
|
||||
{
|
||||
*(string + index) = shellExtParseChar(p);
|
||||
p++;
|
||||
}
|
||||
else if (*p == '\"')
|
||||
{
|
||||
*(string + index) = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(string + index) = *p;
|
||||
}
|
||||
p++;
|
||||
index ++;
|
||||
}
|
||||
*(string + index) = 0;
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 解析数字参数
|
||||
*
|
||||
* @param string 字符串参数
|
||||
* @return size_t 解析出的数字
|
||||
*/
|
||||
static size_t shellExtParseNumber(char *string)
|
||||
{
|
||||
ShellNumType type = NUM_TYPE_DEC;
|
||||
char radix = 10;
|
||||
char *p = string;
|
||||
char offset = 0;
|
||||
signed char sign = 1;
|
||||
size_t valueInt = 0;
|
||||
float valueFloat = 0.0;
|
||||
size_t devide = 0;
|
||||
|
||||
if (*string == '-')
|
||||
{
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
type = shellExtNumType(string + ((sign == -1) ? 1 : 0));
|
||||
|
||||
switch ((char)type)
|
||||
{
|
||||
case NUM_TYPE_HEX:
|
||||
radix = 16;
|
||||
offset = 2;
|
||||
break;
|
||||
|
||||
case NUM_TYPE_OCT:
|
||||
radix = 8;
|
||||
offset = 1;
|
||||
break;
|
||||
|
||||
case NUM_TYPE_BIN:
|
||||
radix = 2;
|
||||
offset = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
p = string + offset + ((sign == -1) ? 1 : 0);
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '.')
|
||||
{
|
||||
devide = 1;
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
valueInt = valueInt * radix + shellExtToNum(*p);
|
||||
devide *= 10;
|
||||
p++;
|
||||
}
|
||||
if (type == NUM_TYPE_FLOAT && devide != 0)
|
||||
{
|
||||
valueFloat = (float)valueInt / devide * sign;
|
||||
return *(size_t *)(&valueFloat);
|
||||
}
|
||||
else
|
||||
{
|
||||
return valueInt * sign;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 解析变量参数
|
||||
*
|
||||
* @param shell shell对象
|
||||
* @param var 变量
|
||||
* @param result 解析结果
|
||||
*
|
||||
* @return int 0 解析成功 --1 解析失败
|
||||
*/
|
||||
static int shellExtParseVar(Shell *shell, char *var, size_t *result)
|
||||
{
|
||||
ShellCommand *command = shellSeekCommand(shell,
|
||||
var + 1,
|
||||
shell->commandList.base,
|
||||
0);
|
||||
if (command)
|
||||
{
|
||||
*result = shellGetVarValue(shell, command);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 解析参数
|
||||
*
|
||||
* @param shell shell对象
|
||||
* @param string 参数
|
||||
* @param type 参数类型
|
||||
* @param result 解析结果
|
||||
*
|
||||
* @return int 0 解析成功 --1 解析失败
|
||||
*/
|
||||
int shellExtParsePara(Shell *shell, char *string, char *type, size_t *result)
|
||||
{
|
||||
if (type == NULL || (*string == '$' && *(string + 1)))
|
||||
{
|
||||
if (*string == '\'' && *(string + 1))
|
||||
{
|
||||
*result = (size_t)shellExtParseChar(string);
|
||||
return 0;
|
||||
}
|
||||
else if (*string == '-' || (*string >= '0' && *string <= '9'))
|
||||
{
|
||||
*result = shellExtParseNumber(string);
|
||||
return 0;
|
||||
}
|
||||
else if (*string == '$' && *(string + 1))
|
||||
{
|
||||
return shellExtParseVar(shell, string, result);
|
||||
}
|
||||
else if (*string)
|
||||
{
|
||||
*result = (size_t)shellExtParseString(string);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
else
|
||||
{
|
||||
if (*string == '$' && *(string + 1))
|
||||
{
|
||||
return shellExtParseVar(shell, string, result);
|
||||
}
|
||||
#if SHELL_SUPPORT_ARRAY_PARAM == 1
|
||||
else if (type[0] == '[')
|
||||
{
|
||||
return shellExtParseArray(shell, string, type, result);
|
||||
}
|
||||
#endif /** SHELL_SUPPORT_ARRAY_PARAM == 1 */
|
||||
else if (strcmp("c", type) == 0)
|
||||
{
|
||||
*result = (size_t)shellExtParseChar(string);
|
||||
return 0;
|
||||
}
|
||||
else if (strcmp("q", type) == 0
|
||||
|| strcmp("h", type) == 0
|
||||
|| strcmp("i", type) == 0
|
||||
|| strcmp("f", type) == 0
|
||||
|| strcmp("p", type) == 0)
|
||||
{
|
||||
*result = shellExtParseNumber(string);
|
||||
return 0;
|
||||
}
|
||||
else if (strcmp("s", type) == 0)
|
||||
{
|
||||
*result = (size_t)shellExtParseString(string);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShellCommand *command = shellSeekCommand(shell,
|
||||
type,
|
||||
shell->commandList.base,
|
||||
0);
|
||||
if (command != NULL)
|
||||
{
|
||||
void *param;
|
||||
if (command->data.paramParser.parser(shellExtParseString(string), ¶m) == 0)
|
||||
{
|
||||
*result = (size_t)param;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
shellWriteString(shell, "Parse param for type: ");
|
||||
shellWriteString(shell, type);
|
||||
shellWriteString(shell, " failed\r\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shellWriteString(shell, "Can't find the param parser for type: ");
|
||||
shellWriteString(shell, type);
|
||||
shellWriteString(shell, "\r\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
/**
|
||||
* @brief 清理参数
|
||||
*
|
||||
* @param shell shell
|
||||
* @param type 参数类型
|
||||
* @param param 参数
|
||||
*
|
||||
* @return int 0 清理成功 -1 清理失败
|
||||
*/
|
||||
int shellExtCleanerPara(Shell *shell, char *type, size_t param)
|
||||
{
|
||||
if (type == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if SHELL_SUPPORT_ARRAY_PARAM == 1
|
||||
if (type[0] == '[') {
|
||||
return shellExtCleanerArray(shell, type, (void *) param);
|
||||
}
|
||||
else
|
||||
#endif /** SHELL_SUPPORT_ARRAY_PARAM == 1 */
|
||||
if (strcmp("c", type) == 0
|
||||
|| strcmp("q", type) == 0
|
||||
|| strcmp("h", type) == 0
|
||||
|| strcmp("i", type) == 0
|
||||
|| strcmp("f", type) == 0
|
||||
|| strcmp("p", type) == 0
|
||||
|| strcmp("s", type) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShellCommand *command = shellSeekCommand(shell,
|
||||
type,
|
||||
shell->commandList.base,
|
||||
0);
|
||||
if (command != NULL && command->data.paramParser.cleaner != NULL)
|
||||
{
|
||||
return command->data.paramParser.cleaner((void *)param);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
|
||||
#if SHELL_SUPPORT_ARRAY_PARAM == 1
|
||||
/**
|
||||
* @brief 估算数组长度
|
||||
*
|
||||
* @param string 数组参数
|
||||
*
|
||||
* @return int 估算的数组长度
|
||||
*/
|
||||
static int shellEstimateArrayLength(char *string)
|
||||
{
|
||||
int length = 0;
|
||||
char *p = string;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == ',')
|
||||
{
|
||||
length++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return length + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 分割数组参数
|
||||
*
|
||||
* @param string 数组参数
|
||||
* @param array 分割后的字符串数组
|
||||
*
|
||||
* @return int 数组长度
|
||||
*/
|
||||
static int shellSplitArray(char *string, char ***array)
|
||||
{
|
||||
int strLen = strlen(string);
|
||||
if (string[strLen - 1] == ']')
|
||||
{
|
||||
string[--strLen] = 0;
|
||||
}
|
||||
if (string[0] == '[')
|
||||
{
|
||||
--strLen;
|
||||
string++;
|
||||
}
|
||||
int size = shellEstimateArrayLength(string);
|
||||
*array = SHELL_MALLOC(size * sizeof(char *));
|
||||
return shellSplit(string, strLen, *array, ',', size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解析数组参数
|
||||
*
|
||||
* @param shell shell 对象
|
||||
* @param string 数组参数
|
||||
* @param type 参数类型
|
||||
* @param result 解析结果
|
||||
*
|
||||
* @return int 0 解析成功 -1 解析失败
|
||||
*/
|
||||
static int shellExtParseArray(Shell *shell, char *string, char *type, size_t *result)
|
||||
{
|
||||
char **params;
|
||||
int size = shellSplitArray(string, ¶ms);
|
||||
int elementBytes = sizeof(void *);
|
||||
|
||||
if (strcmp(type + 1, "q") == 0)
|
||||
{
|
||||
elementBytes = sizeof(char);
|
||||
}
|
||||
else if (strcmp(type + 1, "h") == 0)
|
||||
{
|
||||
elementBytes = sizeof(short);
|
||||
}
|
||||
else if (strcmp(type + 1, "i") == 0)
|
||||
{
|
||||
elementBytes = sizeof(int);
|
||||
}
|
||||
|
||||
ShellArrayHeader *header = SHELL_MALLOC(elementBytes * size + sizeof(ShellArrayHeader));
|
||||
*result = (size_t) ((size_t) header + sizeof(ShellArrayHeader));
|
||||
header->size = size;
|
||||
header->elementBytes = elementBytes;
|
||||
for (short i = 0; i < size; i++)
|
||||
{
|
||||
size_t value;
|
||||
if (shellExtParsePara(shell, params[i], type + 1, &value) != 0)
|
||||
{
|
||||
SHELL_FREE(header);
|
||||
SHELL_FREE(params);
|
||||
return -1;
|
||||
}
|
||||
memcpy((void *) ((size_t) *result + elementBytes * i), &value, elementBytes);
|
||||
}
|
||||
|
||||
SHELL_FREE(params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清理数组参数
|
||||
*
|
||||
* @param shell shell 对象
|
||||
* @param type 参数类型
|
||||
* @param param 参数
|
||||
*
|
||||
* @return int 0 清理成功 -1 清理失败
|
||||
*/
|
||||
static int shellExtCleanerArray(Shell *shell, char *type, void *param)
|
||||
{
|
||||
ShellArrayHeader *header = (ShellArrayHeader *) ((size_t) param - sizeof(ShellArrayHeader));
|
||||
for (short i = 0; i < header->size; i++)
|
||||
{
|
||||
if (shellExtCleanerPara(shell, type + 1, *(size_t *) ((size_t) param + header->elementBytes * i)) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
SHELL_FREE(header);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取数组大小
|
||||
*
|
||||
* @param param 数组
|
||||
*
|
||||
* @return int 数组大小
|
||||
*/
|
||||
int shellGetArrayParamSize(void *param)
|
||||
{
|
||||
ShellArrayHeader *header = (ShellArrayHeader *) ((size_t) param - sizeof(ShellArrayHeader));
|
||||
return header->size;
|
||||
}
|
||||
#endif /** SHELL_SUPPORT_ARRAY_PARAM == 1 */
|
||||
|
||||
|
||||
/**
|
||||
* @brief 执行命令
|
||||
*
|
||||
* @param shell shell对象
|
||||
* @param command 命令
|
||||
* @param argc 参数个数
|
||||
* @param argv 参数
|
||||
* @return int 返回值
|
||||
*/
|
||||
int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
size_t params[SHELL_PARAMETER_MAX_NUMBER] = {0};
|
||||
int paramNum = command->attr.attrs.paramNum > (argc - 1) ?
|
||||
command->attr.attrs.paramNum : (argc - 1);
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
char type[16];
|
||||
int index = 0;
|
||||
|
||||
if (command->data.cmd.signature != NULL)
|
||||
{
|
||||
int except = shellGetParamNumExcept(command->data.cmd.signature);
|
||||
if (except != argc - 1)
|
||||
{
|
||||
shellWriteString(shell, "Parameters number incorrect\r\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (int i = 0; i < argc - 1; i++)
|
||||
{
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
if (command->data.cmd.signature != NULL) {
|
||||
index = shellGetNextParamType(command->data.cmd.signature, index, type);
|
||||
if (shellExtParsePara(shell, argv[i + 1], type, ¶ms[i]) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
{
|
||||
if (shellExtParsePara(shell, argv[i + 1], NULL, ¶ms[i]) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (paramNum)
|
||||
{
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 1
|
||||
case 0:
|
||||
ret = command->data.cmd.function();
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 1 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 2
|
||||
case 1:
|
||||
{
|
||||
int (*func)(size_t) = command->data.cmd.function;
|
||||
ret = func(params[0]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 2 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 3
|
||||
case 2:
|
||||
{
|
||||
int (*func)(size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 3 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 4
|
||||
case 3:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 4 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 5
|
||||
case 4:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 5 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 6
|
||||
case 5:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 6 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 7
|
||||
case 6:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 7 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 8
|
||||
case 7:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 8 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 9
|
||||
case 8:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t)
|
||||
= command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 9 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 10
|
||||
case 9:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
|
||||
size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7],
|
||||
params[8]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 10 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 11
|
||||
case 10:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
|
||||
size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7],
|
||||
params[8], params[9]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 11 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 12
|
||||
case 11:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
|
||||
size_t, size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7],
|
||||
params[8], params[9], params[10]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 12 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 13
|
||||
case 12:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
|
||||
size_t, size_t, size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7],
|
||||
params[8], params[9], params[10], params[11]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 13 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 14
|
||||
case 13:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
|
||||
size_t, size_t, size_t, size_t, size_t) = command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7],
|
||||
params[8], params[9], params[10], params[11], params[12]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 14 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 15
|
||||
case 14:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
|
||||
size_t, size_t, size_t, size_t, size_t, size_t)
|
||||
= command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7],
|
||||
params[8], params[9], params[10], params[11], params[12], params[13]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 15 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 16
|
||||
case 15:
|
||||
{
|
||||
int (*func)(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
|
||||
size_t, size_t, size_t, size_t, size_t, size_t, size_t)
|
||||
= command->data.cmd.function;
|
||||
ret = func(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7],
|
||||
params[8], params[9], params[10], params[11], params[12], params[13], params[14]);
|
||||
break;
|
||||
}
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 16 */
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
if (command->data.cmd.signature != NULL) {
|
||||
index = 0;
|
||||
for (int i = 0; i < argc - 1; i++)
|
||||
{
|
||||
index = shellGetNextParamType(command->data.cmd.signature, index, type);
|
||||
shellExtCleanerPara(shell, type, params[i]);
|
||||
}
|
||||
}
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
47
1.主程序源代码/User/shell/shell_ext.h
Normal file
47
1.主程序源代码/User/shell/shell_ext.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file shell_ext.h
|
||||
* @author Letter (NevermindZZT@gmail.com)
|
||||
* @brief shell extensions
|
||||
* @version 3.0.0
|
||||
* @date 2019-12-31
|
||||
*
|
||||
* @copyright (c) 2019 Letter
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_EXT_H__
|
||||
#define __SHELL_EXT_H__
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
/**
|
||||
* @brief 数字类型
|
||||
*
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NUM_TYPE_DEC, /**< 十进制整型 */
|
||||
NUM_TYPE_BIN, /**< 二进制整型 */
|
||||
NUM_TYPE_OCT, /**< 八进制整型 */
|
||||
NUM_TYPE_HEX, /**< 十六进制整型 */
|
||||
NUM_TYPE_FLOAT /**< 浮点型 */
|
||||
} ShellNumType;
|
||||
|
||||
#if SHELL_SUPPORT_ARRAY_PARAM == 1
|
||||
typedef struct
|
||||
{
|
||||
unsigned short size;
|
||||
unsigned char elementBytes;
|
||||
} ShellArrayHeader;
|
||||
#endif /** SHELL_SUPPORT_ARRAY_PARAM == 1 */
|
||||
|
||||
int shellExtParsePara(Shell *shell, char *string, char *type, size_t *result);
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
int shellExtCleanerPara(Shell *shell, char *type, size_t param);
|
||||
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
|
||||
#if SHELL_SUPPORT_ARRAY_PARAM == 1
|
||||
int shellGetArrayParamSize(void *param);
|
||||
#endif /** SHELL_SUPPORT_ARRAY_PARAM == 1 */
|
||||
int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[]);
|
||||
|
||||
#endif
|
||||
121
1.主程序源代码/User/shell/shell_port.c
Normal file
121
1.主程序源代码/User/shell/shell_port.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @file shell_port.c
|
||||
* @author Letter (NevermindZZT@gmail.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2019-02-22
|
||||
*
|
||||
* @copyright (c) 2019 Letter
|
||||
*
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "shell.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
#include "stm32f10x.h"
|
||||
#include "bsp_usart.h"
|
||||
#include "string.h"
|
||||
|
||||
Shell shell;
|
||||
char shellBuffer[512];
|
||||
|
||||
static SemaphoreHandle_t shellMutex;
|
||||
|
||||
/**
|
||||
* @brief 用户shell写
|
||||
*
|
||||
* @param data 数据
|
||||
* @param len 数据长度
|
||||
*
|
||||
* @return short 实际写入的数据长度
|
||||
*/
|
||||
short userShellWrite(char *data, unsigned short len)
|
||||
{
|
||||
Usart_SendString(USART1,data);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 用户shell读
|
||||
*
|
||||
* @param data 数据
|
||||
* @param len 数据长度
|
||||
*
|
||||
* @return short 实际读取到
|
||||
*/
|
||||
/* 自定义接口函数 */
|
||||
extern uint8_t g_debugRxBuf[];
|
||||
extern uint8_t g_debugRxFlag;
|
||||
extern uint16_t g_debugRxLen;
|
||||
|
||||
void userShellRun(void)
|
||||
{
|
||||
if(g_debugRxFlag)
|
||||
{
|
||||
for(uint8_t i=0;i<=g_debugRxLen;i++)
|
||||
{
|
||||
shellHandler(&shell,g_debugRxBuf[i]);
|
||||
}
|
||||
g_debugRxLen = 0;
|
||||
g_debugRxFlag = 0;
|
||||
memset(g_debugRxBuf,0x00,255);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
short userShellRead(char *data, unsigned short len)
|
||||
{
|
||||
userShellRun();
|
||||
vTaskDelay(20);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 用户shell上锁
|
||||
*
|
||||
* @param shell shell
|
||||
*
|
||||
* @return int 0
|
||||
*/
|
||||
int userShellLock(Shell *shell)
|
||||
{
|
||||
xSemaphoreTake(shellMutex, portMAX_DELAY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 用户shell解锁
|
||||
*
|
||||
* @param shell shell
|
||||
*
|
||||
* @return int 0
|
||||
*/
|
||||
int userShellUnlock(Shell *shell)
|
||||
{
|
||||
xSemaphoreGive(shellMutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 用户shell初始化
|
||||
*
|
||||
*/
|
||||
void userShellInit(void)
|
||||
{
|
||||
shellMutex = xSemaphoreCreateMutex();
|
||||
|
||||
shell.write = userShellWrite;
|
||||
shell.read = userShellRead;
|
||||
shell.lock = userShellLock;
|
||||
shell.unlock = userShellUnlock;
|
||||
shellInit(&shell, shellBuffer, 512);
|
||||
if (xTaskCreate(shellTask, "shell", 256, &shell, 5, NULL) != pdPASS)
|
||||
{
|
||||
printf("shell task creat failed");
|
||||
}
|
||||
}
|
||||
|
||||
21
1.主程序源代码/User/shell/shell_port.h
Normal file
21
1.主程序源代码/User/shell/shell_port.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @file shell_port.h
|
||||
* @author Letter (NevermindZZT@gmail.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2019-02-22
|
||||
*
|
||||
* @copyright (c) 2019 Letter
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_PORT_H__
|
||||
#define __SHELL_PORT_H__
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
extern Shell shell;
|
||||
|
||||
void userShellInit(void);
|
||||
void userShellRun(void);
|
||||
#endif
|
||||
265
1.主程序源代码/User/src/bsp_bat.c
Normal file
265
1.主程序源代码/User/src/bsp_bat.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* @Date: 2025-06-26 16:58:50
|
||||
* @LastEditors: 路怀帅
|
||||
* @LastEditTime: 2025-07-04 17:07:40
|
||||
* @FilePath: \RVMDK(uv5)e:\个人项目\零距电子\安灯遥控器\Andon_Remote_Control\Andon_RTOS\User\src\bsp_bat.c
|
||||
*/
|
||||
#include "main.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#include "task.h"
|
||||
static void BAT_Init(void);
|
||||
static uint8_t BAT_State_Read(void);
|
||||
|
||||
BATClassStruct BATClass = {
|
||||
.Init = BAT_Init,
|
||||
.Read_State = BAT_State_Read};
|
||||
|
||||
static void BAT_Init()
|
||||
{
|
||||
/*电池检测IO初始化*/
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
}
|
||||
|
||||
int cont = 0;
|
||||
static uint8_t BAT_State_Read()
|
||||
{
|
||||
cont++;
|
||||
uint8_t isCharging, batteryLevel;
|
||||
batteryLevel = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2);
|
||||
isCharging = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4);
|
||||
|
||||
if ((isCharging == 0) && (batteryLevel == 1))
|
||||
{
|
||||
if (cont >= 30)
|
||||
{
|
||||
GPIOB->BSRR = ((GPIOB->ODR & GPIO_Pin_0) << 16) | (~GPIOB->ODR & GPIO_Pin_0);
|
||||
cont = 0;
|
||||
}
|
||||
}
|
||||
else if ((isCharging == 1) && (batteryLevel == 0))
|
||||
{
|
||||
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
GPIO_SetBits(GPIOB, GPIO_Pin_0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Power_button_init()
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
}
|
||||
|
||||
uint8_t Check_Power_buttun()
|
||||
{
|
||||
|
||||
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)
|
||||
{
|
||||
delay_ms(30);
|
||||
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)
|
||||
return 0;
|
||||
}
|
||||
else if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1)
|
||||
{
|
||||
delay_ms(30);
|
||||
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ADC1_Init(void);
|
||||
static uint16_t getADC1Value(uint8_t ADC_channelx);
|
||||
|
||||
ADC1ClassStruct ADC1Class = {
|
||||
.Init = ADC1_Init,
|
||||
.GetValue = getADC1Value};
|
||||
|
||||
#define ADC1_DMA_CHANNEL DMA1_Channel1
|
||||
#define ADC1_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
|
||||
#define ADC1_CLK RCC_APB2Periph_ADC1
|
||||
|
||||
#define ADC1_A0_A7_GPIO_PORT GPIOA
|
||||
#define ADC1_A0_A7_GPIO_CLK RCC_APB2Periph_GPIOA
|
||||
#define ADC1_A0_GPIO_PIN GPIO_Pin_0
|
||||
#define ADC1_A1_GPIO_PIN GPIO_Pin_1
|
||||
#define ADC1_A2_GPIO_PIN GPIO_Pin_2
|
||||
#define ADC1_A3_GPIO_PIN GPIO_Pin_3
|
||||
#define ADC1_A4_GPIO_PIN GPIO_Pin_4
|
||||
#define ADC1_A5_GPIO_PIN GPIO_Pin_5
|
||||
#define ADC1_A6_GPIO_PIN GPIO_Pin_6
|
||||
#define ADC1_A7_GPIO_PIN GPIO_Pin_7
|
||||
#define ADC1_B0_B1_GPIO_PORT GPIOB
|
||||
#define ADC1_B0_B1_GPIO_CLK RCC_APB2Periph_GPIOB
|
||||
#define ADC1_B0_GPIO_PIN GPIO_Pin_0
|
||||
#define ADC1_B1_GPIO_PIN GPIO_Pin_1
|
||||
|
||||
#define ADC1_A0_CHANNEL ADC_Channel_0
|
||||
#define ADC1_A1_CHANNEL ADC_Channel_1
|
||||
#define ADC1_A2_CHANNEL ADC_Channel_2
|
||||
#define ADC1_A3_CHANNEL ADC_Channel_3
|
||||
#define ADC1_A4_CHANNEL ADC_Channel_4
|
||||
#define ADC1_A5_CHANNEL ADC_Channel_5
|
||||
#define ADC1_A6_CHANNEL ADC_Channel_6
|
||||
#define ADC1_A7_CHANNEL ADC_Channel_7
|
||||
#define ADC1_B0_CHANNEL ADC_Channel_8
|
||||
#define ADC1_B1_CHANNEL ADC_Channel_9
|
||||
|
||||
__IO uint16_t ADC_ConvertedValue[10] = {0};
|
||||
|
||||
/**
|
||||
* @brief ADC1初始化
|
||||
* @param None
|
||||
* @retval None
|
||||
* @note None
|
||||
*/
|
||||
static void ADC1_Init(void)
|
||||
{
|
||||
/*定义一个GPIO_InitTypeDef类型的结构体*/
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
ADC_InitTypeDef ADC_InitStructure;
|
||||
DMA_InitTypeDef DMA_InitStructure;
|
||||
|
||||
RCC_APB2PeriphClockCmd(ADC1_A0_A7_GPIO_CLK, ENABLE);
|
||||
/***************************************************************/
|
||||
// 1. 修改为所使用的引脚
|
||||
GPIO_InitStructure.GPIO_Pin = ADC1_A5_GPIO_PIN;
|
||||
/***************************************************************/
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
|
||||
GPIO_Init(ADC1_A0_A7_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
// 打开DMA时钟
|
||||
RCC_AHBPeriphClockCmd(ADC1_DMA_CLK, ENABLE);
|
||||
// 打开ADC时钟
|
||||
RCC_APB2PeriphClockCmd(ADC1_CLK, ENABLE);
|
||||
// 复位DMA控制器
|
||||
DMA_DeInit(ADC1_DMA_CHANNEL);
|
||||
// 配置 DMA 初始化结构体
|
||||
// 外设基址为:ADC 数据寄存器地址
|
||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(ADC1->DR));
|
||||
// 存储器地址
|
||||
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;
|
||||
// 数据源来自外设
|
||||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
|
||||
/***************************************************************/
|
||||
// 2.缓存数量 使用1个ADC引脚就是1 使用2个ADC引脚就是2
|
||||
DMA_InitStructure.DMA_BufferSize = 1;
|
||||
/***************************************************************/
|
||||
// 外设寄存器只有一个,地址不用递增
|
||||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
// 存储器地址递增
|
||||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
// 外设数据大小为半字,即两个字节
|
||||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
|
||||
// 内存数据大小也为半字,跟外设数据大小相同
|
||||
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
|
||||
// 循环传输模式
|
||||
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
|
||||
// DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
|
||||
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
||||
// 禁止存储器到存储器模式,因为是从外设到存储器
|
||||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||||
// 初始化DMA
|
||||
DMA_Init(ADC1_DMA_CHANNEL, &DMA_InitStructure);
|
||||
// 使能 DMA 通道
|
||||
DMA_Cmd(ADC1_DMA_CHANNEL, ENABLE);
|
||||
|
||||
// ADC 模式配置
|
||||
// 只使用一个ADC,属于单模式
|
||||
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
|
||||
// 扫描模式
|
||||
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
|
||||
// 连续转换模式
|
||||
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
|
||||
// 不用外部触发转换,软件开启即可
|
||||
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
|
||||
// 转换结果右对齐
|
||||
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
|
||||
/***************************************************************/
|
||||
// 3.转换通道个数 使用1个ADC引脚就是1 使用2个ADC引脚就是2
|
||||
ADC_InitStructure.ADC_NbrOfChannel = 1;
|
||||
/***************************************************************/
|
||||
// 初始化ADC
|
||||
ADC_Init(ADC1, &ADC_InitStructure);
|
||||
// 配置ADC时钟N狿CLK2的8分频,即9MHz
|
||||
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
|
||||
/***************************************************************/
|
||||
// 4.配置ADC通道的转换顺序和采样时间 将所使用的所有引脚按自定义顺序填写
|
||||
ADC_RegularChannelConfig(ADC1, ADC1_A5_CHANNEL, 1, ADC_SampleTime_55Cycles5);
|
||||
// ADC_RegularChannelConfig(ADC1, ADC1_A2_CHANNEL, 2, ADC_SampleTime_55Cycles5);
|
||||
/***************************************************************/
|
||||
// 使能ADC DMA 请求
|
||||
ADC_DMACmd(ADC1, ENABLE);
|
||||
// 开启ADC ,并开始转换
|
||||
ADC_Cmd(ADC1, ENABLE);
|
||||
// 初始化ADC 校准寄存器
|
||||
ADC_ResetCalibration(ADC1);
|
||||
// 等待校准寄存器初始化完成
|
||||
while (ADC_GetResetCalibrationStatus(ADC1))
|
||||
;
|
||||
// ADC开始校准
|
||||
ADC_StartCalibration(ADC1);
|
||||
// 等待校准完成
|
||||
while (ADC_GetCalibrationStatus(ADC1))
|
||||
;
|
||||
// 由于没有采用外部触发,所以使用软件触发ADC转换
|
||||
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
|
||||
}
|
||||
/* 0-9对应第四步中的ADC引脚通道顺序 例如顺序为ADC1_A3 ADC1_A4 则A3引脚对应0 A4引脚对应1*/
|
||||
static uint16_t getADC1Value(uint8_t ADC_channelx)
|
||||
{
|
||||
uint16_t ADCTemp = 0;
|
||||
switch (ADC_channelx)
|
||||
{
|
||||
case 0:
|
||||
ADCTemp = (float)ADC_ConvertedValue[0] * 3.3 * 100 / 4096;
|
||||
break;
|
||||
case 1:
|
||||
ADCTemp = (float)ADC_ConvertedValue[1] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
case 2:
|
||||
ADCTemp = (float)ADC_ConvertedValue[2] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
case 3:
|
||||
ADCTemp = (float)ADC_ConvertedValue[3] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
case 4:
|
||||
ADCTemp = (float)ADC_ConvertedValue[4] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
case 5:
|
||||
ADCTemp = (float)ADC_ConvertedValue[5] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
case 6:
|
||||
ADCTemp = (float)ADC_ConvertedValue[6] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
case 7:
|
||||
ADCTemp = (float)ADC_ConvertedValue[7] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
case 8:
|
||||
ADCTemp = (float)ADC_ConvertedValue[8] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
case 9:
|
||||
ADCTemp = (float)ADC_ConvertedValue[9] / 4096 * 3.3 * 100;
|
||||
break;
|
||||
}
|
||||
return ADCTemp;
|
||||
}
|
||||
459
1.主程序源代码/User/src/bsp_button.c
Normal file
459
1.主程序源代码/User/src/bsp_button.c
Normal file
@@ -0,0 +1,459 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#include "task.h"
|
||||
#include "main.h"
|
||||
|
||||
#define KEY_ENABLED(bit) ((rc_data()->Kv_get.key_en_table & (1 << (bit - 1))) != 0)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
S1_BUTTON = 0,
|
||||
S2_BUTTON,
|
||||
S3_BUTTON,
|
||||
S4_BUTTON,
|
||||
S5_BUTTON,
|
||||
S6_BUTTON,
|
||||
S7_BUTTON,
|
||||
S8_BUTTON,
|
||||
S9_BUTTON,
|
||||
S10_BUTTON,
|
||||
S11_BUTTON,
|
||||
S12_BUTTON,
|
||||
BUTTON_MAX
|
||||
} user_button_t;
|
||||
|
||||
static flex_button_t user_button[BUTTON_MAX];
|
||||
|
||||
/**
|
||||
*@brief 按键1回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_1_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
rc_data()->Lock_state = !rc_data()->Lock_state;
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
LEDClass.Set(BLACK);
|
||||
rc_data()->isLEDTog = DISABLE;
|
||||
rc_data()->isSend = DISABLE;
|
||||
ASR_Power_OFF;
|
||||
rc_data()->Asr_state = LOCK;
|
||||
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
BOARD_Power_OFF;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*@brief 按键2回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_2_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(2))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->Key_data[1] = 1;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
}
|
||||
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*@brief 按键3回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_3_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(3))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
rc_data()->Key_data[0] = 3;
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@brief 按键4回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_4_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(4))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
rc_data()->Key_data[0] = 4;
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*@brief 按键5回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_5_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(5))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
rc_data()->Key_data[0] = 5;
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@brief 按键6回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_6_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(6))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
rc_data()->Key_data[0] = 6;
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@brief 按键7回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_7_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(7))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
rc_data()->Key_data[0] = 7;
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@brief 按键8回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_8_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(8))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
rc_data()->Key_data[0] = 8;
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@brief 按键9回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_9_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(9))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
rc_data()->Key_data[2] = 1;
|
||||
rc_data()->Key_data[3] = 0;
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@brief 按键10回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_10_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(10))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isLEDTog = ENABLE;
|
||||
rc_data()->Key_data[2] = 0;
|
||||
rc_data()->Key_data[3] = 1;
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@brief 按键11回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_11_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
if (KEY_ENABLED(11))
|
||||
{
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
if (rc_data()->Asr_state == UNLOCK && rc_data()->Lock_state == UNLOCK)
|
||||
{
|
||||
ASR_Power_OFF;
|
||||
LEDClass.Set(BLACK);
|
||||
rc_data()->Asr_state = LOCK;
|
||||
}
|
||||
else if (rc_data()->Asr_state == LOCK && rc_data()->Lock_state == UNLOCK)
|
||||
{
|
||||
ASR_Power_ON;
|
||||
LEDClass.Set(BLACK);
|
||||
rc_data()->Asr_state = UNLOCK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@brief 按键12回调函数
|
||||
*@param *btn 按键结构体
|
||||
*@retval None
|
||||
*/
|
||||
static void btn_12_cb(flex_button_t *btn)
|
||||
{
|
||||
switch (btn->event)
|
||||
{
|
||||
case FLEX_BTN_PRESS_DOWN:
|
||||
break;
|
||||
case FLEX_BTN_PRESS_CLICK:
|
||||
rc_data()->Lock_time_tick = 0;
|
||||
rc_data()->isSend = ENABLE;
|
||||
break;
|
||||
case FLEX_BTN_PRESS_LONG_START:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 按键001平读取接口
|
||||
static uint8_t button_s1_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
|
||||
}
|
||||
|
||||
// 按键02电平读取接口
|
||||
static uint8_t button_s2_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11);
|
||||
}
|
||||
|
||||
// 按键03平读取接口
|
||||
static uint8_t button_s3_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12);
|
||||
}
|
||||
|
||||
// 按键04电平读取接口
|
||||
static uint8_t button_s4_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7);
|
||||
}
|
||||
// 按键05电平读取接口
|
||||
static uint8_t button_s5_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);
|
||||
}
|
||||
// 按键06电平读取接口
|
||||
static uint8_t button_s6_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_6);
|
||||
}
|
||||
// 按键07电平读取接口
|
||||
static uint8_t button_s7_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
|
||||
}
|
||||
// 按键08电平读取接口
|
||||
static uint8_t button_s8_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5);
|
||||
}
|
||||
// 按键09电平读取接口
|
||||
static uint8_t button_s9_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15);
|
||||
}
|
||||
// 按键10电平读取接口
|
||||
static uint8_t button_s10_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3);
|
||||
}
|
||||
// 按键11电平读取接口
|
||||
static uint8_t button_s11_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1);
|
||||
}
|
||||
// 按键12电平读取接口
|
||||
static uint8_t button_s12_read(void)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);
|
||||
}
|
||||
|
||||
/**
|
||||
*@brief 按键初始化
|
||||
*@param None
|
||||
*@retval None
|
||||
*/
|
||||
void user_button_init(void)
|
||||
{
|
||||
/*注册按键Callback函数*/
|
||||
memset(&user_button[0], 0x0, sizeof(user_button));
|
||||
|
||||
user_button[S1_BUTTON].usr_button_read = button_s1_read;
|
||||
user_button[S1_BUTTON].cb = (flex_button_response_callback)btn_1_cb;
|
||||
|
||||
user_button[S2_BUTTON].usr_button_read = button_s2_read;
|
||||
user_button[S2_BUTTON].cb = (flex_button_response_callback)btn_2_cb;
|
||||
|
||||
user_button[S3_BUTTON].usr_button_read = button_s3_read;
|
||||
user_button[S3_BUTTON].cb = (flex_button_response_callback)btn_3_cb;
|
||||
|
||||
user_button[S4_BUTTON].usr_button_read = button_s4_read;
|
||||
user_button[S4_BUTTON].cb = (flex_button_response_callback)btn_4_cb;
|
||||
|
||||
user_button[S5_BUTTON].usr_button_read = button_s5_read;
|
||||
user_button[S5_BUTTON].cb = (flex_button_response_callback)btn_5_cb;
|
||||
|
||||
user_button[S6_BUTTON].usr_button_read = button_s6_read;
|
||||
user_button[S6_BUTTON].cb = (flex_button_response_callback)btn_6_cb;
|
||||
|
||||
user_button[S7_BUTTON].usr_button_read = button_s7_read;
|
||||
user_button[S7_BUTTON].cb = (flex_button_response_callback)btn_7_cb;
|
||||
|
||||
user_button[S8_BUTTON].usr_button_read = button_s8_read;
|
||||
user_button[S8_BUTTON].cb = (flex_button_response_callback)btn_8_cb;
|
||||
|
||||
user_button[S9_BUTTON].usr_button_read = button_s9_read;
|
||||
user_button[S9_BUTTON].cb = (flex_button_response_callback)btn_9_cb;
|
||||
|
||||
user_button[S10_BUTTON].usr_button_read = button_s10_read;
|
||||
user_button[S10_BUTTON].cb = (flex_button_response_callback)btn_10_cb;
|
||||
|
||||
user_button[S11_BUTTON].usr_button_read = button_s11_read;
|
||||
user_button[S11_BUTTON].cb = (flex_button_response_callback)btn_11_cb;
|
||||
|
||||
user_button[S12_BUTTON].usr_button_read = button_s12_read;
|
||||
user_button[S12_BUTTON].cb = (flex_button_response_callback)btn_12_cb;
|
||||
|
||||
/*按键检测IO初始化*/
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
|
||||
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_13 | GPIO_Pin_6 | GPIO_Pin_14 | GPIO_Pin_7 | GPIO_Pin_12 | GPIO_Pin_1 | GPIO_Pin_15 | GPIO_Pin_5;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_12 | GPIO_Pin_11;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
user_button[0].pressed_logic_level = 1;
|
||||
user_button[0].click_start_tick = 20;
|
||||
user_button[0].short_press_start_tick = 80;
|
||||
user_button[0].long_press_start_tick = 200;
|
||||
user_button[0].long_hold_start_tick = 300;
|
||||
flex_button_register(&user_button[0]);
|
||||
|
||||
for (uint8_t i = 1; i < BUTTON_MAX; i++)
|
||||
{
|
||||
user_button[i].pressed_logic_level = 0;
|
||||
user_button[i].click_start_tick = 20;
|
||||
user_button[i].short_press_start_tick = 80;
|
||||
user_button[i].long_press_start_tick = 200;
|
||||
user_button[i].long_hold_start_tick = 300;
|
||||
flex_button_register(&user_button[i]);
|
||||
}
|
||||
}
|
||||
30
1.主程序源代码/User/src/bsp_chipid.c
Normal file
30
1.主程序源代码/User/src/bsp_chipid.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "bsp_chipid.h"
|
||||
|
||||
uint32_t ChipUniqueID[3];
|
||||
|
||||
/*
|
||||
* 函数名:Get_ChipID
|
||||
* 描述 :获取芯片ID
|
||||
* 输入 :无
|
||||
* 输出 :无
|
||||
*/
|
||||
void Get_ChipID(void)
|
||||
{
|
||||
ChipUniqueID[0] = *(__IO u32 *)(0X1FFFF7F0); // 高字节
|
||||
ChipUniqueID[1] = *(__IO u32 *)(0X1FFFF7EC); //
|
||||
ChipUniqueID[2] = *(__IO u32 *)(0X1FFFF7E8); // 低字节
|
||||
}
|
||||
|
||||
void WDOG_Init()
|
||||
{
|
||||
// 使能 预分频寄存器PR和重装载寄存器RLR可写
|
||||
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
|
||||
// 设置预分频器值
|
||||
IWDG_SetPrescaler(IWDG_Prescaler_16); // IWDG 1s 超时溢出40k/16/2500= 1s
|
||||
// 设置重装载寄存器值
|
||||
IWDG_SetReload(0xfff);
|
||||
// 把重装载寄存器的值放到计数器中
|
||||
IWDG_ReloadCounter();
|
||||
// 使能 IWDG
|
||||
IWDG_Enable();
|
||||
}
|
||||
117
1.主程序源代码/User/src/bsp_led.c
Normal file
117
1.主程序源代码/User/src/bsp_led.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* @Date: 2025-06-26 09:38:27
|
||||
* @LastEditors: 路怀帅
|
||||
* @LastEditTime: 2025-06-26 15:04:35
|
||||
* @FilePath: \Andon_Remote_Control\MDK_PROJECT\Drive\Led.c
|
||||
*/
|
||||
#include "main.h"
|
||||
|
||||
static void LED_Init(void);
|
||||
static void LED_Set(uint8_t led_x);
|
||||
static void Green_Toggle_Fun(void);
|
||||
static void Red_Toggle_Fun(void);
|
||||
static void Blue_Toggle_Fun(void);
|
||||
static void Yellow_Toggle_Fun(void);
|
||||
|
||||
typedef LED_Color_Enum Led_Color;
|
||||
|
||||
LEDClassStruct LEDClass = {
|
||||
.Init = LED_Init,
|
||||
.Set = LED_Set,
|
||||
.GREEN_Toggle = Green_Toggle_Fun,
|
||||
.RED_Toggle = Red_Toggle_Fun,
|
||||
.BLUE_Toggle = Blue_Toggle_Fun,
|
||||
.YELLOW_Toggle = Yellow_Toggle_Fun};
|
||||
|
||||
static void LED_Set(uint8_t led_x)
|
||||
{
|
||||
switch (led_x)
|
||||
{
|
||||
case BLACK:
|
||||
LED_ALL_OFF;
|
||||
break;
|
||||
case BLUE:
|
||||
BLUE_ON;
|
||||
break;
|
||||
case GREEN:
|
||||
GREEN_ON;
|
||||
break;
|
||||
case RED:
|
||||
RED_ON;
|
||||
break;
|
||||
case YELLOW:
|
||||
RED_ON;
|
||||
GREEN_ON;
|
||||
break;
|
||||
case WHITE:
|
||||
RED_ON;
|
||||
GREEN_ON;
|
||||
BLUE_ON;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void Green_Toggle_Fun()
|
||||
{
|
||||
GREEN_TOG;
|
||||
}
|
||||
static void Blue_Toggle_Fun()
|
||||
{
|
||||
BLUE_TOG;
|
||||
}
|
||||
static void Red_Toggle_Fun()
|
||||
{
|
||||
RED_TOG;
|
||||
}
|
||||
static void Yellow_Toggle_Fun()
|
||||
{
|
||||
RED_TOG;
|
||||
GREEN_TOG;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LED初始化
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void LED_Init()
|
||||
{
|
||||
/*初始化LED引脚*/
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
|
||||
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
|
||||
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
|
||||
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
GPIO_SetBits(GPIOA, GPIO_Pin_6 | GPIO_Pin_7);
|
||||
GPIO_SetBits(GPIOB, GPIO_Pin_0);
|
||||
}
|
||||
|
||||
void ASR_Power_Init()
|
||||
{
|
||||
/*初始化LED引脚*/
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||||
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
|
||||
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
}
|
||||
|
||||
void BOARD_Power_Init()
|
||||
{
|
||||
/*初始化LED引脚*/
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
|
||||
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
BOARD_Power_ON;
|
||||
}
|
||||
40
1.主程序源代码/User/src/bsp_mod.c
Normal file
40
1.主程序源代码/User/src/bsp_mod.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "main.h"
|
||||
|
||||
typedef void (*ToggleFunc)(void);
|
||||
typedef void (*DelayFunc)(uint32_t);
|
||||
|
||||
static void toggleLoop(ToggleFunc toggle, DelayFunc delayFunc, uint8_t iterations, uint32_t delayTime);
|
||||
|
||||
MODClassStruct MODClass = {
|
||||
.Loop = toggleLoop,
|
||||
};
|
||||
|
||||
static void toggleLoop(ToggleFunc toggle, DelayFunc delayFunc, uint8_t iterations, uint32_t delayTime)
|
||||
{
|
||||
for (uint8_t i = 0; i < iterations; i++)
|
||||
{
|
||||
toggle();
|
||||
delayFunc(delayTime);
|
||||
}
|
||||
}
|
||||
|
||||
LoraCommandParams cmd_params[] = {
|
||||
{"6", "1", "0", "0"},
|
||||
{"3", "1", "0", "0"},
|
||||
{"7", "1", "0", "0"},
|
||||
{"5", "1", "0", "0"},
|
||||
{"4", "1", "0", "0"},
|
||||
{"6", "0", "0", "0"},
|
||||
{"3", "0", "0", "0"},
|
||||
{"7", "0", "0", "0"},
|
||||
{"5", "0", "0", "0"},
|
||||
{"4", "0", "0", "0"},
|
||||
{"0", "0", "1", "0"},
|
||||
{"0", "0", "0", "1"},
|
||||
};
|
||||
|
||||
rc_data_t *rc_data(void)
|
||||
{
|
||||
static rc_data_t instance = {0};
|
||||
return &instance;
|
||||
}
|
||||
0
1.主程序源代码/User/src/bsp_sleep.c
Normal file
0
1.主程序源代码/User/src/bsp_sleep.c
Normal file
370
1.主程序源代码/User/src/bsp_usart.c
Normal file
370
1.主程序源代码/User/src/bsp_usart.c
Normal file
@@ -0,0 +1,370 @@
|
||||
#include "main.h"
|
||||
|
||||
static void USART1_Init(uint32_t baudRate);
|
||||
static void USART2_Init(uint32_t baudRate);
|
||||
static void USART3_Init(uint32_t baudRate);
|
||||
static void USART_SendString1(USART_TypeDef *USARTx, uint8_t *str, uint16_t len);
|
||||
static void USART_SendString2(USART_TypeDef *USARTx, uint8_t *str);
|
||||
|
||||
USARTClassStruct USARTClass = {
|
||||
.USART1_Init = USART1_Init,
|
||||
.USART2_Init = USART2_Init,
|
||||
.USART3_Init = USART3_Init,
|
||||
.USART_SendString1 = USART_SendString1,
|
||||
.USART_SendString2 = USART_SendString2};
|
||||
|
||||
#define use_USART1
|
||||
#define use_USART2
|
||||
#define use_USART3
|
||||
#define DEBUG_USART USART1
|
||||
|
||||
/* 在别的地方复现此函数 串口1中断函数
|
||||
void USART1_IRQHandler(void)
|
||||
{
|
||||
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
|
||||
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
/* 在别的地方复现此函数 串口2中断函数
|
||||
void USART2_IRQHandler(void)
|
||||
{
|
||||
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
|
||||
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
/* 在别的地方复现此函数 串口3中断函数
|
||||
void USART3_IRQHandler(void)
|
||||
{
|
||||
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
|
||||
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
#define DEBUG_REVDATA_SIZE 500
|
||||
uint8_t g_debugRxFlag = 0;
|
||||
uint8_t g_debugRxBuf[DEBUG_REVDATA_SIZE];
|
||||
uint16_t g_debugRxLen = 0;
|
||||
uint8_t Lora_sendbuf[DEBUG_REVDATA_SIZE];
|
||||
void USART1_IRQHandler(void)
|
||||
{
|
||||
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
|
||||
g_debugRxBuf[g_debugRxLen] = USART_ReceiveData(USART1);
|
||||
g_debugRxLen++;
|
||||
}
|
||||
else if (USART_GetFlagStatus(USART1, USART_FLAG_IDLE) != RESET)
|
||||
{
|
||||
USART1->SR;
|
||||
USART1->DR;
|
||||
// memcpy(Lora_sendbuf,g_debugRxBuf,g_debugRxLen);
|
||||
|
||||
// printf("send data:%s\r\n",g_debugRxBuf);
|
||||
// USARTClass.USART_SendString1(USART3,g_debugRxBuf,g_debugRxLen);
|
||||
// memset(g_debugRxBuf,0x00,DEBUG_REVDATA_SIZE);
|
||||
// g_debugRxLen = 0;
|
||||
g_debugRxFlag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USART1初始化
|
||||
* @param baudRate: 波特率
|
||||
* @retval None
|
||||
*/
|
||||
static void USART1_Init(uint32_t baudRate)
|
||||
{
|
||||
#ifdef use_USART1
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
USART_InitTypeDef USART_InitStructure;
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
// 打开串口GPIO的时钟
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
// 打开串口外设的时钟
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
||||
|
||||
// 将USART Tx的GPIO配置为推挽复用模式
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
// 将USART Rx的GPIO配置为浮空输入模式
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
// 配置波特率
|
||||
USART_InitStructure.USART_BaudRate = baudRate;
|
||||
// 配置 针数据字长
|
||||
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||
// 配置停止位
|
||||
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||
// 配置校验位
|
||||
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||
// 配置硬件流控制
|
||||
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||
// 配置工作模式,收发一起
|
||||
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
|
||||
// 完成串口的初始化配置
|
||||
USART_Init(USART1, &USART_InitStructure);
|
||||
// 使能串口
|
||||
USART_Cmd(USART1, ENABLE);
|
||||
// 使能接收中断
|
||||
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
|
||||
|
||||
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 使能串口空闲中断
|
||||
|
||||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 中断控制器分组设置
|
||||
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ASR_REVDATA_SIZE 20
|
||||
uint8_t g_asrRxFlag = 0;
|
||||
uint8_t Asr_recbuff[ASR_REVDATA_SIZE];
|
||||
uint16_t g_asrRxLen = 0;
|
||||
|
||||
void USART2_IRQHandler(void)
|
||||
{
|
||||
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
|
||||
Asr_recbuff[g_asrRxLen] = USART_ReceiveData(USART2);
|
||||
g_asrRxLen++;
|
||||
}
|
||||
else if (USART_GetFlagStatus(USART2, USART_FLAG_IDLE) != RESET)
|
||||
{
|
||||
USART2->SR;
|
||||
USART2->DR;
|
||||
g_asrRxLen = 0;
|
||||
// printf("asr data:");
|
||||
// for(int i = 0;i<=2;i++)
|
||||
// {
|
||||
// printf("%02X",Asr_recbuff[i]);
|
||||
|
||||
// }
|
||||
// printf("\r\n");
|
||||
g_asrRxFlag = 1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief USART2初始化
|
||||
* @param baudRate: 波特率
|
||||
* @retval None
|
||||
*/
|
||||
static void USART2_Init(uint32_t baudRate)
|
||||
{
|
||||
#ifdef use_USART2
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
USART_InitTypeDef USART_InitStructure;
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
// 打开串口GPIO的时钟
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
// 打开串口外设的时钟
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
|
||||
|
||||
// 将USART Tx的GPIO配置为推挽复用模式
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
// 将USART Rx的GPIO配置为浮空输入模式
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
// 配置波特率
|
||||
USART_InitStructure.USART_BaudRate = baudRate;
|
||||
// 配置 针数据字长
|
||||
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||
// 配置停止位
|
||||
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||
// 配置校验位
|
||||
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||
// 配置硬件流控制
|
||||
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||
// 配置工作模式,收发一起
|
||||
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
|
||||
// 完成串口的初始化配置
|
||||
USART_Init(USART2, &USART_InitStructure);
|
||||
// 使能串口
|
||||
USART_Cmd(USART2, ENABLE);
|
||||
// 使能接收中断
|
||||
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
|
||||
|
||||
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); // 使能串口空闲中断
|
||||
|
||||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 中断控制器分组设置
|
||||
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define LORA_REVDATA_SIZE 400
|
||||
uint8_t g_loraRxFlag = 0;
|
||||
uint8_t Lora_recbuff[LORA_REVDATA_SIZE];
|
||||
uint16_t g_loraRxLen = 0;
|
||||
|
||||
void USART3_IRQHandler(void)
|
||||
{
|
||||
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
|
||||
Lora_recbuff[g_loraRxLen] = USART_ReceiveData(USART3);
|
||||
g_loraRxLen++;
|
||||
}
|
||||
else if (USART_GetFlagStatus(USART3, USART_FLAG_IDLE) != RESET)
|
||||
{
|
||||
USART3->SR;
|
||||
USART3->DR;
|
||||
g_loraRxLen = 0;
|
||||
printf("%s", Lora_recbuff);
|
||||
memset(Lora_recbuff, 0x00, LORA_REVDATA_SIZE);
|
||||
g_loraRxFlag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USART3初始化
|
||||
* @param baudRate: 波特率
|
||||
* @retval None
|
||||
*/
|
||||
static void USART3_Init(uint32_t baudRate)
|
||||
{
|
||||
#ifdef use_USART3
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
USART_InitTypeDef USART_InitStructure;
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
// 打开串口GPIO的时钟
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||||
// 打开串口外设的时钟
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
|
||||
|
||||
// 将USART Tx的GPIO配置为推挽复用模式
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
// 将USART Rx的GPIO配置为浮空输入模式
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
// 配置波特率
|
||||
USART_InitStructure.USART_BaudRate = baudRate;
|
||||
// 配置 针数据字长
|
||||
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||
// 配置停止位
|
||||
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||
// 配置校验位
|
||||
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||
// 配置硬件流控制
|
||||
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||
// 配置工作模式,收发一起
|
||||
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
|
||||
// 完成串口的初始化配置
|
||||
USART_Init(USART3, &USART_InitStructure);
|
||||
// 使能串口
|
||||
USART_Cmd(USART3, ENABLE);
|
||||
// 使能接收中断
|
||||
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
|
||||
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE); // 使能串口空闲中断
|
||||
|
||||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 中断控制器分组设置
|
||||
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief USART发送定长字符串
|
||||
* @param USARTx: 串口几发送
|
||||
* @param str: 发送的内容
|
||||
* @param len: 长度
|
||||
* @retval None
|
||||
*/
|
||||
static void USART_SendString1(USART_TypeDef *USARTx, uint8_t *str, uint16_t len)
|
||||
{
|
||||
|
||||
unsigned short count = 0;
|
||||
|
||||
for (; count < len; count++)
|
||||
{
|
||||
USART_SendData(USARTx, *str++); // 发送数据
|
||||
while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET)
|
||||
; // 等待发送完成
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief USART发送不定长字符串
|
||||
* @param USARTx: 串口几发送
|
||||
* @param str: 发送的内容
|
||||
* @retval None
|
||||
*/
|
||||
static void USART_SendString2(USART_TypeDef *USARTx, uint8_t *str)
|
||||
{
|
||||
unsigned int k = 0;
|
||||
do
|
||||
{
|
||||
USART_SendData(USARTx, *(str + k));
|
||||
/* 等待发送数据寄存器为空 */
|
||||
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET)
|
||||
{
|
||||
}
|
||||
k++;
|
||||
} while (*(str + k) != '\0');
|
||||
/* 等待发送完成 */
|
||||
while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// 重定向c库函数printf到串口,重定向后可使用printf函数
|
||||
int fputc(int ch, FILE *f)
|
||||
{
|
||||
/* 发送一个字节数据到串口 */
|
||||
USART_SendData(DEBUG_USART, (uint8_t)ch);
|
||||
/* 等待发送完毕 */
|
||||
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET)
|
||||
;
|
||||
return (ch);
|
||||
}
|
||||
|
||||
void Usart_SendByte(USART_TypeDef *pUSARTx, uint8_t ch)
|
||||
{
|
||||
/* 发送一个字节数据到USART */
|
||||
USART_SendData(pUSARTx, ch);
|
||||
|
||||
/* 等待发送数据寄存器为空 */
|
||||
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET)
|
||||
;
|
||||
}
|
||||
|
||||
void Usart_SendString(USART_TypeDef *pUSARTx, char *str)
|
||||
{
|
||||
unsigned int k = 0;
|
||||
do
|
||||
{
|
||||
Usart_SendByte(pUSARTx, *(str + k));
|
||||
k++;
|
||||
} while (*(str + k) != '\0');
|
||||
|
||||
/* 等待发送完成 */
|
||||
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET)
|
||||
{
|
||||
}
|
||||
}
|
||||
153
1.主程序源代码/User/src/delay.c
Normal file
153
1.主程序源代码/User/src/delay.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#include "delay.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//如果使用ucos,则包括下面的头文件即可.
|
||||
#if SYSTEM_SUPPORT_UCOS
|
||||
#include "includes.h" //ucos 使用
|
||||
#endif
|
||||
|
||||
static u8 fac_us=0;//us延时倍乘数
|
||||
static u16 fac_ms=0;//ms延时倍乘数
|
||||
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
|
||||
//systick中断服务函数,使用ucos时用到
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
OSIntEnter(); //进入中断
|
||||
OSTimeTick(); //调用ucos的时钟服务程序
|
||||
OSIntExit(); //触发任务切换软中断
|
||||
}
|
||||
#endif
|
||||
|
||||
//初始化延迟函数
|
||||
//当使用ucos的时候,此函数会初始化ucos的时钟节拍
|
||||
//SYSTICK的时钟固定为HCLK时钟的1/8
|
||||
//SYSCLK:系统时钟
|
||||
void delay_init()
|
||||
{
|
||||
|
||||
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
|
||||
u32 reload;
|
||||
#endif
|
||||
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
|
||||
fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
|
||||
|
||||
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
|
||||
reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K
|
||||
reload*=1000000/OS_TICKS_PER_SEC;//根据OS_TICKS_PER_SEC设定溢出时间
|
||||
//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右
|
||||
fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延时的最少单位
|
||||
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
|
||||
SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中断一次
|
||||
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
|
||||
#else
|
||||
fac_ms=(u16)fac_us*1000;//非ucos下,代表每个ms需要的systick时钟数
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef OS_CRITICAL_METHOD //使用了ucos
|
||||
//延时nus
|
||||
//nus为要延时的us数.
|
||||
void delay_us(u32 nus)
|
||||
{
|
||||
u32 ticks;
|
||||
u32 told,tnow,tcnt=0;
|
||||
u32 reload=SysTick->LOAD; //LOAD的值
|
||||
ticks=nus*fac_us; //需要的节拍数
|
||||
tcnt=0;
|
||||
told=SysTick->VAL; //刚进入时的计数器值
|
||||
while(1)
|
||||
{
|
||||
tnow=SysTick->VAL;
|
||||
if(tnow!=told)
|
||||
{
|
||||
if(tnow<told)tcnt+=told-tnow;//这里注意一下SYSTICK是一个递减的计数器就可以了.
|
||||
else tcnt+=reload-tnow+told;
|
||||
told=tnow;
|
||||
if(tcnt>=ticks)break;//时间超过/等于要延迟的时间,则退出.
|
||||
}
|
||||
};
|
||||
}
|
||||
//延时nms
|
||||
//nms:要延时的ms数
|
||||
void delay_ms(u16 nms)
|
||||
{
|
||||
if(OSRunning==TRUE)//如果os已经在跑了
|
||||
{
|
||||
if(nms>=fac_ms)//延时的时间大于ucos的最少时间周期
|
||||
{
|
||||
OSTimeDly(nms/fac_ms);//ucos延时
|
||||
}
|
||||
nms%=fac_ms; //ucos已经无法提供这么小的延时了,采用普通方式延时
|
||||
}
|
||||
delay_us((u32)(nms*1000)); //普通方式延时,此时ucos无法启动调度.
|
||||
}
|
||||
#else//不用ucos时
|
||||
//延时nus
|
||||
//nus为要延时的us数.
|
||||
void delay_us(u32 nus)
|
||||
{
|
||||
u32 temp;
|
||||
SysTick->LOAD=nus*fac_us; //时间加载
|
||||
SysTick->VAL=0x00; //清空计数器
|
||||
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
|
||||
do
|
||||
{
|
||||
temp=SysTick->CTRL;
|
||||
}
|
||||
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
|
||||
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
|
||||
SysTick->VAL =0X00; //清空计数器
|
||||
}
|
||||
//延时nms
|
||||
//注意nms的范围
|
||||
//SysTick->LOAD为24位寄存器,所以,最大延时为:
|
||||
//nms<=0xffffff*8*1000/SYSCLK
|
||||
//SYSCLK单位为Hz,nms单位为ms
|
||||
//对72M条件下,nms<=1864
|
||||
void delay_ms(u16 nms)
|
||||
{
|
||||
u32 temp;
|
||||
SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
|
||||
SysTick->VAL =0x00; //清空计数器
|
||||
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
|
||||
do
|
||||
{
|
||||
temp=SysTick->CTRL;
|
||||
}
|
||||
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
|
||||
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
|
||||
SysTick->VAL =0X00; //清空计数器
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
293
1.主程序源代码/User/src/flexible_button.c
Normal file
293
1.主程序源代码/User/src/flexible_button.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* @Date: 2025-06-26 10:58:20
|
||||
* @LastEditors: 路怀帅
|
||||
* @LastEditTime: 2025-06-26 14:47:21
|
||||
* @FilePath: \Andon_Remote_Control\MDK_PROJECT\Drive\flexible_button.c
|
||||
*/
|
||||
/**
|
||||
* @File: flexible_button.c
|
||||
* @Author: MurphyZhao
|
||||
* @Date: 2018-09-29
|
||||
*
|
||||
* Copyright (c) 2018-2019 MurphyZhao <d2014zjt@163.com>
|
||||
* https://github.com/murphyzhao
|
||||
* All rights reserved.
|
||||
* License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Change logs:
|
||||
* Date Author Notes
|
||||
* 2018-09-29 MurphyZhao First add
|
||||
* 2019-08-02 MurphyZhao 迁移代码到 murphyzhao 仓库
|
||||
*
|
||||
*/
|
||||
|
||||
#include "flexible_button.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static flex_button_t *btn_head = NULL;
|
||||
|
||||
#define EVENT_CB_EXECUTOR(button) if(button->cb) button->cb((flex_button_t*)button)
|
||||
#define MAX_BUTTON_CNT 16
|
||||
|
||||
static uint16_t trg = 0;
|
||||
static uint16_t cont = 0;
|
||||
static uint16_t keydata = 0xFFFF;
|
||||
static uint16_t key_rst_data = 0xFFFF;
|
||||
static uint8_t button_cnt = 0;
|
||||
|
||||
/**
|
||||
* @brief Register a user button
|
||||
*
|
||||
* @param button: button structure instance
|
||||
* @return Number of keys that have been registered
|
||||
*/
|
||||
int8_t flex_button_register(flex_button_t *button)
|
||||
{
|
||||
flex_button_t *curr = btn_head;
|
||||
|
||||
if (!button || (button_cnt > MAX_BUTTON_CNT))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (curr)
|
||||
{
|
||||
if(curr == button)
|
||||
{
|
||||
return -1; //already exist.
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
button->next = btn_head;
|
||||
button->status = 0;
|
||||
button->event = FLEX_BTN_PRESS_NONE;
|
||||
button->scan_cnt = 0;
|
||||
button->click_cnt = 0;
|
||||
btn_head = button;
|
||||
key_rst_data = key_rst_data << 1;
|
||||
button_cnt ++;
|
||||
return button_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read all key values in one scan cycle
|
||||
*
|
||||
* @param void
|
||||
* @return none
|
||||
*/
|
||||
static void flex_button_read(void)
|
||||
{
|
||||
flex_button_t* target;
|
||||
uint16_t read_data = 0;
|
||||
keydata = key_rst_data;
|
||||
int8_t i = 0;
|
||||
|
||||
for(target = btn_head, i = 0;
|
||||
(target != NULL) && (target->usr_button_read != NULL);
|
||||
target = target->next, i ++)
|
||||
{
|
||||
keydata = keydata |
|
||||
(target->pressed_logic_level == 1 ?
|
||||
((!(target->usr_button_read)()) << i) :
|
||||
((target->usr_button_read)() << i));
|
||||
}
|
||||
|
||||
read_data = keydata^0xFFFF;
|
||||
trg = read_data & (read_data ^ cont);
|
||||
cont = read_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle all key events in one scan cycle.
|
||||
* Must be used after 'flex_button_read' API
|
||||
*
|
||||
* @param void
|
||||
* @return none
|
||||
*/
|
||||
static void flex_button_process(void)
|
||||
{
|
||||
int8_t i = 0;
|
||||
flex_button_t* target;
|
||||
|
||||
for (target = btn_head, i = 0; target != NULL; target = target->next, i ++)
|
||||
{
|
||||
if (target->status > 0)
|
||||
{
|
||||
target->scan_cnt ++;
|
||||
}
|
||||
|
||||
switch (target->status)
|
||||
{
|
||||
case 0: /* is default */
|
||||
if (trg & (1 << i)) /* is pressed */
|
||||
{
|
||||
target->scan_cnt = 0;
|
||||
target->click_cnt = 0;
|
||||
target->status = 1;
|
||||
target->event = FLEX_BTN_PRESS_DOWN;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
target->event = FLEX_BTN_PRESS_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: /* is pressed */
|
||||
if (!(cont & (1 << i))) /* is up */
|
||||
{
|
||||
target->status = 2;
|
||||
}
|
||||
else if ((target->scan_cnt >= target->short_press_start_tick) &&
|
||||
(target->scan_cnt < target->long_press_start_tick))
|
||||
{
|
||||
target->status = 4;
|
||||
target->event = FLEX_BTN_PRESS_SHORT_START;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* is up */
|
||||
if ((target->scan_cnt < target->click_start_tick))
|
||||
{
|
||||
target->click_cnt++; // 1
|
||||
|
||||
if (target->click_cnt == 1)
|
||||
{
|
||||
target->status = 3; /* double click check */
|
||||
}
|
||||
else
|
||||
{
|
||||
target->click_cnt = 0;
|
||||
target->status = 0;
|
||||
target->event = FLEX_BTN_PRESS_DOUBLE_CLICK;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
}
|
||||
else if ((target->scan_cnt >= target->click_start_tick) &&
|
||||
(target->scan_cnt < target->short_press_start_tick))
|
||||
{
|
||||
target->click_cnt = 0;
|
||||
target->status = 0;
|
||||
target->event = FLEX_BTN_PRESS_CLICK;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
else if ((target->scan_cnt >= target->short_press_start_tick) &&
|
||||
(target->scan_cnt < target->long_press_start_tick))
|
||||
{
|
||||
target->click_cnt = 0;
|
||||
target->status = 0;
|
||||
target->event = FLEX_BTN_PRESS_SHORT_UP;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
else if ((target->scan_cnt >= target->long_press_start_tick) &&
|
||||
(target->scan_cnt < target->long_hold_start_tick))
|
||||
{
|
||||
target->click_cnt = 0;
|
||||
target->status = 0;
|
||||
target->event = FLEX_BTN_PRESS_LONG_UP;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
else if (target->scan_cnt >= target->long_hold_start_tick)
|
||||
{
|
||||
/* long press hold up, not deal */
|
||||
target->click_cnt = 0;
|
||||
target->status = 0;
|
||||
target->event = FLEX_BTN_PRESS_LONG_HOLD_UP;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: /* double click check */
|
||||
if (trg & (1 << i))
|
||||
{
|
||||
target->click_cnt++;
|
||||
target->status = 2;
|
||||
target->scan_cnt --;
|
||||
}
|
||||
else if (target->scan_cnt >= target->click_start_tick)
|
||||
{
|
||||
target->status = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: /* is short pressed */
|
||||
if (!(cont & (1 << i))) /* is up */
|
||||
{
|
||||
target->status = 2;
|
||||
}
|
||||
else if ((target->scan_cnt >= target->long_press_start_tick) &&
|
||||
(target->scan_cnt < target->long_hold_start_tick))
|
||||
{
|
||||
target->status = 5;
|
||||
target->event = FLEX_BTN_PRESS_LONG_START;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: /* is long pressed */
|
||||
if (!(cont & (1 << i))) /* is up */
|
||||
{
|
||||
target->status = 2;
|
||||
}
|
||||
else if (target->scan_cnt >= target->long_hold_start_tick)
|
||||
{
|
||||
target->status = 6;
|
||||
target->event = FLEX_BTN_PRESS_LONG_HOLD;
|
||||
EVENT_CB_EXECUTOR(target);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: /* is long pressed */
|
||||
if (!(cont & (1 << i))) /* is up */
|
||||
{
|
||||
target->status = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* flex_button_event_read
|
||||
*
|
||||
* @brief Get the button event of the specified button.
|
||||
*
|
||||
* @param button: button structure instance
|
||||
* @return button event
|
||||
*/
|
||||
flex_button_event_t flex_button_event_read(flex_button_t* button)
|
||||
{
|
||||
return (flex_button_event_t)(button->event);
|
||||
}
|
||||
|
||||
/**
|
||||
* flex_button_scan
|
||||
*
|
||||
* @brief Start key scan.
|
||||
* Need to be called cyclically within the specified period.
|
||||
* Sample cycle: 5 - 20ms
|
||||
*
|
||||
* @param void
|
||||
* @return none
|
||||
*/
|
||||
void flex_button_scan(void)
|
||||
{
|
||||
flex_button_read();
|
||||
flex_button_process();
|
||||
}
|
||||
|
||||
77
1.主程序源代码/User/stm32f10x_conf.h
Normal file
77
1.主程序源代码/User/stm32f10x_conf.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file GPIO/IOToggle/stm32f10x_conf.h
|
||||
* @author MCD Application Team
|
||||
* @version V3.5.0
|
||||
* @date 08-April-2011
|
||||
* @brief Library configuration file.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F10x_CONF_H
|
||||
#define __STM32F10x_CONF_H
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
/* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */
|
||||
#include "stm32f10x_adc.h"
|
||||
//#include "stm32f10x_bkp.h"
|
||||
//#include "stm32f10x_can.h"
|
||||
//#include "stm32f10x_cec.h"
|
||||
//#include "stm32f10x_crc.h"
|
||||
//#include "stm32f10x_dac.h"
|
||||
#include "stm32f10x_dbgmcu.h"
|
||||
#include "stm32f10x_dma.h"
|
||||
//#include "stm32f10x_exti.h"
|
||||
#include "stm32f10x_flash.h"
|
||||
//#include "stm32f10x_fsmc.h"
|
||||
#include "stm32f10x_gpio.h"
|
||||
//#include "stm32f10x_i2c.h"
|
||||
#include "stm32f10x_iwdg.h"
|
||||
//#include "stm32f10x_pwr.h"
|
||||
#include "stm32f10x_rcc.h"
|
||||
//#include "stm32f10x_rtc.h"
|
||||
//#include "stm32f10x_sdio.h"
|
||||
//#include "stm32f10x_spi.h"
|
||||
#include "stm32f10x_tim.h"
|
||||
#include "stm32f10x_usart.h"
|
||||
//#include "stm32f10x_wwdg.h"
|
||||
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Uncomment the line below to expanse the "assert_param" macro in the
|
||||
Standard Peripheral Library drivers code */
|
||||
/* #define USE_FULL_ASSERT 1 */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
#ifdef USE_FULL_ASSERT
|
||||
|
||||
/**
|
||||
* @brief The assert_param macro is used for function's parameters check.
|
||||
* @param expr: If expr is false, it calls assert_failed function which reports
|
||||
* the name of the source file and the source line number of the call
|
||||
* that failed. If expr is true, it returns no value.
|
||||
* @retval None
|
||||
*/
|
||||
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void assert_failed(uint8_t* file, uint32_t line);
|
||||
#else
|
||||
#define assert_param(expr) ((void)0)
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
#endif /* __STM32F10x_CONF_H */
|
||||
|
||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
||||
169
1.主程序源代码/User/stm32f10x_it.c
Normal file
169
1.主程序源代码/User/stm32f10x_it.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c
|
||||
* @author MCD Application Team
|
||||
* @version V3.5.0
|
||||
* @date 08-April-2011
|
||||
* @brief Main Interrupt Service Routines.
|
||||
* This file provides template for all exceptions handler and
|
||||
* peripherals interrupt service routine.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTI
|
||||
|
||||
AL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f10x_it.h"
|
||||
#include "FreeRTOS.h" //FreeRTOSʹÓÃ
|
||||
#include "task.h"
|
||||
|
||||
|
||||
/** @addtogroup STM32F10x_StdPeriph_Template
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cortex-M3 Processor Exceptions Handlers */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief This function handles NMI exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Hard Fault exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
/* Go to infinite loop when Hard Fault exception occurs */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Memory Manage exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void MemManage_Handler(void)
|
||||
{
|
||||
/* Go to infinite loop when Memory Manage exception occurs */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Bus Fault exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void BusFault_Handler(void)
|
||||
{
|
||||
/* Go to infinite loop when Bus Fault exception occurs */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Usage Fault exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void UsageFault_Handler(void)
|
||||
{
|
||||
/* Go to infinite loop when Usage Fault exception occurs */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles SVCall exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
//void SVC_Handler(void)
|
||||
//{
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief This function handles Debug Monitor exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void DebugMon_Handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles PendSVC exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
//void PendSV_Handler(void)
|
||||
//{
|
||||
//}
|
||||
|
||||
///**
|
||||
// * @brief This function handles SysTick Handler.
|
||||
// * @param None
|
||||
// * @retval None
|
||||
// */
|
||||
extern void xPortSysTickHandler(void);
|
||||
//systickÖжϷþÎñº¯Êý
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
#if (INCLUDE_xTaskGetSchedulerState == 1 )
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
|
||||
{
|
||||
#endif /* INCLUDE_xTaskGetSchedulerState */
|
||||
xPortSysTickHandler();
|
||||
#if (INCLUDE_xTaskGetSchedulerState == 1 )
|
||||
}
|
||||
#endif /* INCLUDE_xTaskGetSchedulerState */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function handles PPP interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
/*void PPP_IRQHandler(void)
|
||||
{
|
||||
}*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
||||
54
1.主程序源代码/User/stm32f10x_it.h
Normal file
54
1.主程序源代码/User/stm32f10x_it.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.h
|
||||
* @author MCD Application Team
|
||||
* @version V3.5.0
|
||||
* @date 08-April-2011
|
||||
* @brief This file contains the headers of the interrupt handlers.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F10x_IT_H
|
||||
#define __STM32F10x_IT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f10x.h"
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
|
||||
void NMI_Handler(void);
|
||||
void HardFault_Handler(void);
|
||||
void MemManage_Handler(void);
|
||||
void BusFault_Handler(void);
|
||||
void UsageFault_Handler(void);
|
||||
void SVC_Handler(void);
|
||||
void DebugMon_Handler(void);
|
||||
void PendSV_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F10x_IT_H */
|
||||
|
||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
||||
Reference in New Issue
Block a user