第一章 实时脚本(C++)扩展API
实时脚本在ETest中作为下位机脚本,运行在VXWorks环境下。
实时脚本为C++脚本,符合C++ 17规范。
同时,实时脚本还带有ETest提供的扩展API,提供了一系列服务和支持。本章主要介绍这些扩展API。
1
1
2
3
4
5
6
1
1.1 接口操作
本节介绍对ETest下位机接口设备硬件进行操作,完成通信的接口API。
所有接口类均在命名空间 Kiyun::LowerComputer::Rasl::Device 中。
所有接口都采用设备与通道两层结构,通道统一命名为 Channel_T,作为设备的内嵌类。如串行通信口,类名为 Com_T,其通道为 Com_T::Channel_T。
每个接口的方法主要有两组,分别是 read/write 和 intRead/asyncWrite。其中前一组是阻塞式读/写,后一组是异步(非阻塞式)读/写。其中,异步读/写均为立即返回,不等待读写操作完成;读/写完成后调用回调函数。注意有的设备没有异步读/写API。
在正常使用中,接口对象由 ETest 根据测试连接图自动构造,并以图中的通道名为对象名,可在代码中直接使用。
1.1.1 AD接口
使用模数转换通道主要用到的类型是Ad_T类型。本节对模数转换通道进行介绍。
本节所描述的类型所在命名空间均为:Kiyun::LowerComputer::Rasl::Device。
1.1.1.1 使用方法及范例
在ETest系统中,模数转换操作主要由Ad_T::Channel_T类型完成。
在使用ETest进行仿真模型设计和设备规划过程中,可以建立模数转换通道,并且配置参数。当通道建立完成并且参数配置完成后,系统运行环境会自动创建Ad_T::Channel_T类型的通道,名称和在“仿真模型”中建立的通道名称一致。在实时脚本中,即可直接使用该对象,进行数据的采集操作。
如,在以下范例中,对象f_ad即为Ad_T::Channel_T类型的对象,可以用来完成模拟量采集功能。
单次采集:
![](https://img-blog.csdnimg.cn/img_convert/2ea91cac20e38084f4ece1f3cf70579b.png)
编辑
添加图片注释,不超过 140 字(可选)
单次采集多个点:
![](https://img-blog.csdnimg.cn/img_convert/de58dfdd98701f8c8a2332d081f10bcc.png)
编辑
添加图片注释,不超过 140 字(可选)
连续采集:
if (!f_ad.isValid()) { KYIO(err) << "AD channel initial failed."; return -1; //返回值需要根据该代码片段所处函数返回值类型设定 } if (f_ad.isRunning()) { KYIO(err) << "AD channel is sampling."; return -2; //返回值需要根据该代码片段所处函数返回值类型设定 }
Os::Semaphore_T semAd; //需引入"Kiyun::LowerComputer::Rasl"命名空间 f_ad.intRead([&](float* buf, size_t size, Error_T error) { if (error) { KYIO(err) << "Occur errors in intRead:" << error.message(); return false; }
//通过发送信号量的方式终止连续采集任务的执行,需自行给定终止的条件 /* if(...){ semAd.notifyOne(); return false; } */ return true; //返回true时会一直执行连续采集直到采集出错或有其他的终止条件 } );
f_ad.start(); //开始连续采集 semAd.wait(); //等待信号量,接收到信号量后终止连续采集任务 f_ad.stop(); //停止连续采集 |
1.1.1.2 Ad_T类
本类型是模数转换操作类型。它包含了IntReader_T类型和Channel_T类。
1) IntReader_T类型
在进行中断读取的时候,需要用到一个函数类型作为参数,当读取操作完成的时候,本函数会被调用。
类型定义为:
typedef std::function<bool(float*,size_t,Error_T)> IntReader_T; |
1.1.1.3 Ad_T::Channel_T类
本类型的对象是进行AD采集的主体。具有以下方法:
1) isValid方法
检测通道是否有效。强烈建议使用前判断通道合法性。
函数原型:bool isValid() const
参数说明:无
返回值:true:通道有效,fasle:通道无效
1) path方法
返回通道的标识,可用于在数据上传时构造上传通道。
函数原型:Path_T path() const
参数:无
返回值:通道标识符(类型参加“通用类型介绍”)。
2) read方法一
采集一次数据。
函数原型:float read()
参数:无
返回值:采集到的数据
3) read方法二
多次同步采集数据。采集点数越多,函数返回时间越长。
函数原型:BOOL read(float* buf, size_t size)
参数:buf:存放采集到数据的地址;size:buf的长度(采集点数)
返回值:操作是否成功
4) intRead方法
进行通道注册连续采集。连续采集工作与单次采集工作不能同时进行。
函数原型:void intRead(const IntRead_T& hdl)
函数功能:
参数:hdl:回调函数,函数返回值表示“是否继续接收”,true继续,false停止;
返回值:无
5) isRuning方法
判断是否存在连续采集任务。
函数原型:BOOL isRuning()
参数:无
返回值:TRUE:存在连续采集任务,FALSE:不存在连续采集任务
6) start方法
开始连续采集任务。
函数原型:BOOL start()
参数:无
返回值:TRUE:成功打开或者已经存在任务,FALSE:打开失败
7) stop方法
停止连续采集任务。
函数原型:BOOL stop()
参数:无
返回值:TRUE:成功关闭或者不存在连续采集任务,FALSE:关闭失败
8) reset方法
重置连续采集通道
函数原型:BOOL reset ()
参数:无
返回值:TRUE:成功清除已注册的连续采集通道,FALSE:重置失败(采集任务正在进行)
1.1.2 DA接口
使用数模转换通道主要用到的类型是Da_T类型。本节对数模转换通道进行介绍。
1.1.2.1 使用方法及范例
在ETest系统中,数模转换操作主要由Da_T::Channel_T类型完成。
在使用ETest进行仿真模型设计和设备规划过程中,可以建立数模转换通道,并且配置参数。当通道建立完成并且参数配置完成后,系统运行环境会自动创建Da_T::Channel_T类型的通道,名称和在“仿真模型”中建立的通道名称一致。在实时脚本中,即可直接使用该对象,进行数据的采集操作。
如,在以下范例中,对象da即为Da_T::Channel_T类型的对象,可以用来完成模拟量转换输出功能。
int kiyunMain() { if(!da.isValid()) { KYIO(err) << "DA channel initial failed."; return -1; } da.write(5.0);
Timer_T::delay(5);// Da 保持输出5s
da.stop();// 禁止输出(Da退出会自动调用) return 0; } |
1.1.2.2 Da_T::Channel_T类
本类型所在命名空间为:Kiyun::LowerComputer::Rasl::Device,是进行DA转换的主体。具有以下方法:
1) isValid方法
检测通道是否有效。强烈建议使用前判断通道合法性。
函数原型:bool isValid() const
参数:无
返回值:true:通道有效,fasle:通道无效
2) path方法
返回通道的标识,可用于在数据上传时构造上传通道。
函数原型:Path_T path() const
参数:无
返回值:通道标识符(类型参加“通用类型介绍”)。
3) write方法
设置输出幅值。
函数原型:void write(float value)
参数:value:输出幅值(电压值)。
返回值:无
注:Da32(AECDA-CPCI-32)写操作需要延迟 25ms,Da8(AECDA-CPCI-8-S2)输出间隔应至少1us
4) start方法
开始DA输出。
(write方法会自动调用start方法开始输出)。
函数原型:void start()
参数:无
返回值:无
5) stop方法
停止DA输出。之后可以调用start方法重新启动输出。
函数原型:void stop()
参数:无
返回值:无
1.1.3 串口
使用串口总线主要用到的类型是COM_T类型。本节对串口总线操作进行介绍。
1.1.3.1 使用方法及范例
在ETest系统中,串口总线操作主要由Com_T::Channel_T类型完成。
在使用Etest进行仿真模型设计和设备规划过程中,可以建立串口总线通道,并且配置参数。当通道建立完成并且参数配置完成后,系统运行环境会自动创建Com_T::Channel_T类型的通道,名称和在“仿真模型”中建立的通道名称一致。在实时脚本中,即可直接使用该对象,进行数据的采集操作。
如,交联环境如下配置:
![](https://img-blog.csdnimg.cn/img_convert/49cb26016fca8bac470c20cf2a1b8101.png)
编辑
添加图片注释,不超过 140 字(可选)
对象com0和com1即为Com_T::Channel_T类型的对象,可以用来完成串口总线功能。
示例代码如下:
/** 系统固定头文件 */ #include <Rasl/rasl.hpp> #include <DataUploader/DataUploader.hpp> #include "StaticVariable.h" #include "rasl-dpd/user.hpp" #include "UserChannels.rasi" #include "DataCollect.hpp" /** 系统固定头文件 */
//用户测试代码需要新增的头文件
namespace{ using namespace Kiyun::LowerComputer; using namespace Kiyun::LowerComputer::Rasl; using namespace Kiyun::LowerComputer::Rasl::Frame; using namespace Kiyun::LowerComputer::Rasl::Device; //通道设备命名空间 using namespace Kiyun::LowerComputer::DataUploader; //数据上传命名空间 using namespace Kiyun::Channel; using namespace Kiyun::DataCollect; //数据采集接口命名空间 using namespace Dpdp; //协议命名空间
//本地变量、本地函数声明 //Os::Semaphore_T f_exitSem; Os::Semaphore_T readDone; std::string rs; // 返回值表示“是否继续接收” bool reader(char* buf, size_t size, Error_T) { std::string temp( buf, buf + size); rs += temp; auto done = rs.size() >= 7; if (done) readDone.notifyOne(); return !done; }
void whenWriteDone(size_t size, Error_T) { KYIO(log) << "Write done : " << size; }
int sync_rw() { std::string ws = "abcdefg"; com0.write(ws.data(), ws.size());//同步写 std::string rs(7, '\0'); com1.read(&rs[0], rs.size());//同步读(定量字节) KYIO(out) << rs; return 0; }
int async_rw() { com1.intRead(reader);//注册中断读 std::string ws = "abcdefg"; //异步写 com0.asyncWrite(ws.data(), ws.size(), whenWriteDone); readDone.wait(); KYIO(out) << rs; return 0; }
}
//主函数入口 int Main() { //设置全局日志属性 KYLOG_GLOBAL().severity(Logging_T::Severity_E::TRAC_e); KYLOG_SCOPE("ETestRT::Main").tag("发送").tag("检查"); KYLOG(INFO) << "Hello world, Kiyun!\n"; //可保存到日志文件 KYIO(log) << "Hello World,Kiyun!\n"; //发送到控制台
/*测试代码*/ if(!com1.isValid()) { KYIO(err) << "COM232 channels initial failed."; return -1; //返回值需要根据该代码片段所处函数返回值类型设定 }
KYIO(log) <<com1.path();
sync_rw(); async_rw(); //f_exitSem.wait(); return 0; }
bool Exit(Os::Task_T) { //返回值为true,表示能中止正在运行的实时任务 //f_exitSem.notifyOne(); //return true;
return false; //默认情况下该实时任务不能被中止 } |
1.1.3.2 Com::Channel_T类
本类型所在命名空间为:Kiyun::LowerComputer::Rasl::Device,是进行串口总线操作的主体。具有以下类型和方法:
1) isValid方法
检测通道是否有效。强烈建议使用前判断通道合法性。
函数原型:bool isValid() const
参数:无
返回值:true:通道有效,fasle:通道无效
2) path方法
在进行数据上传时获取通道标识。
函数原型:Path_T path() const
参数:无
返回值:通道标识符
3) WriteHandler_T类型
typedef std::function<void(size_t, Error_T)> WriteHandler_T;
4) asyncWrite方法
异步输出。
函数原型:void asyncWrite(const char* buf, size_t size, WriteHandler_T whenDone)
参数:buf:输出数据的首地址;size:数据长度;whenDone:回调函数。
返回值:无
5) IntRead_T类型
typedef std::function<bool(char*, size_t, Error_T)> IntReader_T;
6) intRead方法
中断读。读取结束时调用参数中的回调函数。
函数原型:void intRead(const IntRead_T& hdl)
参数:hdl:回调函数,函数返回值表示“是否继续接收”,true继续,false停止
返回值:无
7) read方法
同步读。
函数原型:Error_T read(char* buf, size_t size, Timeout_T timeout = 1_s)
参数:buf:存放输入数据的地址;size:读取的字节数;timeout:超时等待时间,默认为1s
返回值:错误码
8) write方法
同步写
函数原型:Error_T write(const char* buf, size_t size, Timeout_T timeout = 1_s)
参数:buf:存放输出数据的地址;size:输出的字节数;timeout:超时等待时间,默认为1s
返回值:错误码
9) clear方法
清除缓冲区
函数原型:void clear();
参数:无。
返回值:无。
10) empty方法
判断缓冲区是否为空
函数原型:bool empty();
参数:无。
返回值:布尔型,是/否为空。
1.1.4 CAN
使用CAN总线主要用到的类型是Can_T类型。本节对CAN总线操作进行介绍。
1.1.4.1 使用方法及范例
在ETest系统中,CAN总线操作主要由Can_T::Channel_T类型完成。
在使用ETest进行仿真模型设计和设备规划过程中,可以建立CAN总线通道,并且配置参数。当通道建立完成并且参数配置完成后,系统运行环境会自动创建Can_T::Channel_T类型的通道,名称和在“仿真模型”中建立的通道名称一致。在实时脚本中,即可直接使用该对象,进行数据的采集操作。
如,交联环境图按照下图配置。
![](https://img-blog.csdnimg.cn/img_convert/ff8d76c7730db95538bd766f5fa32e83.png)
编辑
添加图片注释,不超过 140 字(可选)
对象f_can1和f_can2即为Can_T::Channel_T类型的对象,可以用来完成CAN总线功能。
示例脚本如下:
/** 系统固定头文件 */ #include <Rasl/rasl.hpp> #include <DataUploader/DataUploader.hpp> #include "StaticVariable.h" #include "rasl-dpd/user.hpp" #include "UserChannels.rasi" #include "DataCollect.hpp" /** 系统固定头文件 */
//用户测试代码需要新增的头文件
namespace{ using namespace Kiyun::LowerComputer; using namespace Kiyun::LowerComputer::Rasl; using namespace Kiyun::LowerComputer::Rasl::Frame; using namespace Kiyun::LowerComputer::Rasl::Device; //通道设备命名空间 using namespace Kiyun::LowerComputer::DataUploader; //数据上传命名空间 using namespace Kiyun::Channel; using namespace Kiyun::DataCollect; //数据采集接口命名空间 using namespace Dpdp; //协议命名空间 using namespace Frame; using namespace std;
//本地变量、本地函数声明 //Os::Semaphore_T f_exitSem; //Can 2路通道,0~1 void f_can_asynRead(void); void f_can_asynWrite(void); void f_can_syncRead(void); void f_can_syncWrite(void); void f_can_printf(const Can_T::CanFrame_T& frameWrite); void f_can_printf(const vector<uint8_t>& vet); }
//主函数入口 int Main() { KYIO(out) << "*******************Can Test*******************"; if (!f_can1.isValid()||!f_can2.isValid())//使用通道前,建议判断通道是否可用 { KYIO(err) << "can channels is inVaild ,exit..."; return -1; } //同步读写 f_can_syncWrite(); Timer_T::delay(0.1); f_can_syncRead(); //中断读写 f_can_asynRead(); f_can_asynWrite(); Timer_T::delay(0.1);
KYIO(log)<<f_can1.path(); KYIO(log)<<f_can2.path();
return 0; }
namespace {
void f_can_syncWrite() { Can_T::CanFrame_T frameWrite;//有默认值,标准帧数据帧 frameWrite.id = 1234; frameWrite.dataCnt = 8; for (size_t i = 0; i < frameWrite.dataCnt; i++) { frameWrite.dataBuf[i] = i + 10; } Error_T err = f_can1.write(frameWrite); if (err) KYIO(err) << "write err:" << err.message(); else KYIO(log) << "write OK"; }
void f_can_syncRead() { Can_T::CanFrame_T frameRead; auto err = f_can2.read(frameRead); if (!err) {
f_can_printf(frameRead);
KYIO(log) << "goto buf: "; auto vet = Can_T::toBuf(frameRead); f_can_printf(vet); } else { KYIO(err) << "read err:" << err.message(); } }
void f_can_asynWrite() {
Can_T::CanFrame_T frameWrite; frameWrite.idFormat = Can_T::IdMode_E::EXTENDED_e; frameWrite.frameFormat = Can_T::FrameMode_E::DATA_e; frameWrite.id = 0x02; frameWrite.dataCnt = 8; for (size_t i = 0; i < frameWrite.dataCnt; i++) { frameWrite.dataBuf[i] = i + 50; }
f_can1.asyncWrite(frameWrite, [](Error_T err) { if(!err) KYIO(out) << "async write OK"; }); }
void f_can_asynRead() { f_can2.intRead([&](Can_T::CanFrame_T frameRead,Error_T err) { static int sum = 1; f_can_printf(frameRead); if (0 == (sum++) % 10) return false; return true; }); }
void f_can_printf(const Can_T::CanFrame_T& frameRead) { std::string str = ""; char ch[20]; str.append("received | ");
sprintf(ch, "0x%04x | ", frameRead.id); str.append(ch);
if (Can_T::FrameMode_E::REMOTE_e == frameRead.frameFormat) { str.append("remote | "); } else if(Can_T::FrameMode_E::DATA_e == frameRead.frameFormat) { str.append("data | "); }
if (Can_T::IdMode_E::EXTENDED_e == frameRead.idFormat) { str.append("extended | "); } else if(Can_T::IdMode_E::STANDARD_e == frameRead.idFormat) { str.append("standard | "); } sprintf(ch, "0x%x | ", frameRead.dataCnt); str.append(ch); str.append("x| "); for (size_t i = 0; i < frameRead.dataCnt; i++) { sprintf(ch, "%02x ", frameRead.dataBuf[i]); str.append(ch); } KYIO(log) << str; }
void f_can_printf(const vector<uint8_t>& vet) { KYIO(log) << "buffer size = " << vet.size(); string str; char buffer[20]; str.append("received | "); for (auto ch : vet) { sprintf(buffer, "%02x ", ch); str.append(buffer); } KYIO(log) << str; } }
bool Exit(Os::Task_T) { //返回值为true,表示能中止正在运行的实时任务 //f_exitSem.notifyOne(); //return true;
return false; //默认情况下该实时任务不能被中止 } |
1.1.4.2 Can::Channel_T类
本类型所在命名空间为:Kiyun::LowerComputer::Rasl::Device,是进行CAN总线操作的主体。具有以下类型和方法:
1) isValid方法
检测通道是否有效。强烈建议使用前判断通道合法性。
函数原型:bool isValid() const
参数:无
返回值:true:通道有效,fasle:通道无效
2) path方法
获取通道标识,在数据上传时使用。
函数原型:Path_T path() const
参数:无
返回值:通道标识符
3) asyncWrite方法
异步输出。
函数原型:void asyncWrite(CanFrame_T& can, const WriteHandler_T& hdl)
参数:can:输出数据的首地址;hdl:回调函数。
返回值:无。
4) intRead方法
中断读。
函数原型:void intRead(const IntRead_T& hdl)
参数:hdl:回调函数,函数返回值表示“是否继续接收”,true继续,false停止。
返回值:无。
5) read方法
同步读。
函数原型:BOOL read(Can_T::CanFrame_T & frame, Timeout_T timeout = 1_s)
参数:frame:存放输入数据的地址;timeout:超时等待时间,默认为1s。
返回值:操作是否成功。
6) write方法
同步写。
函数原型:BOOL write(const Can_T::CanFrame_T & frame,Timeout_T timeout = 1_s);
参数:frame:存放输出数据的地址;timeout:超时等待时间,默认为1s
返回值:操作是否成功。
1.1.5 DI/DO接口
使用数字量输入/输出操作主要用到的类型是Dio_T类型。本节对数字量输入/输出操作进行介绍。
1.1.5.1 使用方法及范例
在ETest系统中,数字量输入/输出操作主要由Dio_T::Channel_T类型完成。
在使用Etest进行仿真模型设计和设备规划过程中,可以建立数字量输入/输出通道,并且配置参数。当通道建立完成并且参数配置完成后,系统运行环境会自动创建Dio_T::Channel_T类型的通道,名称和在“仿真模型”中建立的通道名称一致。在实时脚本中,即可直接使用该对象,进行数据的采集操作。
如,在以下范例中,创建交联环境图如下:
![](https://img-blog.csdnimg.cn/img_convert/5cdf93407da5a82f7bb05f3a0b5e5a0f.png)
编辑
添加图片注释,不超过 140 字(可选)
对象CH_数字输入_1和CH_数字输出_1即为Dio::Channel_T类型的对象,可以用来完成数字量输入/输出功能。
在设备规划中需要设置DI通道的属性“跳变检测模式”为正确的模式,才能在intRead函数中进行跳变沿检测处理。
示例代码如下:
/** 系统固定头文件 */ #include <Rasl/rasl.hpp> #include <DataUploader/DataUploader.hpp> #include "StaticVariable.h" #include "rasl-dpd/user.hpp" #include "UserChannels.rasi" #include "DataCollect.hpp" /** 系统固定头文件 */
//用户测试代码需要新增的头文件
namespace{ using namespace Kiyun::LowerComputer; using namespace Kiyun::LowerComputer::Rasl; using namespace Kiyun::LowerComputer::Rasl::Frame; using namespace Kiyun::LowerComputer::Rasl::Device; //通道设备命名空间 using namespace Kiyun::LowerComputer::DataUploader; //数据上传命名空间 using namespace Kiyun::Channel; using namespace Kiyun::DataCollect; //数据采集接口命名空间 using namespace Dpdp; //协议命名空间
//本地变量、本地函数声明 //Os::Semaphore_T f_exitSem; }
//主函数入口 int Main() { //设置全局日志属性 KYLOG_GLOBAL().severity(Logging_T::Severity_E::TRAC_e); KYLOG_SCOPE("ETestRT::Main").tag("发送").tag("检查"); KYLOG(INFO) << "Hello world, Kiyun!\n"; //可保存到日志文件 KYIO(log) << "Hello World,Kiyun!\n"; //发送到控制台
/*测试代码*/ if(!CH_数字输出_1.isValid()) { KYIO(err) << "CH_数字输出_1 channels initial failed."; return -1; //返回值需要根据该代码片段所处函数返回值类型设定 }
KYIO(log) <<CH_数字输出_1.path();
if(!CH_数字输入_1.isValid()) { KYIO(err) << "CH_数字输出_1 channels initial failed."; return -1; //返回值需要根据该代码片段所处函数返回值类型设定 }
KYIO(log) <<CH_数字输入_1.path();
CH_数字输入_1.intRead([](int chID,int state) { KYIO(out) << "Notify ..." << chID << " "<< state; return true; });
CH_数字输出_1.write(TRUE); Timer_T::delay(1); if (CH_数字输入_1.read()) { KYIO(log) << "DI HIGH"; } else { KYIO(log) << "DI LOW"; } Timer_T::delay(5);
CH_数字输出_1.write(FALSE); Timer_T::delay(1); if (CH_数字输入_1.read()) { KYIO(log) << "DI HIGH"; } else { KYIO(log) << "DI LOW"; } CH_数字输出_1.write(TRUE); Timer_T::delay(1);
Timer_T::delay(5);
//f_exitSem.wait(); return 0; }
bool Exit(Os::Task_T) { //返回值为true,表示能中止正在运行的实时任务 //f_exitSem.notifyOne(); //return true;
return false; //默认情况下该实时任务不能被中止 } |
1.1.5.2 Dio::Channel_T类
该类所在的命名空间:Kiyun::LowerComputer::Rasl::Device。具有以下方法:
1) isValid方法
检测通道是否有效。强烈建议使用前判断通道有效性。
函数原型:bool isValid() const
参数:无
返回值:true:通道有效,fasle:通道无效。
2) path方法
获取通道标识。数据上传时会用到。
函数原型:Path_T path() const
参数:无
返回值:通道标识符
3) read方法
获取数字量输入或者状态。
函数原型:BOOL read();
参数:无
返回值:输出状态,TRUE为高电平,FALSE为低电平。
4) write方法
设置数字量输出状态。
函数原型:void write(BOOL status)
参数:status:输出状态,TRUE为高电平,FALSE为低电平
返回值:无
5) intRead方法
数字量输入跳变检测。
函数原型:void intRead(Channel_T::IORVectorHandler_T inputRVector)
参数:inputRVector 跳变检测回调函数,函数说明为:
Bool inputRVector(int id,int state)
参数id为发生跳变的通道号。
参数state为当前通道的状态(0或者1)。
返回值表示“是否继续检测”,true继续,false停止。
返回值:无
1.1.6 1553B接口
使用UDP接口操作主要用到的类型是M1553_T类型。本节对1553B接口操作进行介绍。
1.1.6.1 使用方法及范例
在ETest系统中,1553B接口操作主要由M1553_T类型完成。
在使用Etest进行仿真模型设计和设备规划过程中,可以建立1553BC、1553RT、1553MT、1553BSP通道,并且配置参数。当通道建立完成并且参数配置完成后,系统运行环境会自动创建对于类型的通道,名称和在“仿真模型”中建立的通道名称一致。在实时脚本中,即可直接使用该对象,进行数据的读/写操作。
创建仿真模型如下图所示。
![](https://img-blog.csdnimg.cn/img_convert/8631155c729502b4cfccc27520902c70.png)
编辑
添加图片注释,不超过 140 字(可选)
图 1 1553范例仿真模型
在设备规划中,选中设备,在“属性”窗体编辑属性,建立消息列表。
![](https://img-blog.csdnimg.cn/img_convert/0b39ffdac3b3e4200af6099435f03191.png)
编辑
添加图片注释,不超过 140 字(可选)
图 2 1553范例设备规划
![](https://img-blog.csdnimg.cn/img_convert/132413bc29ebd30816eac05c8455fb3f.png)
编辑
添加图片注释,不超过 140 字(可选)
图 3 1553范例消息编辑器
编写如下实时脚本,完成消息的收发。
同步读写:
/** 系统固定头文件 */ #include <Rasl/rasl.hpp> #include <DataUploader/DataUploader.hpp> #include "StaticVariable.h" #include "rasl-dpd/user.hpp" #include "UserChannels.rasi" #include "DataCollect.hpp" /** 系统固定头文件 */ //#define MC_APPNAME "M1553-TEST" #include <Rasl/rasl.hpp>
namespace {
using namespace Kiyun::LowerComputer; using namespace Kiyun::LowerComputer::Rasl; using namespace Kiyun::LowerComputer::Rasl::Frame; using namespace Kiyun::LowerComputer::Rasl::Device; //通道设备命名空间 using namespace Kiyun::LowerComputer::DataUploader; //数据上传命名空间 using namespace Kiyun::Channel; using namespace Kiyun::DataCollect; //数据采集接口命名空间 using namespace Dpdp; //协议命名空间
using namespace std; using namespace Mince::LowerComputer::Rasl; using namespace Mince::LowerComputer::Rasl::Frame; using namespace Mince::LowerComputer::Rasl::Device; void fc_msgPrint(M1553_T::RecvMsg_T* rmsg, size_t size); void fc_msgPrint(const std::vector<uint8_t>& buf); }
int test1553() {
MCIO(log) << "-------------1553 TEST-----------------"; if (!mt.isValid()) { MCIO(err) << "bm is inValid...exit"; return -1; } if (!dsp.isValid()) { MCIO(err) << "dsp is inValid...exit"; return -1; }
uint16_t outData[32] = {0}; for (int i = 0; i < 32; i++) outData[i] = 0x1234 + i;
//BC to RT bc0.write(outData, 32);
//RT to BC outData[0] = 0x4321; rt5.write(outData, 32);
//RT to RT outData[0] = 0x2134; rt2.write(outData, 32);
//执行消息 dsp.write(0); dsp.write(1); dsp.write(2);
//延时保证消息已处理 Timer_T::delay(0.1);
MCIO(log) << "-------------BC READ-----------------"; fc_msgPrint(bc0.read()); fc_msgPrint(bc1.read()); fc_msgPrint(bc2.read());
MCIO(log) << "-------------RT READ-----------------"; MCIO(log) << "------rt 2,7 read"; fc_msgPrint(rt2.read()); MCIO(log) << "------rt 5,8 read"; fc_msgPrint(rt5.read());
MCIO(log) << "-------------MT READ-----------------";
//fc_msgPrint(mt.read()); M1553_T::RecvMsg_T rmsg[10]; size_t res = 0; auto err = mt.read(rmsg, 10, res); if (!err) fc_msgPrint(rmsg, res); else MCIO(err) << "BM read err:" << err.message(); return 0; }
int Main() { return test1553(); }
namespace {
void fc_msgPrint(M1553_T::RecvMsg_T* rmsg, size_t size) { char ch[100]; std::string str; for (size_t i = 0; i < size; i++) { str = ""; snprintf(ch, sizeof(ch), "bsw = 0x%04x,", rmsg[i].bsw); str.append(ch); snprintf(ch, sizeof(ch), "cmd1 = 0x%04x,", rmsg[i].msgBlock.cmdWord1); str.append(ch); snprintf(ch, sizeof(ch), "cmd2 = 0x%04x,", rmsg[i].msgBlock.cmdWord2); str.append(ch); str.append(" data : "); for (size_t j = 0; j < 32; ++j) { snprintf(ch, sizeof(ch), "%04x ", rmsg[i].msgBlock.dataBlk[j]); str.append(ch); } MCIO(log) << str; } }
void fc_msgPrint(const std::vector<uint8_t>& buf) { char ch[100]; std::string str;
auto wordBuf = M1553_T::toWord(buf);
for (const auto& val: wordBuf) { snprintf(ch, 100, "%04x ", val); str.append(ch); } MCIO(log) <<"data : "<< str; } } |
异步读写
/** 系统固定头文件 */ #include <Rasl/rasl.hpp> #include <DataUploader/DataUploader.hpp> #include "StaticVariable.h" #include "rasl-dpd/user.hpp" #include "UserChannels.rasi" #include "DataCollect.hpp" /** 系统固定头文件 */ //#define MC_APPNAME "M1553-TEST" #include <Rasl/rasl.hpp>
namespace {
using namespace Kiyun::LowerComputer; using namespace Kiyun::LowerComputer::Rasl; using namespace Kiyun::LowerComputer::Rasl::Frame; using namespace Kiyun::LowerComputer::Rasl::Device; //通道设备命名空间 using namespace Kiyun::LowerComputer::DataUploader; //数据上传命名空间 using namespace Kiyun::Channel; using namespace Kiyun::DataCollect; //数据采集接口命名空间 using namespace Dpdp; //协议命名空间
using namespace std; using namespace Mince::LowerComputer::Rasl; using namespace Mince::LowerComputer::Rasl::Frame; using namespace Mince::LowerComputer::Rasl::Device; void fc_msgPrint(M1553_T::RecvMsg_T* rmsg, size_t size); void fc_msgPrint(const std::vector<uint8_t>& buf); }
int test1553() {
MCIO(log) << "-------------1553 TEST-----------------"; if (!mt.isValid()) { MCIO(err) << "bm is inValid...exit"; return -1; } if (!dsp.isValid()) { MCIO(err) << "dsp is inValid...exit"; return -1; }
uint16_t outData[32] = {0}; for (int i = 0; i < 32; i++) outData[i] = 0x1234 + i;
//BC to RT bc0.write(outData, 32);
//RT to BC outData[0] = 0x4321; rt5.write(outData, 32);
//RT to RT outData[0] = 0x2134; rt2.write(outData, 32);
//执行消息 dsp.write(0); dsp.write(1); dsp.write(2);
//延时保证消息已处理 Timer_T::delay(0.1);
dsp.write(0, false); Timer_T::delay(1);
if (!dsp.isRunning()) MCIO(log) << "bc stoped..."; else MCIO(log) << "bc is running...";
uint32_t isRunning = 1; while (isRunning) { isRunning = dsp.isRunning(); } printf("BC stopped.\n");
bc0.intRead([&](uint16_t * buf, size_t size,Error_T err)->bool { MCIO(log) << "-----------------------bc intRead:" << (int)buf[0]; return true; });
rt2.intRead([&](uint16_t * buf, size_t size, Error_T err)->bool { MCIO(log) << "-----------------------rt intRead:" << (int)buf[0]; return true; });
mt.intRead([&](uint16_t * buf, size_t size, Error_T err)->bool { MCIO(log) << "------------------------mt intRead:" << (int)buf[0]; return true; });
return 0; }
int Main() { return test1553(); }
namespace {
void fc_msgPrint(M1553_T::RecvMsg_T* rmsg, size_t size) { char ch[100]; std::string str; for (size_t i = 0; i < size; i++) { str = ""; snprintf(ch, sizeof(ch), "bsw = 0x%04x,", rmsg[i].bsw); str.append(ch); snprintf(ch, sizeof(ch), "cmd1 = 0x%04x,", rmsg[i].msgBlock.cmdWord1); str.append(ch); snprintf(ch, sizeof(ch), "cmd2 = 0x%04x,", rmsg[i].msgBlock.cmdWord2); str.append(ch); str.append(" data : "); for (size_t j = 0; j < 32; ++j) { snprintf(ch, sizeof(ch), "%04x ", rmsg[i].msgBlock.dataBlk[j]); str.append(ch); } MCIO(log) << str; } }
void fc_msgPrint(const std::vector<uint8_t>& buf) { char ch[100]; std::string str;
auto wordBuf = M1553_T::toWord(buf);
for (const auto& val: wordBuf) { snprintf(ch, 100, "%04x ", val); str.append(ch); } MCIO(log) <<"data : "<< str; } } |