Advertisement
Guest User

Untitled

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