Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADS-sum command: Read or Write a list of variables with one single ADS-command #205

Open
li317546360 opened this issue Jun 16, 2023 · 1 comment

Comments

@li317546360
Copy link

ADS-sum command wrapper example, intended as a reference to assist those in need. It has been successfully tested on macOS.

#pragma once

#include "AdsDevice.h"
#include "vector"

#include <array>


struct AdsVariableList {
    AdsVariableList(const AdsDevice& route, std::vector<std::string> symbolNames)
        :m_route{route},
        m_symboleNames {symbolNames},
        m_symboleEntrys {route.getSymbolEntrys(m_symboleNames)}
    {
        int dataSize = 0;
        for (const AdsSymbolEntry &en : m_symboleEntrys) {
            dataSize += en.size;
            AdsSymbolInfoByName info {en.iGroup,en.iOffs,en.size};
            m_symboleInfos.push_back(info);
        }
        m_rBuf.resize(4 * m_symboleNames.size() + dataSize,0);
        m_wBuf.resize(12 * symbolNames.size() + dataSize,0);
        initWBuf();
    }

    void read() {
        uint32_t bytesRead = 0;
        size_t symboleSize = m_symboleNames.size();
        uint32_t error = m_route.ReadWriteReqEx2(
            ADSIGRP_SUMUP_READ,
            symboleSize,
            m_rBuf.size(),
            const_cast<uint8_t*>(m_rBuf.data()),
            12 * symboleSize,
            m_symboleInfos.data(),
            &bytesRead);
        if (error || (m_rBuf.size() != bytesRead)) {
            throw AdsException(error);
        }
    }

    void write() {
        uint32_t bytesRead = 0;
        size_t symboleSize = m_symboleNames.size();
        copyData2WriteBuf();

        size_t readSize = 0;
        auto rbf = getStateBuf(&readSize);

        uint32_t error = m_route.ReadWriteReqEx2(
            ADSIGRP_SUMUP_WRITE,
            symboleSize,
            readSize,
            rbf,
            m_wBuf.size(),
            m_wBuf.data(),
            &bytesRead);
        if (error || (readSize != bytesRead)) {
            throw AdsException(error);
        }
    }

    size_t getSymboleSize(const std::string& name) const {
        int index = 0;
        for (const std::string &n : m_symboleNames) {
            if (name == n) {
                return m_symboleEntrys.at(index).size;
            }
            ++index;
        }
    }

    void * getSymboleData(const std::string& name, size_t* length) {

        auto pdbf = getDataBuf(nullptr);

        for (int i=0; i<m_symboleEntrys.size();++i) {
            if (name == m_symboleNames.at(i)) {
                if (length) {
                    *length = m_symboleEntrys.at(i).size;
                }
                return pdbf;
            }
            pdbf += m_symboleEntrys.at(i).size;
        }
    }

    void setSymbolData(const std::string& name, void *data, size_t length, size_t begin = 0) {
        size_t size = 0;
        auto buf = static_cast<uint8_t*>(getSymboleData(name,&size));
        if ((begin + length) > size)
            return;
        std::memcpy((buf + begin),data,length);
    }

    int32_t getStateCode(const std::string& name) const {

        auto psbf = getStateBuf(nullptr);
        for(int i=0;i<m_symboleNames.size();++i) {
            if (name == m_symboleNames.at(i)) {
                return *reinterpret_cast<int32_t*>(psbf + 4 * i);
            }
        }
    }

private:
    uint8_t * getStateBuf(size_t* size) const{
        size_t len = 4 * m_symboleNames.size();

        if (size) {
            *size = len;
        }
        return const_cast<uint8_t*>(m_rBuf.data());
    }

    uint8_t * getDataBuf(size_t* size) const{
        size_t stlen = 4 * m_symboleNames.size();
        size_t len = m_rBuf.size() - stlen;

        if (size) {
            *size = len;
        }
        return const_cast<uint8_t*>(m_rBuf.data()) + stlen;
    }

    uint8_t * getWriteDataBuf(size_t* size) const{
        size_t inflen = 12 * m_symboleNames.size();
        size_t len = m_rBuf.size() - inflen;

        if (size) {
            *size = len;
        }
        return const_cast<uint8_t*>(m_wBuf.data()) + inflen;
    }

    void copyData2WriteBuf() {
        size_t rdataSize = 0;
        auto rbf = getDataBuf(&rdataSize);
        auto wbf = getWriteDataBuf(nullptr);
        std::memcpy(wbf,rbf,rdataSize);
    }

    void initWBuf() {
        auto pInt32buf = reinterpret_cast<int32_t*>(const_cast<uint8_t*>(m_wBuf.data()));
        auto symboleSize = m_symboleNames.size();
        for (int i = 0; i < symboleSize; ++i) {
            *pInt32buf = m_symboleEntrys.at(i).iGroup;
            ++pInt32buf;
            *pInt32buf = m_symboleEntrys.at(i).iOffs;
            ++pInt32buf;
            *pInt32buf = m_symboleEntrys.at(i).size;
            ++pInt32buf;
        }
    }

    const AdsDevice &m_route;
    const std::vector<std::string> m_symboleNames;
    const std::vector<AdsSymbolEntry> m_symboleEntrys;
    std::vector<AdsSymbolInfoByName> m_symboleInfos;
    std::vector<uint8_t> m_rBuf;
    std::vector<uint8_t> m_wBuf;
};

Use

static void readWriteMulteExample(std::ostream& out,const AdsDevice& route,const std::vector<std::string> names) {
    AdsVariableList vbl{route,names};
    vbl.read();
    size_t size = 0;

    auto data = static_cast<uint8_t*>(vbl.getSymboleData(names[0], &size));
    auto data2 = static_cast<int16_t*>(vbl.getSymboleData(names[1],nullptr));
    auto data3 = static_cast<int16_t*>(vbl.getSymboleData(names[2],nullptr));
    auto data4 = static_cast<int16_t*>(vbl.getSymboleData(names[3],nullptr));
    for (size_t i=0;i<size;++i,++data) {
        out << static_cast<int>(*data) << ";";
    }
    out << "\n" << names[1] << "=" << *data2 << std::endl;
    out << names[2] << "=" << *data3 << std::endl;
    out << names[3] << "=" << *data4 << std::endl;
    std::array<uint8_t,10> arr {1,2,3,4,5,6,7,8,9,10};
    // std::reverse(arr.begin(),arr.end());
    vbl.setSymbolData(names[0],arr.data(),arr.size(),10);
    int16_t temp = 1122;
    vbl.setSymbolData(names[1],&temp,sizeof(int16_t));
    temp = 2211;
    vbl.setSymbolData(names[2],&temp,sizeof(int16_t));
    temp = 3344;
    vbl.setSymbolData(names[3],&temp,sizeof(int16_t));
    vbl.write();
    vbl.read();
    data = static_cast<uint8_t*>(vbl.getSymboleData(names[0], &size));
    data2 = static_cast<int16_t*>(vbl.getSymboleData(names[1],nullptr));
    data3 = static_cast<int16_t*>(vbl.getSymboleData(names[2],nullptr));
    data4 = static_cast<int16_t*>(vbl.getSymboleData(names[3],nullptr));
    for (size_t i=0;i<size;++i,++data) {
        out << static_cast<int>(*data) << ";";
    }
    out << "\n" << names[1] << "=" << *data2 << std::endl;
    out << names[2] << "=" << *data3 << std::endl;
    out << names[3] << "=" << *data4 << std::endl;
}

static void runExample(std::ostream& out)
{
    static const AmsNetId remoteNetId { 192, 168, 3, 15, 1, 1 };
    static const char remoteIpV4[] = "192.168.2.38";

    // uncomment and adjust if automatic AmsNetId deduction is not working as expected
    //bhf::ads::SetLocalAddress({192, 168, 0, 1, 1, 1});

    AdsDevice route {remoteIpV4, remoteNetId, AMSPORT_R0_PLC_TC3};
    // std::vector<std::string> symbols{"MAIN.byByte","MAIN.ai_data","MAIN.ao_data"};
    std::vector<std::string> symbols{"MAIN.byByte","MAIN.ao_data","MAIN.ao_data2","MAIN.ai_Data"};
    readWriteMulteExample(out,route,symbols);
    // notificationExample(out, route);
    // notificationByNameExample(out, route);
    // readExample(out, route);
    // readByNameExample(out, route);
    // readWriteExample(out, route);
    // readWriteArrayExample(out, route);
    // readStateExample(out, route);
@li317546360
Copy link
Author

I forgot about the extension part of AdsDevice, which is used to query variable information

AdsSymbolEntry AdsDevice::getSymbolEntry(const std::string &symbolName) const
{
    AdsSymbolEntry entry;
    uint32_t bytesRead = 0;
    uint32_t error = ReadWriteReqEx2(
        ADSIGRP_SYM_INFOBYNAMEEX,
        0x0,
        sizeof(entry),
        &entry,
        sizeof(symbolName),
        symbolName.c_str(),
        &bytesRead);
    if (error) {
        throw AdsException(error);
    }
    return entry;
}

std::vector<AdsSymbolEntry> AdsDevice::getSymbolEntrys(const std::vector<std::string>& symbolNames) const
{
    std::vector<AdsSymbolEntry> re;
    for (const std::string &name : symbolNames){
        re.push_back(getSymbolEntry(name));
    }
    return re;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant