1553B板卡详解

news2024/9/22 13:31:30

个人博客地址: https://cxx001.gitee.io

简介

1553b板卡主要应用于航天航空工业领域,它的数据传输结构有点类似集中分布式服务器的设计,分为BC、RT、BM三类部件,BC有且仅有1个,类似我们的master管理服务节点,RT有0~32个,类似我们的各业务服务节点,BM则是监控节点。所以按传统服务器设计结构也很好理解1553B了。

环境安装

  1. 安装驱动,驱动盘里有个imsk的脚本执行一下就好了,需要注意的是驱动版本一定要与板卡一致。

  2. 接线,各通道的线通过耦合器连到一起就可以了。

    在这里插入图片描述

模拟工具

在windows上提供了一个测试工具,FlightPack-1553B可以与自己封装的1553B模块对测。

在这里插入图片描述

BC设置,我一般用的子帧模式,添加需要的消息,主要是BC有些设置,其它基本没什么要设置的,像RT基本就是使能下就可以了。

在这里插入图片描述

模块封装

RT封装倒是比较简单,直接参考示例程序就行了,没什么特别的,主要是BC的封装,有几个点需要注意,它是一个管理类,消息个数是可以动态添加的,而且默认子帧模式,消息有开始和结束形成一个环。还一点特别注意在设置RT->RT消息时,消息块的cmd_wd1字段只能是接收,cmd_wd2只能是发送。

1. RT

#include "CtrlSysLibTool.h"
#include "Port_1553B_RT.h"

#ifdef WIN32
#include <windows.h>
#endif

#include "json.hpp"
#include "kl_common_info.h"
#include <stdio.h>
#include <string.h>

struct CAV1553B_RT_INFO {
    CAV1553B_RT_INFO(CORE_U16 dev_num, CORE_U32 channel_num, CORE_U16 rt_addr, CORE_U16 sub_addr)
        : dev_num_(dev_num), channel_num_(channel_num), rt_addr_(rt_addr), sub_addr_(sub_addr)
    {
        memset(&rt_sabuf_, 0, sizeof(rt_sabuf_));
        rt_sabuf_.legal_wc = 0xFFFFFFFF;
        data_size_ = sizeof(rt_sabuf_.data_wds);
    }

    CORE_RT_SA_BUFFER rt_sabuf_; // rt读写buffer
    int data_size_;              // data_wds数据的长度,这里会默认32个CORE_U16(unsigned short)
    CORE_U16 dev_num_;           // 设备号
    CORE_U32 channel_num_;       // 通道号
    CORE_U16 rt_addr_;           // RT 地址,取值范围 0~31;
    CORE_U16 sub_addr_;          // RT 子地址,取值范围 0~31;
    std::map<std::pair<CORE_U16, CORE_U32>, bool>
            *init_info_1553b_;     // 记录通道初始化情况,相同的dev_num及channel_num只初始化一次
    std::vector<std::string> vars; // 存储协议字段的类型
};

/***********************************
        内部变量初始化
        内部变量:rtinfo_
***********************************/
int32_t Block_Port_1553B_RT::initInternalVariable()
{
    LOG_INFO("CAV1553BInit start...\n");
    // Devnum 由设备编号和 1553 板卡类型组成。其中:
    // 1)设备编号:设备编号(从 0 开始编号),取值范围 0~3。
    // 2)1553 板卡类型:
    // devnum = (0 | PCI_1553_TYPE),代表的是 PCI1553 板卡,设备 0;
    // devnum = (1 | PCI_1553_TYPE),代表的是 PCI1553 板卡,设备 1;
    // devnum = (0 | USB_1553_TYPE),代表的是 USB1553 板卡,设备 0;
    // devnum = (1 | USB_1553_TYPE),代表的是 USB1553 板卡,设备 1。
    CORE_U16 dev_num = (CORE_U16)P(devNum) | PCI_1553_TYPE;
    CORE_U32 channel_num = P(channelNum);
    CORE_U16 rt_addr = P(rtAddr);
    CORE_U16 sub_addr = P(subAddr);

    rtinfo_ = new CAV1553B_RT_INFO(dev_num, channel_num, rt_addr, sub_addr);
    CAV1553B_RT_INFO *rtinfo = static_cast<CAV1553B_RT_INFO *>(rtinfo_);
    rtinfo->init_info_1553b_ = GetInitInfo_1553b();

    auto iter = rtinfo->init_info_1553b_->find({ dev_num, channel_num });
    // 没有找到,或者找到了但是为false,则表示未初始化,那么进行相关初始化操作
    if (iter == rtinfo->init_info_1553b_->end()) {
        // 该函数用于初始化某一个板卡的通道。三个参数分别为:设备号、通道号、中断队列长度(取值:4,8,16,32,64,128,256。)
        // SUCCESS:设备初始化成功;FAILURE:设备初始化失败。
        if (FAILURE == CORE_GEN_Full_Init(dev_num, channel_num, 16)) {
            return false;
        }
        LOG_INFO("CORE_GEN_Full_Init finished...\n");

        // CORE_RT_Multiple_Is_Supported 用于查看板卡是否支持多 RT 功能。
        // 1:支持多 RT;0:不支持多 RT。
        int multiple = CORE_RT_Multiple_Is_Supported(dev_num, channel_num);
        if (!multiple && rt_addr > 0) {
            LOG_ERROR("not support multiple,channel_num = %d\n", (int)channel_num);
            return false;
        }
        LOG_INFO("CORE_RT_Multiple_Is_Supported finished...\n");

        // CORE_RT_Init 用于初始化板卡中的 RT 功能,进行 RT 内存分配,在用 RT 功能之前,需要调用此函数。
        // SUCCESS:RT 初始化成功;FAILURE:RT 初始化失败。
        if (FAILURE == CORE_RT_Init(dev_num, channel_num)) {
            LOG_ERROR("Initializing RT Failure,channel_num = %d\n", (int)channel_num);
            return false;
        }
		
		rtinfo->init_info_1553b_->insert({ { dev_num, channel_num }, true });
		
        LOG_INFO("CORE_RT_Init finished...\n");
    }

    // CORE_RT_Enable 用来使能某一特定的 RT 地址,使其有效。使用任何 RT 之前都需要使能这个 RT 地址,否则 RT
    // 将不工作。
    CORE_RT_Enable(dev_num, channel_num, rt_addr);

    // CORE_RT_Allocate_SA_Buffers 为特定的 RT 的子地址分配一个或者多个缓冲区,用于存储相关数据
    // SUCCESS:RT 缓冲分配成功;FAILURE:RT 缓冲分配失败。
    // devnum:见上面注释;
    // channel_num:通道编号(从 0 开始编号),取值范围 0~3;
    // rt:RT 地址,取值范围 0~31;
    // tr:发送还是接收。 1:发送;0:接收;
    // sa:RT 子地址,取值范围 0~31;
    // num_bufs:要分配多少个缓冲 buffer。
    CORE_U16 tr = 0;
    if (P(bsend)) {
        tr = 1;
    }
    if (FAILURE == CORE_RT_Allocate_SA_Buffers(dev_num, channel_num, rt_addr, tr, sub_addr, 1)) {
        LOG_ERROR("Allocating Failure,channel_num = %d\n", (int)channel_num);
        return false;
    }
    LOG_INFO("CORE_RT_Allocate_SA_Buffers finished...\n");

    if (FAILURE == CORE_RT_Write_SA_Buffer(dev_num, channel_num, rt_addr, tr, sub_addr, 0, &rtinfo->rt_sabuf_)) {
        return false;
    }

    // CORE_RT_Start运行已经配置好的 RT 。
    CORE_RT_Start(dev_num, channel_num);

    /*****************************解析协议json文件, 将协议字段的类型放入数组中***********************/
    nlohmann::ordered_json root;
#ifdef _WIN32
    std::ifstream(P(filename).c_str()) >> root;
#else
    std::string strfilePath = P(filename).c_str();
    std::string strfile = "protocol/" + strfilePath.substr(strfilePath.find_last_of("/") + 1);
    if (access(strfile.c_str(), F_OK) == -1) {
        return false;
    }
    std::ifstream(strfile.c_str()) >> root;
#endif

    nlohmann::ordered_json child = root["Protocol fields"];
    for (auto &item : child.items()) {
        rtinfo->vars.push_back(item.value()["type"]);
        // std::string tp = item.value()["type"];
        // LOG_ERROR("type=%s\n", tp.c_str());
    }

    bool bi = P(bsend) && I(p_dynamic_Input_).size_ != rtinfo->vars.size();
    bool bo = !P(bsend) && O(p_dynamic_Output_).size_ != rtinfo->vars.size();
    if (bi || bo) {
        // 如果动态输入端口的个数与协议字段的个数不一致则有错误
        return false;
    }

    binit_ = true; // 标识已完成初始化
    LOG_INFO("CAV1553BInit  success...\n");
    return true;
}

/**********************************
        在此函数中编写自定义代码
        输入变量:
        输出变量:
        参数:bsend, channelNum, devNum, filename, rtAddr, subAddr
        状态变量:
        示例:O(输出变量) = I(输入变量) + P(参数)
***********************************/
void Block_Port_1553B_RT::runAlgorithm(void *extra)
{
    CAV1553B_RT_INFO *rtinfo = static_cast<CAV1553B_RT_INFO *>(rtinfo_);

    //memset(&rtinfo->rt_sabuf_, 0, sizeof(rtinfo->rt_sabuf_)); // 清空上次数据
    if (P(bsend)) {
        // 作为发送模块
        size_t offset = 0;
        for (size_t i = 0; i < rtinfo->vars.size(); i++) {
            if (1 == P(checkType) && i == rtinfo->vars.size() - 1) {
                // checkType==1时为crc校验
                uint16_t crc = get_crc16((uint8_t *)rtinfo->rt_sabuf_.data_wds, offset);
                memcpy(rtinfo->rt_sabuf_.data_wds + offset, &crc, sizeof(uint16_t));
                offset += sizeof(uint16_t);
            }

            size_t var_len = type_len(rtinfo->vars[i]);
            convert_var_to_buffer(rtinfo->vars[i], offset, (uint8_t *)rtinfo->rt_sabuf_.data_wds,
                                  I(p_dynamic_Input_).ptr_[i], var_len);
            offset += var_len;
        }

        // 不能超过缓存大小
        if (offset <= rtinfo->data_size_) {
            if (SUCCESS
                == CORE_RT_Write_SA_Buffer(rtinfo->dev_num_, rtinfo->channel_num_, rtinfo->rt_addr_, 1,
                                           rtinfo->sub_addr_, 0, &rtinfo->rt_sabuf_)) { }
        }
    } else {
        // 作为接收模块
        if (SUCCESS
            == CORE_RT_Read_SA_Buffer(rtinfo->dev_num_, rtinfo->channel_num_, rtinfo->rt_addr_, 0, rtinfo->sub_addr_, 0,
                                      &rtinfo->rt_sabuf_)) {
            size_t offset = 0;
            for (size_t i = 0; i < rtinfo->vars.size(); i++) {
                if (1 == P(checkType) && i == rtinfo->vars.size() - 1) {
                    // checkType==1时为crc校验
                    uint16_t crc = get_crc16((uint8_t *)rtinfo->rt_sabuf_.data_wds, offset); // 先计算自己的crc
                    uint16_t *recv_crc = (uint16_t *)(rtinfo->rt_sabuf_.data_wds + offset); // 解析收到数据包的crc字段
                    if (crc != *recv_crc) {
                        // 错误信息
                    }
                    offset += sizeof(uint16_t);
                }

                size_t var_len = type_len(rtinfo->vars[i]);
                *O(p_dynamic_Output_).ptr_[i] =
                        convert_buffer_to_var(rtinfo->vars[i], offset, (uint8_t *)rtinfo->rt_sabuf_.data_wds);
                offset += var_len;
            }
        }
    }
}

/**********************************
在此函数中编写自定义积分函数
***********************************/
int32_t Block_Port_1553B_RT::integral(int32_t msg, double t, double *state, double *derivative)
{
    return 0;
}

/**********************************
        在此函数中释放内部变量资源
        内部变量:rtinfo_
***********************************/
void Block_Port_1553B_RT::destroyInternalVariable()
{
    // 是否调用了初始化函数,默认为false(控制引擎会出现直接调用destroy的情况,而成员变量si_未初始化被使用会导致崩溃)
    if (!binit_) {
        return;
    }
    CAV1553B_RT_INFO *rtinfo = static_cast<CAV1553B_RT_INFO *>(rtinfo_);

    CORE_RT_Disable(rtinfo->dev_num_, rtinfo->channel_num_, rtinfo->rt_addr_);

    auto iter = rtinfo->init_info_1553b_->find({ rtinfo->dev_num_, rtinfo->channel_num_ });
    if (iter == rtinfo->init_info_1553b_->end() || !iter->second) {
        CORE_RT_Stop(rtinfo->dev_num_, rtinfo->channel_num_);
    }

    delete rtinfo;
}

2. BC

#include "CtrlSysLibTool.h"
#include "Port_1553B_BC.h"

#ifdef WIN32
#include <windows.h>
#endif

#include "json.hpp"
#include "kl_common_info.h"
#include <stdio.h>
#include <string.h>

struct CAV1553B_BC_INFO {
    CAV1553B_BC_INFO(CORE_U16 dev_num, CORE_U32 channel_num, doubleVector& rt_addr, doubleVector& sub_addr, doubleVector& msg_type)
        : dev_num_(dev_num)
        , channel_num_(channel_num)
        , init_info_1553b_(nullptr)
    {
        memset(&bc_sabuf_, 0, sizeof(bc_sabuf_));
        data_size_ = sizeof(bc_sabuf_.data_wds);
        for (int i = 0; i < 32; i++) {
            rt_addr_[i] = (CORE_U16)rt_addr[i];
            sub_addr_[i] = (CORE_U16)sub_addr[i];
            msg_type_[i] = (CORE_U16)msg_type[i];
        }
    }

    CORE_BC_MSG_BUFFER bc_sabuf_; // bc读写buffer
    int data_size_; // data_wds数据的长度,这里会默认32个CORE_U16(unsigned short)
    CORE_U16 dev_num_; // 设备号
    CORE_U32 channel_num_; // 通道号
    CORE_U16 rt_addr_[32]; // RT 地址,取值范围 0~31;
    CORE_U16 sub_addr_[32]; // RT 子地址,取值范围 0~31;
    CORE_U16 msg_type_[32]; // BC消息类型,如rt->bc,bc->rt,rt->rt
    std::map<std::pair<CORE_U16, CORE_U32>, bool>* init_info_1553b_; // 记录通道初始化情况,相同的dev_num及channel_num只初始化一次
    std::vector<std::vector<std::string>> bc_rt_vars; // 存储bc->rt协议字段的类型
    std::vector<std::vector<std::string>> rt_bc_vars; // 存储rt->bc协议字段的类型
    std::vector<int> bc_rt_nums; // bc->rt消息个数
    std::vector<int> rt_bc_nums; // rt->bc消息个数
};

/***********************************
        内部变量初始化
        内部变量:bcinfo_
***********************************/
int32_t Block_Port_1553B_BC::initInternalVariable()
{
    LOG_INFO("CAV1553B_BC_Init start...\n");
    // Devnum 由设备编号和 1553 板卡类型组成。其中:
    // 1)设备编号:设备编号(从 0 开始编号),取值范围 0~3。
    // 2)1553 板卡类型:
    // devnum = (0 | PCI_1553_TYPE),代表的是 PCI1553 板卡,设备 0;
    // devnum = (1 | PCI_1553_TYPE),代表的是 PCI1553 板卡,设备 1;
    // devnum = (0 | USB_1553_TYPE),代表的是 USB1553 板卡,设备 0;
    // devnum = (1 | USB_1553_TYPE),代表的是 USB1553 板卡,设备 1。
    CORE_U16 dev_num = (CORE_U16)P(devNum) | PCI_1553_TYPE;
    CORE_U32 channel_num = (CORE_U32)P(channelNum);

    bcinfo_ = new CAV1553B_BC_INFO(dev_num, channel_num, P(rtAddr), P(subAddr), P(msgType));
    CAV1553B_BC_INFO* bcinfo = static_cast<CAV1553B_BC_INFO*>(bcinfo_);
    bcinfo->init_info_1553b_ = GetInitInfo_1553b();

    size_t block_count = P(msgType).size();
    auto iter = bcinfo->init_info_1553b_->find({ dev_num, channel_num });
    // 没有找到,或者找到了但是为false,则表示未初始化,那么进行相关初始化操作
    if (iter == bcinfo->init_info_1553b_->end() || !iter->second) {
        // 该函数用于初始化某一个板卡的通道。三个参数分别为:设备号、通道号、中断队列长度(取值:4,8,16,32,64,128,256。)
        // SUCCESS:设备初始化成功;FAILURE:设备初始化失败。
        if (FAILURE == CORE_GEN_Full_Init(dev_num, channel_num, 16)) {
            return false;
        }
        LOG_INFO("CORE_GEN_Full_Init finished...\n");

        /*
        CORE_BC_Is_Supported 查看板卡是否支持 BC 功能。
        1:支持 BC;
        0:不支持 BC
        */
        int surportBC = CORE_BC_Is_Supported(dev_num, channel_num);
        if (!surportBC) {
            LOG_ERROR("not support BC,channel_num = %d\n", (int)channel_num);
            return false;
        }

        LOG_INFO("CORE_BC_Is_Supported finished...\n");

        /*
            CORE_BC_Init 用于初始化板卡中的 BC 功能,设置 BC 需要发送的消息个数
            devnum:设备号;
            channel_num:通道编号(从 0 开始编号),取值范围 0~3;
            num_blocks:所需建立的 BC BLOCK 的个数;
            frame_us:以 us 为单位的子帧时间间隔,取值范围 40~0xFFFFFFFF;
            wTimeout1:无响应时间,单位 us,取值范围 0~31。当 wTimeout1 和 wTimeout2都为 0
           时为不设置延时时间,使用系统默认时间); wTimeout2:最迟响应时间,单位 us,取值范围 0~31。(当 wTimeout1 和
           wTimeout2都为 0 时为不设置延时时间,使用系统默认时间)
        */
        if (CORE_BC_Init(dev_num, channel_num, block_count, 100000, 0, 0) == FAILURE) {
            LOG_ERROR("Initializing BC Failure,channel_num = %d\n", (int)channel_num);
            return false;
        }
        LOG_INFO("CORE_BC_Init finished...\n");
    } else {
        LOG_ERROR("BC is Initializing\n");
        return false;
    }

    CORE_BC_BLOCK bc_block;
    for (int i = 0; i < block_count; i++) {
        /*
        CORE_BC_Allocate_Msg_Buffers 为特定的 BC Block 分配 Message Buffers。
        devnum:设备号;
        channel_num:通道编号(从 0 开始编号),取值范围 0~3;
        msg_num:BC Block 编号(需要为哪个 BLOCK 分配消息);
        num_buffs:所需分配的消息的个数,默认值为 1。
        */
        if (CORE_BC_Allocate_Msg_Buffers(dev_num, channel_num, i, 1) == FAILURE) {
            LOG_ERROR("CORE_BC_Allocate_Msg_Buffers  Failure,channel_num = %d\n", (int)channel_num);
            return false;
        }

        memset(&bc_block, 0, sizeof(bc_block));
        int bcMsgType = (int)P(msgType)[i];
        if (0 == i) {
            bc_block.next_msg_num = i + 1;
            bc_block.bc_control_wd = bcMsgType | BC_BLOCK_FRAME_BEGIN | BC_BLOCK_FLAG_BUS_A;
        } else if (block_count - 1 == i) {
            bc_block.next_msg_num = 0;
            bc_block.bc_control_wd = bcMsgType | BC_BLOCK_FRAME_END | BC_BLOCK_FLAG_BUS_A;
        } else {
            bc_block.next_msg_num = i + 1;
            bc_block.bc_control_wd = bcMsgType | BC_BLOCK_FLAG_BUS_A;
        }
        /*
            CORE_Set_BC_Command 组合 MIL-STD-1553B BC 的命令字。
            devnum:设备号
            channel_num:通道编号(从 0 开始编号),取值范围 0~3;
            RT:RT 地址,取值范围 0~31;
            tr:发送还是接收。1 代表发送,0 代表接收;
            data_count:数据字个数,取值范围:0~31(0 代表 32 个字);
            如果消息是 ModeCode 类型,data_count 代表的是模式代码。
            subaddr:RT 子地址,取值范围 0~31
        */
		if (bcMsgType == BC_BLOCK_TYPE_MSG_RTRT) {
			// 当消息类型为RT->RT时,接收的RT必须设置到cmd_wd1中,发送的RT设置到cmd_wd2中
			if (0 == P(rtType)[i]) {
				bc_block.cmd_wd1 = CORE_Set_BC_Command(dev_num, channel_num, P(rtAddr)[i], P(rtType)[i], 0, P(subAddr)[i]);
				bc_block.cmd_wd2 = CORE_Set_BC_Command(dev_num, channel_num, P(rtAddr)[i + 1], P(rtType)[i + 1], 0, P(subAddr)[i + 1]);
			} else {
				bc_block.cmd_wd1 = CORE_Set_BC_Command(dev_num, channel_num, P(rtAddr)[i + 1], P(rtType)[i + 1], 0, P(subAddr)[i + 1]);
				bc_block.cmd_wd2 = CORE_Set_BC_Command(dev_num, channel_num, P(rtAddr)[i], P(rtType)[i], 0, P(subAddr)[i]);
			}
        } else {
            bc_block.cmd_wd1 = CORE_Set_BC_Command(dev_num, channel_num, P(rtAddr)[i], P(rtType)[i], 0, P(subAddr)[i]);
        }
        bc_block.im_gap = 10;

        /*
            CORE_BC_Write_Block 函数将用户设置好的 BC BLOCK,通过向 API 函数传入结构体的方式写到板卡内存中。
            devnum:设备号;
            channel_num:通道编号(从 0 开始编号),取值范围 0~3;
            msg_num:BC BLOCK 编号(需要为哪个 BLOCK 分配消息);
            bc_block:需设置的 BC BLOCK 结构体
        */
        if (CORE_BC_Write_Block(dev_num, channel_num, i, &bc_block) == FAILURE) {
            LOG_ERROR("CORE_BC_Write_Block  Failure,channel_num = %d\n", (int)channel_num);
            return false;
        }

        if (bcMsgType == BC_BLOCK_TYPE_MSG_BCRT) {
            /*
                CORE_BC_Write_Buffer 函数将用户设置好的 BC BLOCK 对应的消息,通过向API 函数传入结构体的方式写到板卡内存中
                devnum:设备号
                channel_num:通道编号(从 0 开始编号),取值范围 0~3;
                msg_num:BC BLOCK 编号(需要为哪个 BLOCK 分配消息);  // 指定分配的通道
                buffnum:BC BLOCK 对应的消息编号;
                msg_buff:需设置的 CORE_BC_MSG_BUFFER 结构体的指针。
            */
            if (CORE_BC_Write_Buffer(dev_num, channel_num, i, 0, &bcinfo->bc_sabuf_) == FAILURE) { // 这里自定义一个编号吧
                LOG_ERROR("CORE_BC_Write_Buffer  Failure,channel_num = %d\n", (int)channel_num);
                return false;
            }
            bcinfo->bc_rt_nums.push_back(i);
        } else if (bcMsgType == BC_BLOCK_TYPE_MSG_RTBC) {
            bcinfo->rt_bc_nums.push_back(i);
        }
    }

    // CORE_BC_Start 运行已经配置好的 BC
    CORE_BC_Start(dev_num, channel_num, 0);

    /*****************************解析协议json文件, 将协议字段的类型放入数组中***********************/
    nlohmann::ordered_json root;
#ifdef _WIN32
    std::ifstream(P(filename).c_str()) >> root;
#else
    std::string strfilePath = P(filename).c_str();
    std::string strfile = "protocol/" + strfilePath.substr(strfilePath.find_last_of("/") + 1);
    if (access(strfile.c_str(), F_OK) == -1) {
        return false;
    }
    std::ifstream(strfile.c_str()) >> root;
#endif

    for (const auto& field : root["Protocol fields"]["bc_rt"]) {
        std::vector<std::string> innerVector;
        for (const auto& subfield : field) {
            innerVector.push_back(subfield["type"]);
        }
        if (innerVector.size() > 0) {
            bcinfo->bc_rt_vars.push_back(innerVector);
        }
    }

    for (const auto& field : root["Protocol fields"]["rt_bc"]) {
        std::vector<std::string> innerVector;
        for (const auto& subfield : field) {
            innerVector.push_back(subfield["type"]);
        }
        bcinfo->rt_bc_vars.push_back(innerVector);
    }

    binit_ = true; // 标识已完成初始化
    LOG_INFO("CAV1553B_BC_Init  success...\n");
    return true;
}

/**********************************
        在此函数中编写自定义代码
        输入变量:
        输出变量:
        参数:bsend, channelNum, devNum, filename, rtAddr, subAddr
        状态变量:
        示例:O(输出变量) = I(输入变量) + P(参数)
***********************************/
void Block_Port_1553B_BC::runAlgorithm(void* extra)
{
    CAV1553B_BC_INFO* bcinfo = static_cast<CAV1553B_BC_INFO*>(bcinfo_);

    // BC->RT
    size_t pos = 0;
    for (size_t i = 0; i < bcinfo->bc_rt_nums.size(); i++) {
        size_t offset = 0;
        for (size_t j = 0; j < bcinfo->bc_rt_vars[i].size(); j++) {
            size_t var_len = type_len(bcinfo->bc_rt_vars[i][j]);
            convert_var_to_buffer(bcinfo->bc_rt_vars[i][j], offset, (uint8_t*)bcinfo->bc_sabuf_.data_wds,
                I(p_dynamic_Input_).ptr_[pos], var_len);
            offset += var_len;
            pos++;
        }

        // 不能超过缓存大小
        int msg_num = bcinfo->bc_rt_nums[i];
        if (offset <= bcinfo->data_size_) {
            if (SUCCESS == CORE_BC_Write_Buffer(bcinfo->dev_num_, bcinfo->channel_num_, msg_num, 0, &bcinfo->bc_sabuf_)) {
            }
        }
    }

    // RT->BC
    pos = 0;
    for (size_t i = 0; i < bcinfo->rt_bc_nums.size(); i++) {
        int msg_num = bcinfo->rt_bc_nums[i];
        if (SUCCESS == CORE_BC_Read_Buffer(bcinfo->dev_num_, bcinfo->channel_num_, msg_num, 0, &bcinfo->bc_sabuf_)) {
            size_t offset = 0;
            for (size_t j = 0; j < bcinfo->rt_bc_vars[i].size(); j++) {
                size_t var_len = type_len(bcinfo->rt_bc_vars[i][j]);
                *O(p_dynamic_Output_).ptr_[pos] = convert_buffer_to_var(bcinfo->rt_bc_vars[i][j], offset, (uint8_t*)bcinfo->bc_sabuf_.data_wds);
                offset += var_len;
                pos++;
            }
        }
    }

    // memset(&bcinfo->bc_sabuf_, 0, sizeof(bcinfo->bc_sabuf_)); // 清空上次数据
}

/**********************************
在此函数中编写自定义积分函数
***********************************/
int32_t Block_Port_1553B_BC::integral(int32_t msg, double t, double* state, double* derivative)
{
    return 0;
}

/**********************************
        在此函数中释放内部变量资源
        内部变量:bcinfo_
***********************************/
void Block_Port_1553B_BC::destroyInternalVariable()
{
    // 是否调用了初始化函数,默认为false(控制引擎会出现直接调用destroy的情况,而成员变量si_未初始化被使用会导致崩溃)
    if (!binit_) {
        return;
    }
    CAV1553B_BC_INFO* bcinfo = static_cast<CAV1553B_BC_INFO*>(bcinfo_);

    auto iter = bcinfo->init_info_1553b_->find({ bcinfo->dev_num_, bcinfo->channel_num_ });
    if (iter == bcinfo->init_info_1553b_->end() || !iter->second) {
        CORE_BC_Stop(bcinfo->dev_num_, bcinfo->channel_num_);
    }

    delete bcinfo;
}

3. 测试

测试场景包含BC->RT, RT->BC, RT->RT,下面是我们产品一个BC对应的设置界面。

在这里插入图片描述

这里给BC添加了3条消息,分别是bc->rt, rt->bc, rt->rt。它们是一个数组,一一对应,只有msgType字段少一个是因为rt->rt这1条消息有2个rt,还有需要注意rtType字段的收/发是针对rt来的。

最后,时间匆忙,文章整理得比较粗糙,不过上面的两个示例程序是现场正式环境验证通过了的,封装它们是踩了无数的坑过来的。关于1553B有任何疑问欢迎留言交流~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1249331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LangChain(0.0.339)官方文档二:LCEL

文章目录 一、LangChain Expression Language (LCEL)1.1 LCEL简介1.2 Runnable1.2.1 Runnable方法1.2.2 Runnable组合方式1.2.3 修改行为 1.3 输入输出模式1.3.1 前置知识&#xff1a;Pydantic1.3.2 Input Schema1.3.3 Output Schema 1.4 同步调用1.4.1 Invoke1.4.2 Stream1.4.…

超分辨率重建

意义 客观世界的场景含有丰富多彩的信息&#xff0c;但是由于受到硬件设备的成像条件和成像方式的限制&#xff0c;难以获得原始场景中的所有信息。而且&#xff0c;硬件设备分辨率的限制会不可避免地使图像丢失某些高频细节信息。在当今信息迅猛发展的时代&#xff0c;在卫星…

io.lettuce.core.RedisCommandExecutionException

io.lettuce.core.RedisCommandExecutionException: ERR invalid password ERR invalid password-CSDN博客 io.lettuce.core.RedisCommandExecutionException /** Copyright 2011-2022 the original author or authors.** Licensed under the Apache License, Version 2.0 (the…

医学图像分割:U_Net 论文阅读

“U-Net: Convolutional Networks for Biomedical Image Segmentation” 是一篇由Olaf Ronneberger, Philipp Fischer, 和 Thomas Brox发表的论文&#xff0c;于2015年在MICCAI的医学图像计算和计算机辅助干预会议上提出。这篇论文介绍了一种新型的卷积神经网络架构——U-Net&a…

二叉树--详解

目录 树的概念 关于树的概念 二叉树 概念 两种特殊的二叉树 满二叉树 完全二叉树 二叉树的性质 巩固性质的习题 简单的创建二叉树 二叉树的遍历 递归实现二叉树的前中后后序遍历 二叉树的基本操作 获取树中节点个数 获取叶子结点个数 子问题思路-获取叶子结点个…

CTFSHOW sqll注入

号过滤绕过 号和不加通配符的 like 是一样的。 还可以使用 < >号来绕过&#xff0c;<> 在mysql中等于! 如果在加一个! 双重否定代表肯定 就是了 空格过滤绕过 /**/ &#xff0c;()&#xff0c;&#xff0c;tab&#xff0c;两个空格 or and xor not 过滤绕过 a…

Jenkins 整合 Docker 自动化部署

Docker 安装 Jenkins 配置自动化部署 1. Docker 安装 Jenkins 1.1 拉取镜像文件 docker pull jenkins/jenkins1.2 创建挂载文件目录 mkdir -p $HOME/jenkins_home1.3 启动容器 docker run -d -p 8080:8080 -v $HOME/jenkins_home:/var/jenkins_home --name jenkins jenkin…

Redis高并发缓存架构

前言&#xff1a; 针对缓存我们并不陌生&#xff0c;而今天所讲的是使用redis作为缓存工具进行缓存数据。redis缓存是将数据保存在内存中的&#xff0c;而内存的珍贵性是不可否认的。所以在缓存之前&#xff0c;我们需要明确缓存的对象&#xff0c;是否有必要缓存&#xff0c;怎…

播放器开发(四):多线程解复用与解码模块实现

学习课题&#xff1a;逐步构建开发播放器【QT5 FFmpeg6 SDL2】 前言 根据第一章内容&#xff0c;我们首先可以先把解复用和解码模块完成&#xff0c;其中需要使用到多线程以及队列&#xff0c;还需要使用FFmpeg进行解复用和解码动作的实现。 创建BaseQueue基类 BaseQueue.h…

技术分享 | 在 IDE 插件开发中接入 JCEF 框架

项目背景 当前的开发环境存在多种不同语言的 IDE&#xff0c;如 JetBrains 全家桶、Eclipse、Android Studio 和 VS Code 等等。由于每个 IDE 各有其特定的语言和平台要求&#xff0c;因此开发 IDE 插件时&#xff0c;需要投入大量资源才能尽可能覆盖大部分工具。同时&#xf…

java中的String.format()方法详解

介绍 String.format() 是 Java 中的一个字符串格式化方法&#xff0c;它用于生成指定格式的字符串。这个方法可以接受一个或多个参数&#xff0c;并将它们按照指定的格式插入到字符串中。它使用了类似于 C 语言中的 printf 函数的语法。 String.format() 方法的使用格式如下&…

Linux技能篇-非交互式修改密码

今天的文章没有格式&#xff0c;简单分享一个小技能&#xff0c;就是标题所说–非交互式修改密码。 一、普通方式修改用户密码 最普通的修改密码的命令就是passwd命令 [rootlocalhost ~]# passwd root Changing password for user root. New password: Retype new password:…

【经典小练习】修改文件中的数据

文章目录 &#x1f339;例子&#x1f33a;思路&#x1f6f8;方法一✨报错解决 &#x1f6f8;方法二 &#x1f339;例子 文本文件中有下面的数据 2-1-9-4-7-8 将文件中的数据进行排序&#xff0c;变成下面的数据 1-2-4-7-8-9 &#x1f33a;思路 要对这些数据进行排序&#xf…

发送一个网络数据包的过程解析

在 ip_queue_xmit 中&#xff0c;也即 IP 层的发送函数里面&#xff0c;有三部分逻辑。第一部分&#xff0c;选取路由&#xff0c;也即我要发送这个包应该从哪个网卡出去。 这件事情主要由 ip_route_output_ports 函数完成。接下来的调用链为&#xff1a;ip_route_output_port…

Python报错:AttributeError(类属性、实例属性)

Python报错&#xff1a;AttributeError&#xff08;类属性、实例属性&#xff09; Python报错&#xff1a;AttributeError 这个错误就是说python找不到对应的对象的属性&#xff0c;百度后才发现竟然是初始化类的时候函数名写错了 __init__应该有2条下划线&#xff0c;如果只有…

【JavaEE初阶】Thread 类及常见方法、线程的状态

目录 1、Thread 类及常见方法 1.1 Thread 的常见构造方法 1.2 Thread 的几个常见属性 1.3 启动⼀个线程 - start() 1.4 中断⼀个线程 1.5 等待⼀个线程 - join() 1.6 获取当前线程引用 1.7 休眠当前线程 2、线程的状态 2.1 观察线程的所有状态 2.2 线程状态和状…

黑马点评笔记 分布式锁

文章目录 分布式锁基本原理和实现方式对比Redis分布式锁的实现核心思路实现分布式锁版本一Redis分布式锁误删情况说明解决Redis分布式锁误删问题分布式锁的原子性问题分布式锁-Redission分布式锁-redission可重入锁原理分布式锁-redission锁重试和WatchDog机制分布式锁-redissi…

RocketMQ 消息中间件 知识点汇总

目录 RocketMQ1、什么是RocketMQ?常用术语:2、为什么需要消息队列3、什么是异步处理4、什么是服务解耦5、什么是流量控制6、消息队列两种模型队列模型:发布/订阅模型:总结:7、怎么保证消息不丢失8、如何处理消息被重复消费**出现消息重复的情况:****解决方法:**9、如何保…

RocketMQ消息的一生

这篇文章我准备来聊一聊RocketMQ消息的一生。 不知你是否跟我一样&#xff0c;在使用RocketMQ的时候也有很多的疑惑&#xff1a; 消息是如何发送的&#xff0c;队列是如何选择的&#xff1f; 消息是如何存储的&#xff0c;是如何保证读写的高性能&#xff1f; RocketMQ是如何…

Dreamview底层实现原理

1. Dreamview底层实现原理(3个模块) (1) HMI--可视化人机交互 a. HMIConfig: 1) 支持哪些模式&#xff1b;2)支持哪些地图&#xff1b;3)支持哪些车辆&#xff1b;4)HMIAction HMIMode: b.HMIStatus (2) SimControl (3) Monitor--监视自动驾驶行驶过程中软硬件状态 Referenc…