Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <iomanip>
- #include <iostream>
- #include <stdexcept>
- #include <string>
- #include <string_view>
- #include <utility>
- #include <boost/format.hpp>
- #include "adsData.h"
- #ifdef _MSC_VER
- # include <wtypes.h>
- using bytes_read_type = unsigned long;
- #else
- using bytes_read_type = std::uint32_t;
- #endif
- #include <TcAdsDef.h>
- #include <TcAdsAPI.h>
- using namespace std::literals::string_view_literals;
- class AmsAccess
- {
- private:
- AmsAccess() : adsPort(AdsPortOpenEx()), addr()
- {
- if (adsPort == 0)
- throw std::runtime_error("cannot open ads port");
- }
- AmsAccess(const AmsAccess&) = delete;
- AmsAccess(AmsAccess&&) = delete;
- AmsAccess& operator=(const AmsAccess&) = delete;
- AmsAccess& operator=(AmsAccess&&) = delete;
- public:
- AmsAccess(decltype(AmsAddr::port) port) : AmsAccess()
- {
- if (auto err = AdsGetLocalAddressEx(adsPort, &addr); err != ADSERR_NOERR)
- throw std::runtime_error((boost::format("cannot get local ams address: %#4x") % err).str());
- addr.port = port;
- }
- ~AmsAccess() { AdsPortCloseEx(adsPort); }
- AdsData getPlcData()
- {
- bytes_read_type bytes_read = 0;
- AdsSymbolUploadInfo2 info{};
- if (auto err = AdsSyncReadReqEx2(adsPort, &addr, ADSIGRP_SYM_UPLOADINFO2, 0, sizeof(info), &info, &bytes_read);
- err != ADSERR_NOERR)
- throw std::runtime_error((boost::format("cannot read symbol upload info: %#4x") % err).str());
- if (bytes_read != sizeof(info))
- throw std::runtime_error(
- (boost::format("error reading sym_uploadinfo2: %1% bytes read") % bytes_read).str());
- std::vector<char> symData(info.nSymSize);
- std::vector<char> dtData(info.nDatatypeSize);
- if (auto err =
- AdsSyncReadReqEx2(adsPort, &addr, ADSIGRP_SYM_UPLOAD, 0, info.nSymSize, &symData[0], &bytes_read);
- err != ADSERR_NOERR)
- throw std::runtime_error((boost::format("cannot read symbol info: %#4x") % err).str());
- if (bytes_read != info.nSymSize)
- throw std::runtime_error(
- (boost::format("error reading symbols: %1% bytes read, %2% expected") % bytes_read % info.nSymSize)
- .str());
- if (auto err = AdsSyncReadReqEx2(adsPort, &addr, ADSIGRP_SYM_DT_UPLOAD, 0, info.nDatatypeSize, &dtData[0],
- &bytes_read);
- err != ADSERR_NOERR)
- throw std::runtime_error((boost::format("cannot read datatype info: %#4x") % err).str());
- if (bytes_read != info.nDatatypeSize)
- throw std::runtime_error((boost::format("error reading datatypes: %1% bytes read, %2% expected")
- % bytes_read % info.nDatatypeSize)
- .str());
- return AdsData(symData, dtData);
- }
- template <typename T>
- T read(std::uint32_t group, std::uint32_t offset)
- {
- bytes_read_type bytes_read = 0;
- T result = {};
- if (auto err = AdsSyncReadReqEx2(adsPort, &addr, group, offset, sizeof(T), &result, &bytes_read);
- err != ADSERR_NOERR)
- throw std::runtime_error(
- (boost::format("cannot read: %1#4x with group %2% and offset %3%") % err % group % offset).str());
- if (bytes_read != sizeof(T))
- throw std::runtime_error(
- (boost::format("error reading: %1% bytes read, %2% expected") % bytes_read % sizeof(T)).str());
- return result;
- }
- AdsSymbolEntry* getSymInfoByName(std::vector<char*>& buffer, std::string& name)
- {
- bytes_read_type bytes_read = 0;
- auto err = AdsSyncReadWriteReqEx2(adsPort, &addr, ADSIGRP_SYM_INFOBYNAMEEX, 0,
- static_cast<std::uint32_t>(buffer.size()), &buffer[0],
- static_cast<std::uint32_t>(name.size() + 1), name.data(), &bytes_read);
- if (err == ADSERR_NOERR)
- return reinterpret_cast<AdsSymbolEntry*>(&buffer[0]);
- std::cout << boost::format("%1$-72s FAILED\n\tSYM_INFOBYNAMEEX %2$#4x\n") % name % err;
- return nullptr;
- }
- AdsSymbolEntry* getSymInfoByName(std::vector<char*>& buffer, std::string&& name)
- {
- return getSymInfoByName(buffer, name);
- }
- std::uint32_t getAddrData(const AdsVarData& var)
- {
- if (!var.isPointer() && !var.isReference())
- throw std::runtime_error("not a reference or pointer");
- return read<std::uint32_t>(var.group(), var.offset());
- }
- private:
- std::int32_t adsPort;
- AmsAddr addr;
- };
- std::ostream& operator<<(std::ostream& s, DatatypeId val)
- {
- static constexpr std::pair<DatatypeId, std::string_view> typenames[] = {
- {DatatypeId::void_, "void"sv}, {DatatypeId::int16_, "int16"sv}, {DatatypeId::int32_, "int32"sv},
- {DatatypeId::float_, "float"sv}, {DatatypeId::double_, "double"sv}, {DatatypeId::int8_, "int8"sv},
- {DatatypeId::uint8_, "uint8"sv}, {DatatypeId::uint16_, "uint16"sv}, {DatatypeId::uint32_, "uint32"sv},
- {DatatypeId::int64_, "int64"sv}, {DatatypeId::uint64_, "uint64"sv}, {DatatypeId::string_, "string"sv},
- {DatatypeId::wstring_, "wstring"sv}, {DatatypeId::ldouble_, "long double"sv}, {DatatypeId::bool_, "bool"sv},
- {DatatypeId::blob_, "blob"sv}, {DatatypeId::maxtypes_, "max_types"sv}};
- auto it =
- std::lower_bound(std::begin(typenames), std::end(typenames), val, [](auto& x, auto& y) { return x.first < y; });
- if (it == std::end(typenames) || it->first != val)
- s << "unknown(" << static_cast<int>(val) << ')';
- else
- s << it->second << '(' << static_cast<int>(val) << ')';
- return s;
- }
- static bool ignoreTypeId = false;
- void verify(AmsAccess& ams, const AdsVarData& var, std::string prefix = "", bool deref_once = false)
- {
- auto name = var.name(prefix);
- if (deref_once)
- {
- std::cout << boost::format("%-73s DEREF\n") % name << "\toffset: " << var.offset() << '\n'
- << "\tsize: " << var.size() << '\n';
- return;
- }
- std::vector<char*> buffer(1 << 16);
- auto symData = ams.getSymInfoByName(buffer, name);
- if (!symData)
- {
- std::cout << "parsed as:\n"
- << "\ttype: " << var.type() << '\n'
- << "\ttypeId: " << var.typeId() << '\n'
- << "\tgroup: " << var.group() << '\n'
- << "\toffset: " << var.offset() << '\n'
- << "\tsize: " << var.size() << '\n';
- return;
- }
- if (var.isReference())
- {
- std::cout << boost::format("%-71s SKIPPED\n") % name;
- return;
- }
- if (var.type() != PADSSYMBOLTYPE(symData) || (var.typeId() != symData->dataType && !ignoreTypeId)
- || var.group() != symData->iGroup || var.offset() != symData->iOffs || var.size() != symData->size)
- {
- std::cout << boost::format("%-72s FAILED\nSYM_INFOBYNAMEEX says:\n") % name
- << "\ttype: " << PADSSYMBOLTYPE(symData) << '\n'
- << "\ttypeId: " << DatatypeId(symData->dataType) << '\n'
- << "\tgroup: " << symData->iGroup << '\n'
- << "\toffset: " << symData->iOffs << '\n'
- << "\tsize: " << symData->size << "\nbut parsed as:\n"
- << "\ttype: " << var.type() << '\n'
- << "\ttypeId: " << var.typeId() << '\n'
- << "\tgroup: " << var.group() << '\n'
- << "\toffset: " << var.offset() << '\n'
- << "\tsize: " << var.size() << '\n';
- }
- else
- std::cout << boost::format("%-76s OK\n") % name;
- }
- void verifySubs(AdsData& plcData, AmsAccess& ams, const AdsVarData& var, std::string prefix, bool deref_once = false)
- {
- for (auto sub : var)
- {
- if (!deref_once)
- plcData[sub.name(prefix)];
- verify(ams, sub, prefix, deref_once);
- verifySubs(plcData, ams, sub, sub.name(prefix), deref_once);
- if (!deref_once && (sub.isPointer() || sub.isReference()))
- {
- auto refVar = sub.deref(ams.getAddrData(sub));
- verify(ams, refVar, sub.name(prefix), true);
- verifySubs(plcData, ams, refVar, refVar.name(sub.name(prefix)), true);
- }
- }
- }
- int main(int argc, char** argv)
- {
- if (argc < 2)
- {
- std::cout << "usage: " << argv[0] << " <port> [options]\noptions:\n -i ignore typeId";
- return 1;
- }
- auto port = static_cast<decltype(AmsAddr::port)>(std::stoul(argv[1]));
- ignoreTypeId = (argc >= 3 && argv[2] == "-i"sv);
- try
- {
- AmsAccess ams(port);
- AdsData plcData = ams.getPlcData();
- for (auto var : plcData)
- {
- if (var.shortName() == "MAIN.arrrr"sv)
- {
- std::cout << '\n';
- }
- plcData[var.shortName()];
- verify(ams, var);
- verifySubs(plcData, ams, var, var.shortName());
- if (var.isPointer() || var.isReference())
- {
- auto refVar = var.deref(ams.getAddrData(var));
- verify(ams, refVar, var.shortName(), true);
- verifySubs(plcData, ams, refVar, refVar.name(var.shortName()), true);
- }
- }
- }
- catch (std::exception& e)
- {
- std::cout << e.what() << '\n';
- return 1;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement