Advertisement
Guest User

Untitled

a guest
Apr 12th, 2018
40
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.57 KB | None | 0 0
  1. #include <algorithm>
  2. #include <iomanip>
  3. #include <iostream>
  4. #include <stdexcept>
  5. #include <string>
  6. #include <string_view>
  7. #include <utility>
  8.  
  9. #include <boost/format.hpp>
  10.  
  11. #include "adsData.h"
  12. #ifdef _MSC_VER
  13. #    include <wtypes.h>
  14. using bytes_read_type = unsigned long;
  15. #else
  16. using bytes_read_type = std::uint32_t;
  17. #endif
  18. #include <TcAdsDef.h>
  19.  
  20. #include <TcAdsAPI.h>
  21.  
  22. using namespace std::literals::string_view_literals;
  23.  
  24. class AmsAccess
  25. {
  26. private:
  27.     AmsAccess() : adsPort(AdsPortOpenEx()), addr()
  28.     {
  29.         if (adsPort == 0)
  30.             throw std::runtime_error("cannot open ads port");
  31.     }
  32.     AmsAccess(const AmsAccess&) = delete;
  33.     AmsAccess(AmsAccess&&)      = delete;
  34.     AmsAccess& operator=(const AmsAccess&) = delete;
  35.     AmsAccess& operator=(AmsAccess&&) = delete;
  36.  
  37. public:
  38.     AmsAccess(decltype(AmsAddr::port) port) : AmsAccess()
  39.     {
  40.         if (auto err = AdsGetLocalAddressEx(adsPort, &addr); err != ADSERR_NOERR)
  41.             throw std::runtime_error((boost::format("cannot get local ams address: %#4x") % err).str());
  42.         addr.port = port;
  43.     }
  44.     ~AmsAccess() { AdsPortCloseEx(adsPort); }
  45.  
  46.     AdsData getPlcData()
  47.     {
  48.         bytes_read_type bytes_read = 0;
  49.  
  50.         AdsSymbolUploadInfo2 info{};
  51.         if (auto err = AdsSyncReadReqEx2(adsPort, &addr, ADSIGRP_SYM_UPLOADINFO2, 0, sizeof(info), &info, &bytes_read);
  52.             err != ADSERR_NOERR)
  53.             throw std::runtime_error((boost::format("cannot read symbol upload info: %#4x") % err).str());
  54.         if (bytes_read != sizeof(info))
  55.             throw std::runtime_error(
  56.                 (boost::format("error reading sym_uploadinfo2: %1% bytes read") % bytes_read).str());
  57.  
  58.         std::vector<char> symData(info.nSymSize);
  59.         std::vector<char> dtData(info.nDatatypeSize);
  60.  
  61.         if (auto err =
  62.                 AdsSyncReadReqEx2(adsPort, &addr, ADSIGRP_SYM_UPLOAD, 0, info.nSymSize, &symData[0], &bytes_read);
  63.             err != ADSERR_NOERR)
  64.             throw std::runtime_error((boost::format("cannot read symbol info: %#4x") % err).str());
  65.         if (bytes_read != info.nSymSize)
  66.             throw std::runtime_error(
  67.                 (boost::format("error reading symbols: %1% bytes read, %2% expected") % bytes_read % info.nSymSize)
  68.                     .str());
  69.  
  70.         if (auto err = AdsSyncReadReqEx2(adsPort, &addr, ADSIGRP_SYM_DT_UPLOAD, 0, info.nDatatypeSize, &dtData[0],
  71.                                          &bytes_read);
  72.             err != ADSERR_NOERR)
  73.             throw std::runtime_error((boost::format("cannot read datatype info: %#4x") % err).str());
  74.         if (bytes_read != info.nDatatypeSize)
  75.             throw std::runtime_error((boost::format("error reading datatypes: %1% bytes read, %2% expected")
  76.                                       % bytes_read % info.nDatatypeSize)
  77.                                          .str());
  78.  
  79.         return AdsData(symData, dtData);
  80.     }
  81.  
  82.     template <typename T>
  83.     T read(std::uint32_t group, std::uint32_t offset)
  84.     {
  85.         bytes_read_type bytes_read = 0;
  86.         T               result     = {};
  87.  
  88.         if (auto err = AdsSyncReadReqEx2(adsPort, &addr, group, offset, sizeof(T), &result, &bytes_read);
  89.             err != ADSERR_NOERR)
  90.             throw std::runtime_error(
  91.                 (boost::format("cannot read: %1#4x with group %2% and offset %3%") % err % group % offset).str());
  92.         if (bytes_read != sizeof(T))
  93.             throw std::runtime_error(
  94.                 (boost::format("error reading: %1% bytes read, %2% expected") % bytes_read % sizeof(T)).str());
  95.  
  96.         return result;
  97.     }
  98.  
  99.     AdsSymbolEntry* getSymInfoByName(std::vector<char*>& buffer, std::string& name)
  100.     {
  101.         bytes_read_type bytes_read = 0;
  102.         auto            err        = AdsSyncReadWriteReqEx2(adsPort, &addr, ADSIGRP_SYM_INFOBYNAMEEX, 0,
  103.                                           static_cast<std::uint32_t>(buffer.size()), &buffer[0],
  104.                                           static_cast<std::uint32_t>(name.size() + 1), name.data(), &bytes_read);
  105.         if (err == ADSERR_NOERR)
  106.             return reinterpret_cast<AdsSymbolEntry*>(&buffer[0]);
  107.  
  108.         std::cout << boost::format("%1$-72s FAILED\n\tSYM_INFOBYNAMEEX %2$#4x\n") % name % err;
  109.         return nullptr;
  110.     }
  111.     AdsSymbolEntry* getSymInfoByName(std::vector<char*>& buffer, std::string&& name)
  112.     {
  113.         return getSymInfoByName(buffer, name);
  114.     }
  115.  
  116.     std::uint32_t getAddrData(const AdsVarData& var)
  117.     {
  118.         if (!var.isPointer() && !var.isReference())
  119.             throw std::runtime_error("not a reference or pointer");
  120.  
  121.         return read<std::uint32_t>(var.group(), var.offset());
  122.     }
  123.  
  124. private:
  125.     std::int32_t adsPort;
  126.     AmsAddr      addr;
  127. };
  128.  
  129. std::ostream& operator<<(std::ostream& s, DatatypeId val)
  130. {
  131.     static constexpr std::pair<DatatypeId, std::string_view> typenames[] = {
  132.         {DatatypeId::void_, "void"sv},       {DatatypeId::int16_, "int16"sv},         {DatatypeId::int32_, "int32"sv},
  133.         {DatatypeId::float_, "float"sv},     {DatatypeId::double_, "double"sv},       {DatatypeId::int8_, "int8"sv},
  134.         {DatatypeId::uint8_, "uint8"sv},     {DatatypeId::uint16_, "uint16"sv},       {DatatypeId::uint32_, "uint32"sv},
  135.         {DatatypeId::int64_, "int64"sv},     {DatatypeId::uint64_, "uint64"sv},       {DatatypeId::string_, "string"sv},
  136.         {DatatypeId::wstring_, "wstring"sv}, {DatatypeId::ldouble_, "long double"sv}, {DatatypeId::bool_, "bool"sv},
  137.         {DatatypeId::blob_, "blob"sv},       {DatatypeId::maxtypes_, "max_types"sv}};
  138.     auto it =
  139.         std::lower_bound(std::begin(typenames), std::end(typenames), val, [](auto& x, auto& y) { return x.first < y; });
  140.     if (it == std::end(typenames) || it->first != val)
  141.         s << "unknown(" << static_cast<int>(val) << ')';
  142.     else
  143.         s << it->second << '(' << static_cast<int>(val) << ')';
  144.     return s;
  145. }
  146.  
  147. static bool ignoreTypeId = false;
  148. void        verify(AmsAccess& ams, const AdsVarData& var, std::string prefix = "", bool deref_once = false)
  149. {
  150.     auto name = var.name(prefix);
  151.  
  152.     if (deref_once)
  153.     {
  154.         std::cout << boost::format("%-73s DEREF\n") % name << "\toffset: " << var.offset() << '\n'
  155.                   << "\tsize: " << var.size() << '\n';
  156.         return;
  157.     }
  158.  
  159.     std::vector<char*> buffer(1 << 16);
  160.     auto               symData = ams.getSymInfoByName(buffer, name);
  161.  
  162.     if (!symData)
  163.     {
  164.         std::cout << "parsed as:\n"
  165.                   << "\ttype: " << var.type() << '\n'
  166.                   << "\ttypeId: " << var.typeId() << '\n'
  167.                   << "\tgroup: " << var.group() << '\n'
  168.                   << "\toffset: " << var.offset() << '\n'
  169.                   << "\tsize: " << var.size() << '\n';
  170.         return;
  171.     }
  172.  
  173.     if (var.isReference())
  174.     {
  175.         std::cout << boost::format("%-71s SKIPPED\n") % name;
  176.         return;
  177.     }
  178.  
  179.     if (var.type() != PADSSYMBOLTYPE(symData) || (var.typeId() != symData->dataType && !ignoreTypeId)
  180.         || var.group() != symData->iGroup || var.offset() != symData->iOffs || var.size() != symData->size)
  181.     {
  182.         std::cout << boost::format("%-72s FAILED\nSYM_INFOBYNAMEEX says:\n") % name
  183.                   << "\ttype: " << PADSSYMBOLTYPE(symData) << '\n'
  184.                   << "\ttypeId: " << DatatypeId(symData->dataType) << '\n'
  185.                   << "\tgroup: " << symData->iGroup << '\n'
  186.                   << "\toffset: " << symData->iOffs << '\n'
  187.                   << "\tsize: " << symData->size << "\nbut parsed as:\n"
  188.                   << "\ttype: " << var.type() << '\n'
  189.                   << "\ttypeId: " << var.typeId() << '\n'
  190.                   << "\tgroup: " << var.group() << '\n'
  191.                   << "\toffset: " << var.offset() << '\n'
  192.                   << "\tsize: " << var.size() << '\n';
  193.     }
  194.     else
  195.         std::cout << boost::format("%-76s OK\n") % name;
  196. }
  197.  
  198. void verifySubs(AdsData& plcData, AmsAccess& ams, const AdsVarData& var, std::string prefix, bool deref_once = false)
  199. {
  200.     for (auto sub : var)
  201.     {
  202.         if (!deref_once)
  203.             plcData[sub.name(prefix)];
  204.         verify(ams, sub, prefix, deref_once);
  205.         verifySubs(plcData, ams, sub, sub.name(prefix), deref_once);
  206.         if (!deref_once && (sub.isPointer() || sub.isReference()))
  207.         {
  208.             auto refVar = sub.deref(ams.getAddrData(sub));
  209.             verify(ams, refVar, sub.name(prefix), true);
  210.             verifySubs(plcData, ams, refVar, refVar.name(sub.name(prefix)), true);
  211.         }
  212.     }
  213. }
  214.  
  215. int main(int argc, char** argv)
  216. {
  217.     if (argc < 2)
  218.     {
  219.         std::cout << "usage: " << argv[0] << " <port> [options]\noptions:\n -i ignore typeId";
  220.         return 1;
  221.     }
  222.     auto port = static_cast<decltype(AmsAddr::port)>(std::stoul(argv[1]));
  223.  
  224.     ignoreTypeId = (argc >= 3 && argv[2] == "-i"sv);
  225.  
  226.     try
  227.     {
  228.         AmsAccess ams(port);
  229.         AdsData   plcData = ams.getPlcData();
  230.  
  231.         for (auto var : plcData)
  232.         {
  233.             if (var.shortName() == "MAIN.arrrr"sv)
  234.             {
  235.                 std::cout << '\n';
  236.             }
  237.             plcData[var.shortName()];
  238.             verify(ams, var);
  239.             verifySubs(plcData, ams, var, var.shortName());
  240.             if (var.isPointer() || var.isReference())
  241.             {
  242.                 auto refVar = var.deref(ams.getAddrData(var));
  243.                 verify(ams, refVar, var.shortName(), true);
  244.                 verifySubs(plcData, ams, refVar, refVar.name(var.shortName()), true);
  245.             }
  246.         }
  247.     }
  248.     catch (std::exception& e)
  249.     {
  250.         std::cout << e.what() << '\n';
  251.         return 1;
  252.     }
  253. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement