<< 点击显示目录 >> 主页 exOS使用助手 > exOS Automation Help > Development > Programming > exOS Communication API reference (exos_api.h) > exos_datamodel_handle_t |
数据模型句柄
typedef struct exos_datamodel_handle exos_datamodel_handle_t;
typedef struct exos_datamodel_sync_info
{
bool in_sync;
bool _reserved_bool[8];
uint32_t missed_dmr_cycles;
uint32_t missed_ar_cycles;
EXOS_DATAMODEL_PROCESS_MODE process_mode;
uint32_t _reserved_uint32[7];
} exos_datamodel_sync_info_t;
struct exos_datamodel_handle
{
char *name;
EXOS_CONNECTION_STATE connection_state;
EXOS_ERROR_CODE error;
void *user_context;
long user_tag;
char *user_alias;
exos_datamodel_event_cb datamodel_event_callback;
exos_datamodel_sync_info_t sync_info;
bool _reserved_bool[8];
uint32_t _reserved_uint32[8];
void *_reserved_void[8];
exos_datamodel_private_t _private;
};
•名称
(只读)用 exos_datamodel_connect_ 初始化的数据模型实例的名称 数据 模型实例应 分别 在 exostarget 配置元素和 exos-api.conf 中 配置 ,由 数据集消息路由器读出 , 以便与远程系统建立合适的连接。如果没有为 数据集消息路由器 配置数据模型实例 , 数据集消息路由器 将在系统日志中输出警告,并允许本地连接,这可用于测试没有远程系统的应用程序。exos_datamodel_handle_t 中的名称是传递给 exos_datamodel_connect_ 函数 的 字符串的副本 ,因此 在 删除数据模型时,必须 使用 exos_datamodel_delete 释放所有分配的内存。
•连接状态:
(数据集消息路由器的连接状态(只读) 。请参阅 CONNECTION_STATE
•错误:
(只读)连接状态进入 EXOS_STATE_ABORTED 时的错误代码。请参见 错误代码 (EXOS_ERROR_CODE error;)
•同步信息:
sync_info 包含使用 exos_datamodel_set_process_mode()设置的当前进程模式 ,以及应用程序与 数据集消息路由器 和自动化运行时 的同步状态 。 有关同步状态的更多信息, 请参阅 exos_datamodel_event_cb 和 exos_datamodel_get_nettime()。
•用户语境:
(读/写)用户可分配的上下文指针
在许多情况下,数据模型是另一个对象(如 C++ 类)的一部分。在这种情况下,将 user_context 初始化为类指针 "this",并在 datamodelEvent 回调中检索对象引用是合理 的。
在 C++ 对象中嵌入 exos_datamodel_handle_t 的示例:
class MyApp {
public:
MyApp() {
exos_datamodel_init(&this->datamodel, "MyApplication", "MyApplicationClass");
//here we set the class instance reference
this->datamodel.user_context = this;
exos_datamodel_connect_myapplication(&this->datamodel, &MyApp:_dataModelEvent)
}
private:
exos_datamodel_handle_t datamodel;
//functions to be implemented by an inherited class
virtual void connected() {}
virtual void disconnected() {}
static void _datamodelEvent(exos_datamodel_handle_t *datamodel, const EXOS_DATAMODEL_EVENT_TYPE event_type, void *info) {
switch (event_type) {
case EXOS_DATASET_EVENT_CONNECTION_CHANGED:
switch (datamodel->connection_state) {
case EXOS_STATE_DISCONNECTED:
case EXOS_STATE_ABORTED:
if(datamodel->user_context != NULL) {
//reference the class instance back from the user context
MyApp *inst = reinterpret_cast<MyApp *>(datamodel->user_context);
inst->disconnected();
}
break;
case EXOS_STATE_CONNECTED:
case EXOS_STATE_OPERATIONAL:
if(datamodel->user_context != NULL) {
//reference the class instance back from the user context
MyApp *inst = reinterpret_cast<MyApp *>(datamodel->user_context);
inst->connected();
}
break;
}
break;
}
}
};
•user_tag:
(读/写)用户自定义标签,可用于枚举数据模型
在某些情况下,您可能会将同一个 eventHandler 连接到不同的数据模型,或者您的应用程序中连接数据集的数据模型不止一个。在某些情况下,exos_dataset_handle_t 可以查询它属于哪个数据模型。通过在数据模型上设置 user_tag,数据集就可以通过其数据模型指针访问 user_tag。例如
static void datasetEvent(exos_dataset_handle_t *dataset, EXOS_DATASET_EVENT_TYPE event_type, void *info)
{
if(dataset->connection_state != EXOS_STATE_OPERATIONAL) return;
switch(dataset->datamodel->user_tag) //here the tag reference can be evauated
{
case MYAPPLICATION1:
...
}
}
int main(int argc, char *argc[])
{
exos_datamodel_handle_t mydatamodel;
exos_datamodel_init(&mydatamodel, "MyApplication", "MyApplication1");
mydatamodel.user_tag = MYAPPLICATION1; //set the reference here..
exos_datamodel_connect_myapplication(&mydatamodel, NULL);
exos_dataset_handle_t counter;
exos_dataset_init(&counter, &mydatamodel, "Counter", &interface.Counter, sizeof(interface.Counter));
exos_dataset_connect(&counter, EXOS_DATASET_SUBSCRIBE, datasetEvent);
...
所有数据模型句柄都应使用 exos_datamodel_init() 函数进行初始化 。
由于句柄会在整个应用程序中使用,因此用户程序必须存储 exos_datamodel_handle_t。这意味着要确保 exos_datamodel_handle_t 不会超出作用域。
•好:在当前堆栈上
int main(int argc, char *argc[])
{
//datamodel is on the stack, within the scope
exos_datamodel_handle_t mydatamodel;
exos_datamodel_init(&mydatamodel, "MyApplication");
...
while(true)
{
...
•坏:超出范围
exos_datamodel_handle_t *makeBadDatamodel(void)
{
exos_datamodel_handle_t mydatamodel;
exos_datamodel_init(&mydatamodel, "MyApplication");
return &mydatamodel; //ouch! this handle is gone as soon as you exit the call
}
int main(int argc, char *argc[])
{
exos_datamodel_handle_t *mydatamodel = makeBadDatamodel();
//most functions should return EXOS_ERROR_BAD_DATAMODEL_HANDLE from now on. but theres only so much we can do
...
此外,exos_datamodel_handle_t 还有几个可以读写的成员。在初始化该结构的成员时,应在 调用 exos_datamodel_init()之后进行 。
•好:
exos_datamodel_init(&this->datamodel, "MyApplication");
this->datamodel.user_context = this;
...
•坏:
this->datamodel.user_context = this; //nope! this wont work as the structure is initialized (reset) in the next line.
exos_datamodel_init(&this->datamodel, "MyApplication");
...
The datamodel handle
typedef struct exos_datamodel_handle exos_datamodel_handle_t;
typedef struct exos_datamodel_sync_info
{
bool in_sync;
bool _reserved_bool[8];
uint32_t missed_dmr_cycles;
uint32_t missed_ar_cycles;
EXOS_DATAMODEL_PROCESS_MODE process_mode;
uint32_t _reserved_uint32[7];
} exos_datamodel_sync_info_t;
struct exos_datamodel_handle
{
char *name;
EXOS_CONNECTION_STATE connection_state;
EXOS_ERROR_CODE error;
void *user_context;
long user_tag;
char *user_alias;
exos_datamodel_event_cb datamodel_event_callback;
exos_datamodel_sync_info_t sync_info;
bool _reserved_bool[8];
uint32_t _reserved_uint32[8];
void *_reserved_void[8];
exos_datamodel_private_t _private;
};
•name:
(read only) name of the datamodel instance initialized with exos_datamodel_connect_ The datamodel instance should be configured in the exostarget Configuration Element, respectively in the exos-api.conf, which is read out by the Dataset Message Router to have a suitable connection to the remote system. If no datamodel instance is configured for the Dataset Message Router, the Dataset Message Router will output a warning in the system log and allow local connections which can be used for testing an application without a remote system. The name inside the exos_datamodel_handle_t is a copy of the character string you pass to the exos_datamodel_connect_ function, therefore it is important to use exos_datamodel_delete to free all allocated memory when the datamodel is removed.
•connection_state:
(read only) connection state to the Dataset Message Router. See CONNECTION_STATE
•error:
(read only) Error code in case the connection_state goes into EXOS_STATE_ABORTED. See Error codes (EXOS_ERROR_CODE error;)
•sync_info:
The sync_info contains the current process_mode set with exos_datamodel_set_process_mode(), and the synchronisation state of the application towards the Dataset Message Router and the latter towards Automation Runtime. Please see exos_datamodel_event_cb ans exos_datamodel_get_nettime() for more information on the synchronization state.
•user_context:
(read / write) Context pointer that can be assigned by the user
In many cases the datamodel is part of another object, like a C++ class. Here, it makes sense to initialize the user_context to the class pointer "this" and retrieve the object reference in the datamodelEvent callback.
An example embedding an exos_datamodel_handle_t in a C++ object:
class MyApp {
public:
MyApp() {
exos_datamodel_init(&this->datamodel, "MyApplication", "MyApplicationClass");
//here we set the class instance reference
this->datamodel.user_context = this;
exos_datamodel_connect_myapplication(&this->datamodel, &MyApp:_dataModelEvent)
}
private:
exos_datamodel_handle_t datamodel;
//functions to be implemented by an inherited class
virtual void connected() {}
virtual void disconnected() {}
static void _datamodelEvent(exos_datamodel_handle_t *datamodel, const EXOS_DATAMODEL_EVENT_TYPE event_type, void *info) {
switch (event_type) {
case EXOS_DATASET_EVENT_CONNECTION_CHANGED:
switch (datamodel->connection_state) {
case EXOS_STATE_DISCONNECTED:
case EXOS_STATE_ABORTED:
if(datamodel->user_context != NULL) {
//reference the class instance back from the user context
MyApp *inst = reinterpret_cast<MyApp *>(datamodel->user_context);
inst->disconnected();
}
break;
case EXOS_STATE_CONNECTED:
case EXOS_STATE_OPERATIONAL:
if(datamodel->user_context != NULL) {
//reference the class instance back from the user context
MyApp *inst = reinterpret_cast<MyApp *>(datamodel->user_context);
inst->connected();
}
break;
}
break;
}
}
};
•user_tag:
(read / write) User defined tag that can be used for enumerating datamodels
In some cases, you might have the same eventHandler connected to different datamodels, or you simply have more than one datamodel in your application that you connect datasets to. In some cases it might make sense for the exos_dataset_handle_t to query which datamodel it belongs to. By setting the user_tag on the datamodel, the dataset can access the user_tag via its datamodel pointer. For example:
static void datasetEvent(exos_dataset_handle_t *dataset, EXOS_DATASET_EVENT_TYPE event_type, void *info)
{
if(dataset->connection_state != EXOS_STATE_OPERATIONAL) return;
switch(dataset->datamodel->user_tag) //here the tag reference can be evauated
{
case MYAPPLICATION1:
...
}
}
int main(int argc, char *argc[])
{
exos_datamodel_handle_t mydatamodel;
exos_datamodel_init(&mydatamodel, "MyApplication", "MyApplication1");
mydatamodel.user_tag = MYAPPLICATION1; //set the reference here..
exos_datamodel_connect_myapplication(&mydatamodel, NULL);
exos_dataset_handle_t counter;
exos_dataset_init(&counter, &mydatamodel, "Counter", &interface.Counter, sizeof(interface.Counter));
exos_dataset_connect(&counter, EXOS_DATASET_SUBSCRIBE, datasetEvent);
...
All datamodel handles should be initialized with the exos_datamodel_init() function.
As the handle is used throughout the entire application, it is important for the user program to store the exos_datamodel_handle_t. This means ensuring that the exos_datamodel_handle_t never gets out of scope.
•Good: on the current stack
int main(int argc, char *argc[])
{
//datamodel is on the stack, within the scope
exos_datamodel_handle_t mydatamodel;
exos_datamodel_init(&mydatamodel, "MyApplication");
...
while(true)
{
...
•Bad: out of scope
exos_datamodel_handle_t *makeBadDatamodel(void)
{
exos_datamodel_handle_t mydatamodel;
exos_datamodel_init(&mydatamodel, "MyApplication");
return &mydatamodel; //ouch! this handle is gone as soon as you exit the call
}
int main(int argc, char *argc[])
{
exos_datamodel_handle_t *mydatamodel = makeBadDatamodel();
//most functions should return EXOS_ERROR_BAD_DATAMODEL_HANDLE from now on. but theres only so much we can do
...
Furthermore, the exos_datamodel_handle_t has several members that can be read and written to. When intializing members of the structure, this should be done after calling exos_datamodel_init().
•Good:
exos_datamodel_init(&this->datamodel, "MyApplication");
this->datamodel.user_context = this;
...
•Bad:
this->datamodel.user_context = this; //nope! this wont work as the structure is initialized (reset) in the next line.
exos_datamodel_init(&this->datamodel, "MyApplication");
...