Jef*_*amb 8 c database embedded
我正在设计嵌入式C数据存储模块.它将包含在希望访问此"共享"系统范围数据的文件/模块中.多个任务聚合了数十个输入(GPIO,CAN,I2C/SPI/SSP数据等),并使用API存储这些值.然后,其他任务可以通过API安全地访问数据.该系统是带有RTOS的嵌入式应用程序,因此互斥锁用于保护数据.无论实施如何,都将使用这些想法
我过去曾设计过这样的东西,我正在努力改进它.我目前正处于一个新实施的中途,我遇到了一些小问题,并且会从一个全新的视角中受益.
快速了解该模块的要求:
问题是你将如何设计这样的东西?枚举,结构,访问器,宏等?我不是在这里寻找代码,只讨论一般的整体设计思路.如果互联网上有一个解决这些问题的解决方案,甚至只需一个链接即可.
我自己曾经遇到过这种情况.每当我结束"滚动自己"时,我绝对不会患有"不发明"(NIH)综合症.有时,空间,处理周转时间或可靠性/可恢复性要求只会使这条路成为最不痛苦的路径.
所以,不要在这个主题上写出伟大的美国小说,我只会在这里抛出一些想法,因为你的问题相当广泛(但感谢你至少形成一个问题并提供背景).
桌面上有C++吗?内联函数,模板和一些Boost库在这里可能很有用.但我猜这是直截了当的C.
如果您使用的是C99,则至少可以使用内联函数,这在函数类型安全性方面比宏高出一步.
您可能想要考虑使用多个互斥锁来保护数据的不同部分; 即使更新很快,您可能希望将数据拆分为多个部分(例如配置数据,初始化数据,错误记录数据,跟踪数据等),并为每个部分提供自己的互斥锁,从而减少漏斗/阻塞点.
您还可以考虑使对数据的所有访问都通过服务器任务.所有读取和写入都通过API与服务器任务进行通信.服务器任务从其队列中按顺序提取读取和写入请求,通过写入RAM镜像快速处理它们,如果需要(至少对于读取请求)发送响应,然后在必要时在后台将数据缓冲到NVM.与简单的互斥体相比,它听起来很重,但它在某些用例中具有优势.对您的应用程序了解不足以了解这是否可能.
我要说的一件事是,通过标签获取/设置的想法(例如,可能是CONFIG_DATA,ADDRESS_DATA等枚举列表)是直接寻址数据的一大步(例如"在地址处给我256个字节) ox42000).我看到许多商店在整个物理寻址方案最终崩溃并且需要重新设计/重新设计时遭受巨大的痛苦.尽量保持与"如何"脱离的"什么" - 客户不应该知道或关心存储的东西,它有多大等等.(你可能已经知道这一切,对不起,如果是这样,我只是一直看到它......)
最后一件事.你提到过互斥体.谨防优先级倒置......在某些情况下,可以使这些"快速访问"需要很长时间.大多数内核互斥锁实现允许您对此进行说明,但通常默认情况下不会启用它.再次,对不起,如果这是旧消息......
我想我会更新我唯一未接受的问题之一。这是我的最终实现。使用这个已经一年多了,效果非常好。添加变量非常容易,而且它给我们带来的好处非常少。
lib_data.h:
#ifndef __LIB_DATA_H
#define __LIB_DATA_H
#include <type.h>
/****************************************************************************************
* Constant Definitions
***************************************************************************************/
/* Varname, default value (uint32_t) */
#define DATA_LIST \
DM(D_VAR1, 0) \
DM(D_VAR2, 1) \
DM(D_VAR3, 43)
#define DM(y, z) y,
/* create data structure from the macro */
typedef enum {
DATA_LIST
NUM_DATA_VARIABLES
} dataNames_t;
typedef struct {
dataNames_t name;
uint32_t value;
} dataPair_t;
/* the macro has to be undefined to allow the fault list to be reused without being
* defined multiple times
*
* this requires:
* a file specific lint option to suppress the rule for use of #undef
*/
#undef DM
/****************************************************************************************
* Data Prototypes
***************************************************************************************/
/****************************************************************************************
* External Function Prototypes
***************************************************************************************/
/**
* Fetch a machine parameter
*
* \param dataName The variable from DATA_LIST that you want to fetch
*
* \return The value of the requested parameter
*
*/
uint32_t lib_data_Get(dataNames_t dataName);
/**
* Set a machine parameter
*
* \param dataName The variable from DATA_LIST that you want to set
* \param dataVal The value you want to set the variable to
*
* \return void
*
*/
void lib_data_Set(dataNames_t dataName, uint32_t dataVal);
#endif /* __LIB_DATA_H */
Run Code Online (Sandbox Code Playgroud)
lib_data.c:
#include <type.h>
#include "lib_data.h"
/****************************************************************************************
* Variable Declarations
***************************************************************************************/
/* Used to initialize the data array with defaults ##U appends a 'U' to the bare
* integer specified in the DM macro */
#define DM(y, z) \
dataArray[y].name = y; \
dataArray[y].value = z##U;
static bool_t dataInitialized = FALSE;
static dataPair_t dataArray[NUM_DATA_VARIABLES];
/****************************************************************************************
* Private Function Prototypes
***************************************************************************************/
static void lib_data_Init(void);
/****************************************************************************************
* Public Functions
***************************************************************************************/
uint32_t lib_data_Get(dataNames_t dataName) {
if(!dataInitialized) {
lib_data_Init();
}
/* Should only be used on systems that do word-sized asm reads/writes.
* If the lib gets extended to multi-word storage capabilities, a mutex
* is necessary to protect against multi-threaded access */
return dataArray[dataName].value;
}
void lib_data_Set(dataNames_t dataName, uint32_t dataVal) {
if(!dataInitialized) {
lib_data_Init();
}
/* Should only be used on systems that do word-sized asm reads/writes.
* If the lib gets extended to multi-word storage capabilities, a mutex
* is necessary to protect against multi-threaded access */
dataArray[dataName].value = dataVal;
}
/****************************************************************************************
* Private Functions
***************************************************************************************/
/**
* initialize the machine data tables
*
* \param none
*
* \return none
*
*/
static void lib_data_Init(void) {
/* Invoke the macro to initialize dataArray */
DATA_LIST
dataInitialized = TRUE;
}
Run Code Online (Sandbox Code Playgroud)