Beckhoff / ADS

Beckhoff protocol to communicate with TwinCAT devices.
MIT License
491 stars 193 forks source link

Question: How to get decimal values of different twincat3 variables with the help of a notification #181

Closed alexanderwwagner closed 1 year ago

alexanderwwagner commented 1 year ago

Question At the moment I try to get some integer values of my plc project with the ads client library. For this requirement I use the notification functionality. But I have problems to get the decimal value of my integer plc value. After some research I found the solution for the read functionality: AdsVariable readVarInt {route, ".myInt"}; for type INT

Can you help me to find the problem in following syntax?

Environment OS: Archlinux gcc: 12.2.0

To Reproduce Run the method "notificationByNameExample()" of the example and do this changes.

notificationByNameExample()

static void notificationByNameExample(std::ostream& out, const AdsDevice& route)
{
    const AdsNotificationAttrib attrib = {
        1,
        ADSTRANS_SERVERCYCLE,
        0,
        {4000000}
    };

    out << __FUNCTION__ << "():\n";
    AdsNotification notification { route, "MAIN.DintTest", attrib, &NotifyCallback, 0xBEEFDEAD };

    out << "Hit ENTER to stop by name notifications\n";
    std::cin.ignore();
}

NotifyCallback()

static void NotifyCallback(const AmsAddr* pAddr, const AdsNotificationHeader* pNotification, uint32_t hUser)
{
    const int16_t* data = reinterpret_cast<const int16_t*>(pNotification + 1);
    std::cout << std::setfill('0') <<
        "NetId: " << pAddr->netId <<
        " hUser 0x" << std::hex << hUser <<
        " sample time: " << std::dec << pNotification->nTimeStamp <<
        " sample size: " << std::dec << pNotification->cbSampleSize <<
        " value:";
    for (size_t i = 0; i < pNotification->cbSampleSize; ++i) {
        std::cout << std::dec << (int16_t)data[i];
    }
    std::cout << '\n';
}

Output => I get the value "-9833" but the actual value is something about "+8000"

Hit ENTER to stop by name notifications
NetId: 172.22.158.7.1.1 hUser 0xbeefdead sample time: 133147987054890000 sample size: 1 value:-9833
pbruenn commented 1 year ago

Your PLC variable name says you use a DINT. If thats true I guess you should use int32_t instead of uint16_t in the NotifyCallback()

https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/2529399691.html

p.s.: If you run on BigEndian be sure to convert from little endian (ADS network byte order ...)

alexanderwwagner commented 1 year ago

Hmm both systems are little endian + i read out integer so it should be okay. If I look at the official documentation (ADS-DLL C++) of beckhoff the ADSNotificationHeader has one item "data" but this item is missing in this library and I have to set the pointer position myself? Documentation ADS-DLL C++: https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsnetref/7313399947.html&id=

So I do not know where the problem could be...maybe the pointer position is wrong?

pbruenn commented 1 year ago

data is a zero sized array just behind AdsNotificationHeader. You already calculate the pointer position: const int16_t* data = reinterpret_cast<const int16_t*>(pNotification + 1); What PLC data type has the variable you are trying to read?

alexanderwwagner commented 1 year ago

I tried to read some integer values : INT | -32768 | 32767 | 16 bit-- | -- | -- | -- https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/2529399691.html&id=

pbruenn commented 1 year ago

Ooops, sorry took me some time to understand my own example. You have to adjust this line: https://github.com/Beckhoff/ADS/blob/master/example/example.cpp#L32

static void notificationByNameExample(std::ostream& out, const AdsDevice& route)
{
    const AdsNotificationAttrib attrib = {
-       1,
+       sizeof(uint16_t),
        ADSTRANS_SERVERCYCLE,
        0,
        {4000000}
    };

The example was written to be generic. https://github.com/Beckhoff/ADS/blob/master/example/example.cpp#L23-L25 cbSampleSize is not number of samples but size of sample in bytes. What makes it worse is that we have taken a 1 byte example, which reinforces the false impression that data is an array of values. I will try to find a better example...

alexanderwwagner commented 1 year ago

Thank you! That solved the problem :)