libplctag / libplctag4android

An experimental repo with an example Android application using libplctag.
Mozilla Public License 2.0
2 stars 2 forks source link

Tag.java is a copy of the version in libplctag4j #1

Open kyle-github opened 4 years ago

kyle-github commented 4 years ago

The Tag.java file is a copy of the version in libplctag4j.

The solution should be to use libplctag4j directly either in the same manner as libplctag is used or by cloning/pulling the repo and then just using the single file. Ideally the entire libplctag4j repo could be used as is and a minimal JAR built with just the single Tag.class file in it.

GitHubDragonFly commented 4 years ago

I was experimenting with this repo and here is what worked:

Here is what modifications look like:

Android guard, which allows it to bypass examples and tests but I am not sure if it is correct and whether it works properly in other platforms:

if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
    # add the examples and tests
    all entries here
endif()

Project's build.gradle file:

plugins { id 'org.ajoberstar.grgit' version '4.0.2' apply true }

App's build.gradle file:

import org.ajoberstar.grgit.Grgit

externalNativeBuild {
    cmake {
        path "$rootDir/app/src/main/cpp/libplctag/CMakeLists.txt"
        version "3.10.2"
    }
}
task checkoutLibplctagSource {
    def libplctagFolderPath = "$rootDir/app/src/main/cpp/libplctag"
    def libplctagFolder = new File(libplctagFolderPath)

    // if it does not exist, then clone the repo.
    if(!libplctagFolder.exists()) {
        Grgit.clone(dir: libplctagFolder, uri: "https://github.com/libplctag/libplctag.git", refToCheckout: "release")
    } else {
        // if it does exist, do a pull.
        def grgitInstance = Grgit.open(dir: libplctagFolder)
        grgitInstance.pull()
    }
}

The above procedure does clone the "release" library but continuous connection to the Internet is required while working on the project in Android Studio since, whenever synced, it will throw an error if it cannot find github.com.

My solution was to clone the library, update the CMakeLists.txt file, comment out the above procedure and then switch networks for testing while working on the project.

kyle-github commented 4 years ago

Hi,

There is an Android guard already, but not in the release version. It is in prerelease. I have tested it and it Works For Me(tm) :smiley: I will be releasing it to the release branch this weekend. I have not announced the Android repo officially because not all of the pieces are in release status yet.

The requirement for an Internet connection is a problem. I think some careful tweaking of the gradle build can be done so that if there is no copy downloaded, it will download, and if there is not, it will try to do a pull but if that fails, it won't fail the build. I think I saw an example of how to do that.

That way, if you do have an internet connection, it will update from Git and if you don't, the build will still succeed.

Can you please open an issue on the Android repo? Most of your changes are there and not in this one :-)

I am concerned about the JNA problem. I will experiment there. I want to make sure that the build automatically gets it if it is missing and automatically updates it if not. Thanks for bringing that up.

kyle-github commented 4 years ago

BTW, why did you need to change the dependency on grgit? It was working for me in my tests the way it was. I am not saying that the way it was was the best way to do it. I am still learning Gradle, so I would like to know why you made those changes.

GitHubDragonFly commented 4 years ago

The simple process was to download this experimental project and open it in Android Studio. The very first error it stopped at was the grgit saying it couldn't invoke method clone() on null object.

What do you mean by "Can you please open an issue on the Android repo?" ? Would that be the android_mods branch?

The reason I posted here is because I was testing this experimental repo.

kyle-github commented 4 years ago

Sorry about the "please open an issue..." I was reading from email and failed to notice that you were filing the comment on this repo and not the C repo :facepalm:

I still do not have the problem of requiring an Internet connection at all times fixed. However, I am able to completely erase my working copy, clone it from GitHub, follow the directions in the README and build a working APK. I am now doing that as one of my base tests to make sure that I do not have a copy that only works locally.

I was able to eliminate all the remnants of the ASAN libraries. That cleaned up a lot of things. I like it when I can make the build file even smaller.

I was able to fix the git checkout problem for the C library. It now makes the directories if they do not exist and then does the checkout into them. I also fixed the problem that you saw with grgit and the "cannot clone null". That was a problem on the original C repo. I had done a full PR merge into the release branch and had deleted the prerelease branch, then went to bed and never recreated it. Again, totally my fault on that :disappointed:

Over in the libplctag4j repo, I now have the buildt making two JAR files. One has everything and the kitchen sink as before. The other has just the Tag.class and inner class files. I hope to eventually push these to JCenter and Maven Central so that the minimal JAR can be a standard dependency in the Android project.

GitHubDragonFly commented 4 years ago

You will need to specify the exact steps for those who would like to start a fresh Android Studio project and include your library.

As for now, here is what currently works in Android Studio, assuming that whenever you make changes you do File/Save All and File/Sync with Gradle Files:

plugins { id 'org.ajoberstar.grgit' version '4.0.2' apply true }

import org.ajoberstar.grgit.Grgit

externalNativeBuild {
    cmake {
        path "$rootDir/app/src/main/cpp/libplctag/CMakeLists.txt"
        version "3.10.2"
    }
}

tasks.whenTaskAdded { task ->
    if (task.name == "externalNativeBuild") {
        task.dependsOn checkoutLibplctagSource
    }
}

task checkoutLibplctagSource {
    def libplctagFolderPath = "$rootDir/app/src/main/cpp/libplctag"
    def libplctagFolder = new File(libplctagFolderPath)

    // if it does not exist, then clone the repo.
    if (!libplctagFolder.exists()) {
        // need to make the directory in which we will check out the C library.
        libplctagFolder.mkdirs()

        // get the C library.
        Grgit.clone(dir: libplctagFolderPath, uri: "https://github.com/libplctag/libplctag", refToCheckout: "prerelease")
    } else {
        // if it does exist, do a pull.
        def grgitInstance = Grgit.open(dir: libplctagFolderPath)
        grgitInstance.pull()
    }
}

and add to the dependencies:

implementation 'net.java.dev.jna:jna:5.6.0@aar' (save all and sync)

The library gets cloned and everything is built without any issues, which suggests that your Android guard is working fine.

Grgit just wouldn't work without that import and using "$rootDir/app/src/main/cpp/libplctag" instead of "$buildDir/src/cpp/libplctag". Continuous Internet connection is still required.

GitHubDragonFly commented 4 years ago

The way I was doing it was to download zipped files and open it as an existing project.

I just tried doing things the way you do them, by using Android Studio's feature Get from Version Control (Git) and the project does clone without errors but with a warning about missing jna folder.

The mentioned jna reference seems to be inside the project's settings.gradle, stated as: include ':jna'.

Another thing would be your choice of folder inside the app's build.gradle: "$buildDir/src/cpp/libplctag" An attempt to use Build/Rebuild Project feature will try to delete the build folder all together.

You might try "$rootDir/app/src/main/cpp/libplctag" instead because that's pretty much the location where Android Studio stores C++ files when a new project is created with a C++ selection.

GitHubDragonFly commented 4 years ago

Just so you know, it is possible to package, into an AAR library, all precompiled android libplctag libraries together with Tag.java file.

The installation is then very simple, it is imported as a module into a project but, the way I've done it, it also requires jna.aar module to be separately installed.

kyle-github commented 4 years ago

Hmm, I had not tried loading the project as a ZIP file. I wonder why that is different? Thanks for that pointer as some people will do that!

Thanks for the pointer to settings.gradle! That seems to have been the remaining reference to JNA outside of the dependencies. I got rid of that reference and the warning is gone! The build still works.

The choice of folder for the C project is intentional. There is not a well defined Gradle step for loading source but it is considered a bad idea to do any source loading or generation into the existing source tree. By putting it into the build directory, I am following "best practices" (for some definition thereof!). I am not fond of it, but I do want an explicit "Project clean" to clear it out as the calls to CMake are fairly basic. From what I can tell doing a normal build will result in a git pull to update the source.

So at this point this is "working as designed" though the design may not be done yet :-)

I want to get to the point where I can make an AAR JAR (is that the term?), but that will require headless Gradle operation and that, in turn requires loading the NDK with Gradle. I am not there yet, but that is the plan. All the other repos I use are fully headless and build on GitHub's CI system and generate usable artifacts. It is definitely the plan to have a single JAR that is directly usable by Android without any other dependencies.

In the mean time I am getting closer to getting a push to JCenter working with the libplctag4j project. As soon as I have that working as a prototype, I can focus on how to generate the AAR with headless Gradle on GitHub CI. Once I have the headless Gradle working, I may merge that into the libplctag4j project rather than the Android project so that it generates several artifacts for use. Then the Android project can become even simpler and more straightforward as an example!

Thanks for doing all this testing. I will try to understand why the ZIP file is different than doing a git clone and fix that.

GitHubDragonFly commented 4 years ago

If you try using the grgit as I did then it might possibly work for both. As for the folder choice, you should test the project as zip file to see if it creates errors (which it did from what I recall).

As for the AAR, here is what worked for me:

No jna files will be included in it, there will be "jni" folder with libplctag libraries and also 4 empty folders will be added to it. Not really sure how to disable creation of these 4 empty folders but the AAR can be opened with 7-zip program and these folders deleted.

The attached pictures show the project folder structure, libplctag's build.gradle file as well as the resulting AAR file opened with 7-zip program.

Then this AAR can be added as a module to any new project but will also require jna.aar module to be installed separately.

Android Studio AAR archive

kyle-github commented 4 years ago

I have to drop this for a few days, but this weekend I was able to get a single Gradle build system that builds two projects:

  1. A normal "fat" JAR.
  2. A normal "fat" AAR for Android.

I am not entirely sure what should be in an AAR, but I see all the libjni_blah.so stuff from JNA. I see the C++ library .so and I see libplctag.so. I see all the libplctag classes in classes.jar as well as the JNA classes.

This is still very fragile and broken but I think I am getting pretty close to being able to build both sets of artifacts via GitHub Actions CI automatically from the libplctag4j project.

I am also starting to push JARs (and hopefully soon AARs) to JCenter automatically if the build and tests succeed. Or at least to some part of JFrog's system. I am definitely flailing about with that, but the JARs push. I have not tried to pull them via a dependency yet.

The longer term plan is to modify libplctag4j so that it builds both JAR and AAR artifacts, both with the native libraries and JNA included. I am very close to that now. Then I'll push those to JCenter via GitHub Actions. I am doing that now, I think, but I do not know if they are usable via dependencies. Again, long term the goal is to build the native libraries at the time I build the JARs using the latest tagged version of the C library. This is already happening for Android AARs.

Once I get JARs and AARs pushed to JCenter correctly, then I can try to modify the Android app so that it just has a dependency on the libplctag4j AAR and get that working.

GitHubDragonFly commented 4 years ago

Strings in this experimental project were hard coded for quick testing.

Here is a possible way of allowing a user to enter certain parts of the string manually from the MainActivity and then pass it on to the async task for processing (this is a shortened version of getting tags from CLGX PLC):

public class AsyncTaskGetCLGXTags extends AsyncTask<String, Void, String> { private static String tagGetControllerTags = ""; private static String tagGetProgramTags = ""; int timeout; public List< String > valsC = new ArrayList< ~ >(), valsP = new ArrayList< ~ >();

private Tag GetCLGXTagsMaster = null;

// This is used to update the UI
GetCLGXTagsTaskCallback GetCLGXTagstaskCallback = MainActivity.GetCLGXTagstaskCallback;

@Override
protected String doInBackground(String... params) {
    tagGetControllerTags = "protocol=ab_eip&" + params[0] + "&cpu=controllogix&name=@tags";
    tagGetProgramTags = "protocol=ab_eip&" + params[0] + "&cpu=controllogix&name=Program:" + params[1] + ".@tags";
    timeout = Integer.parseInt(params[2]);

    GetCLGXTagsMaster = new Tag(tagGetControllerTags, timeout);

    .
    .    code for processing where all controller tags can be stored into valsC that will be                   
    .    returned to UI via publishProgress() that is using callback
    .

    GetCLGXTagsMaster = new Tag(tagGetProgramTags, timeout);

    .
    .    code for processing where all tags can be stored into valsP initially and then
    .    added to valsC, which is returned to UI via publishProgress() that is using callback
    }

public interface GetCLGXTagsTaskCallback { void UpdateGetCLGXTagsUI(List< String > vals); }

Everything above marked as "< String >" and "< ~ >" needs to have spaces removed, since GitHub system doesn't show them as such, for whatever reason.

kyle-github commented 4 years ago

Ooh, nice! I was thinking that listing tags would be nice as then you could just point at one and click it.

GitHubDragonFly commented 4 years ago

It wouldn't be as simple as that, you would still need to specify the data type so the received value can be displayed properly (element size alone doesn't cut it since 4 bytes could be for either integer or float).

If all CLGX PLCs are responding with the same type values then it might be possible to create a predetermined Type -> Data Type list, like an example below:

Type......Data Type 193........BOOL 195........INT 196........DINT 197........LINT 202........REAL

The way I am currently doing this is to use Android "spinner" controls, which are like a drop-down clickable list (or combobox in Visual Studio).

If you check the attached picture, which shows a part of the tablet UI that I am creating, spinner controls are blue and green.

The blue one is using preset strings of cpus while the green one is dynamically populated with received CLGX tags. Clicking a tag does copy it to the clipboard which can then be used in other part of UI where data type can be added and then sent to the async task.

Tablet UI

kyle-github commented 4 years ago

When you get a tag back from the tag listing, one of the attributes that comes back is the tag type. It is a little finicky to decode. I can send you a picture of what it all means and there is some C code I have that knows what most of the type codes mean.

It sounds like what you are talking about is doing an Android app version of the tag_rw command, only a lot nicer!

Dealing with UDTs and system structures is certainly possible, but at this point is not supported by the library. I just saw your issue on the C library and I'll respond there.

There is a bit of a discussion about whether to embed the tag reading into the library or not. Right now it is half in the library and half out of it. If I embed it completely in the library, then I can use a different way to read tags that uses less space and supposedly is slightly faster. But then the library will not be as good for embedded use because it will be larger and use a lot more memory at run time.

GitHubDragonFly commented 4 years ago

The document mentioned in that issue I raised on the C library actually describes of how to interpret type. It is something along the line of:

The simplest thing I could think of was to actually include data type in the name of the tag, something you can see in the picture I posted previously but here it is again:

Get Tag List

So, as per this I did create a small table of identities but am not sure if this is a standard and if all controllers respond with the same type value:

Value..........Type 193...............BOOL (1 byte) 195...............INT (2 bytes) 196...............DINT (4 bytes) 197...............LINT (8 bytes) 202...............REAL (4 bytes) 8387.............INT ARRAY [x] (2 bytes) 8388.............DINT ARRAY [x] (4 bytes) 8394.............REAL ARRAY [x] (4 bytes) 8403.............BOOL ARRAY [x] (4 bytes) 16579...........INT ARRAY [x, y] (2 bytes) 16580...........DINT ARRAY [x, y] (4 bytes) 16586...........REAL ARRAY [x, y] (4 bytes) 24772...........DINT ARRAY [x, y, z] (4 bytes) 24778...........REAL ARRAY [x, y, z] (4 bytes) 34920...........CUSTOM LENGTH STRING (8 bytes) - 1char 36171...........CUSTOM LENGTH STRING (24 bytes) - 20char 35541...........TIME (28 bytes) 36738...........COUNTER (12 bytes) 36737...........CONTROL (12 bytes) 36739...........TIMER (12 bytes) 36814...........STRING (88 bytes) 45006...........STRING ARRAY [x] (88 bytes)

GitHubDragonFly commented 4 years ago

As for the android, the AAR should only have libplctag.so (which is plctag) and libjnidispatch.so (which is jna) as everything works properly with them only.

The other ones seem to be used only with the whole library project when it is added to android studio project.

GitHubDragonFly commented 4 years ago

Just to mention that you still have -fsanitize=undefined,address flags in your CMakeLists.txt file.

kyle-github commented 4 years ago

Here are the types for the built in "atomic" types:

#define AB_CIP_DATA_BIT         ((uint8_t)0xC1) /* Boolean value, 1 bit */
#define AB_CIP_DATA_SINT        ((uint8_t)0xC2) /* Signed 8–bit integer value */
#define AB_CIP_DATA_INT         ((uint8_t)0xC3) /* Signed 16–bit integer value */
#define AB_CIP_DATA_DINT        ((uint8_t)0xC4) /* Signed 32–bit integer value */
#define AB_CIP_DATA_LINT        ((uint8_t)0xC5) /* Signed 64–bit integer value */
#define AB_CIP_DATA_USINT       ((uint8_t)0xC6) /* Unsigned 8–bit integer value */
#define AB_CIP_DATA_UINT        ((uint8_t)0xC7) /* Unsigned 16–bit integer value */
#define AB_CIP_DATA_UDINT       ((uint8_t)0xC8) /* Unsigned 32–bit integer value */
#define AB_CIP_DATA_ULINT       ((uint8_t)0xC9) /* Unsigned 64–bit integer value */
#define AB_CIP_DATA_REAL        ((uint8_t)0xCA) /* 32–bit floating point value, IEEE format */
#define AB_CIP_DATA_LREAL       ((uint8_t)0xCB) /* 64–bit floating point value, IEEE format */
#define AB_CIP_DATA_STIME       ((uint8_t)0xCC) /* Synchronous time value */
#define AB_CIP_DATA_DATE        ((uint8_t)0xCD) /* Date value */
#define AB_CIP_DATA_TIME_OF_DAY ((uint8_t)0xCE) /* Time of day value */
#define AB_CIP_DATA_DATE_AND_TIME ((uint8_t)0xCF) /* Date and time of day value */
#define AB_CIP_DATA_STRING      ((uint8_t)0xD0) /* Character string, 1 byte per character */
#define AB_CIP_DATA_BYTE        ((uint8_t)0xD1) /* 8-bit bit string */
#define AB_CIP_DATA_WORD        ((uint8_t)0xD2) /* 16-bit bit string */
#define AB_CIP_DATA_DWORD       ((uint8_t)0xD3) /* 32-bit bit string */
#define AB_CIP_DATA_LWORD       ((uint8_t)0xD4) /* 64-bit bit string */
#define AB_CIP_DATA_STRING2     ((uint8_t)0xD5) /* Wide char character string, 2 bytes per character */
#define AB_CIP_DATA_FTIME       ((uint8_t)0xD6) /* High resolution duration value */
#define AB_CIP_DATA_LTIME       ((uint8_t)0xD7) /* Medium resolution duration value */
#define AB_CIP_DATA_ITIME       ((uint8_t)0xD8) /* Low resolution duration value */
#define AB_CIP_DATA_STRINGN     ((uint8_t)0xD9) /* N-byte per char character string */
#define AB_CIP_DATA_SHORT_STRING ((uint8_t)0xDA) /* Counted character sting with 1 byte per character and 1 byte length indicator */
#define AB_CIP_DATA_TIME        ((uint8_t)0xDB) /* Duration in milliseconds */
#define AB_CIP_DATA_EPATH       ((uint8_t)0xDC) /* CIP path segment(s) */
#define AB_CIP_DATA_ENGUNIT     ((uint8_t)0xDD) /* Engineering units */
#define AB_CIP_DATA_STRINGI     ((uint8_t)0xDE) /* International character string (encoding?) */

If the type is not a structure or system type, then the lowest byte is one of the above values. I am probably missing one or two.

The ASAN stuff is still not released to the release label yet, so you probably still see it. It is on the tip of the prerelease label. I am trying not to flood the group using the C library with changes, so I am batching them up to the release branch.

GitHubDragonFly commented 4 years ago

Thank you for those types, now I am a bit smarter and might eventually use that knowledge.

As for the unsigned functions in your Tag.java, the getUInt64() is missing all together and I am not sure if the other ones work properly. Just an FYI, here is what I have and appears to be working properly for READING:

public BigInteger getUInt64(int offset) {
    long tmp_res = Tag.plc_tag_get_uint64(this.tag_id, offset);

    BigInteger value = new BigInteger(String.valueOf(tmp_res));
    BigInteger max = new BigInteger("18446744073709551615");

    if(tmp_res < 0) {
        value = max.add(value);
    }

    return value;
}

public long getUInt32(int offset) {
    long tmp_res = Tag.plc_tag_get_uint32(this.tag_id, offset);

    if(tmp_res < 0) {
        tmp_res = tmp_res & 0xFFFFFFFFL;
    }

    return tmp_res;
}

public int getUInt16(int offset) {
    int tmp_res = Tag.plc_tag_get_uint16(this.tag_id, offset);

    if(tmp_res < 0) {
        tmp_res = tmp_res & 0xFFFF;
    }

    return tmp_res;
}

public short getUInt8(int offset) {
    short tmp_res = Tag.plc_tag_get_uint8(this.tag_id, offset);

    if(tmp_res < 0) {
        tmp_res = (short) (tmp_res & 0xFF);
    }

    return tmp_res;
}

Here is what I have not tested yet and is intended for WRITING:

public int setUInt64(int offset, BigInteger val) { return Tag.plc_tag_set_uint64(this.tag_id, offset, val.longValue()); }

public int setUInt32(int offset, long val) { return Tag.plc_tag_set_uint32(this.tag_id, offset, (int)val); }

public int setUInt16(int offset, int val) { return Tag.plc_tag_set_uint16(this.tag_id, offset, (short)val); }

public int setUInt8(int offset, short val) { return Tag.plc_tag_set_uint8(this.tag_id, offset, (sbyte)val); }
kyle-github commented 4 years ago

I intentionally left out the unsigned 64-bit integer stuff because Java did not have a primitive type that would match. I did not even think of using BigInteger!

Would you be able to cut a PR for that?

GitHubDragonFly commented 4 years ago

The reason I put the code in my comments is so you can look at it and if you find anything useful then integrate it wherever it might fit. There are no restrictions that come with any of the code so you can modify and apply it under your licenses (not to mention the fact that it is actually your original code that was just modified by me).

You are keeping track of everything in your own way so do the same with this.

GitHubDragonFly commented 4 years ago

There should be a small correction in the code related to:

BigInteger max = new BigInteger("18446744073709551615");

It should be increased by 1 to read "18446744073709551616" for the calculation.

kyle-github commented 4 years ago

Sorry, I have not been to responsive. Work is killing me right now. It's going to be another week or so before this slows down a little bit.

GitHubDragonFly commented 4 years ago

Just so you know a bit more about this latest pull request:

GitHubDragonFly commented 4 years ago

The latest change to the app's build.gradle file is the addition of ping which checks Internet connectivity.

If it might be considered intrusive by the network being pinged than maybe we should remove it.

The following article suggests that pinging is harmless but I cannot be smart about it:

https://www.pingplotter.com/wisdom/article/is-ping-dangerous

Since my latest pull request is proposing pinging your newly created website, is there a way that you can find out from GitHub whether they have a policy related to pings?

GitHubDragonFly commented 4 years ago

As for the pull request in this repo, if you don't find the proposed changes acceptable then just cancel it or reject it (whatever github allows you to do).

Just in case if you might be interested, I have created a new repo with a full Android project designed for tablet use:

https://github.com/GitHubDragonFly/TabletTest

It could potentially be described as a GUI version of your tag_rw tool and is using a slightly modified Tag.java file.

kyle-github commented 4 years ago

Sorry! I completely got buried with other stuff and totally forgot about this PR!

I just merged it.

I am still buried at work and have not been able to finish up the JCenter uploads. I am having problems with having two completely different Gradle projects using the same source code. It seems like I am close but it is still not working. I found a fatal flaw in how I was testing and that uncovered a flaw in how I was using JNA. That is fixed but the result is only a "normal" JAR file. I have not fixed the Android version of libplctag4j yet.

GitHubDragonFly commented 4 years ago

What you are trying to do for Android jar seems to be rather tricky.

Implementing JNA project doesn't include Android libraries. It does include them if "@AAR" is specified but then the resulting jar will include the AndroidManifest.xml file that Android Studio sees as an error (which interestingly enough it doesn't complain about when jna.aar file is added as a module to Android Studio project).

My suggestion to you would be to create libplctag.aar file yourself and release it as such (or just use the one from the tablet project I mentioned). This would provide for an easy implementation in Android projects, along with jna.aar file.

The latest libplctag libraries can be compiled with libplctag4android project, extracted from the resulting APK and re-packed into the existing AAR file.

GitHubDragonFly commented 3 years ago

There is now another Android phone project, which is more user friendly in a sense that it allows users to enter all the parameters via GUI:

https://github.com/GitHubDragonFly/PhoneTest

It does not include the Modbus functionality of the libplctag library but can be used as an example of how to create a project that would include it.

kyle-github commented 3 years ago

Nice! I just got libplctag4j to upload to JCenter. I am trying to figure out if I have it all working right. I ran out of time last weekend. It took far longer than reasonable to figure out the exact POM contents, path etc. to upload. Luckily the JFrog support people were very patient with me.

I am pretty close to uploading a version of the AAR, but I want to make sure everything is tested first. Then I can go back and make sure that I get your BigInt changes added.

maurojrodriguezj commented 3 years ago

Good evening,

I try to run the project, fine, but this Line:

private static String tagABString = "protocol=ab_eip&gateway=192.168.1.10&path=0&plc=micrologix&elem_size=0&elem_count=1&name=Signal";

but only I get err-7, how can i set up to read the real value?