1

Let me quickly describe my setup and goal. I have a android tablet display running Android version 7.1.2

I have a motor controller that is hooked up to the Android tablet via ethernet. In my Android app that controls the motor controller, I use Wifi to communicate with some servers that provide/store data. Currently, I can use an Android simulator (in Android Studio) that allows me to communicate with the motor controller while also using the wifi for calls to the server. When I run the app on the Android tablet itself, I can only have Wifi OR Ethernet active at one time.

According to this post this is a hard limitation in Android itself. It also details some possible fixes, but its quite old and to be honest I do not have any experience in the required steps described by their vague instructions.

Can anyone provide a more up-to-date solution to this problem, preferably one that is a little more detailed for newbies like me? Even just a pointer to learning how to do the necessary steps for fixing this would be great, I've been stuck on this for awhile! Thanks for any help!

EDIT: Here's some relevant info in regards to AlwaysLearning's answer...

The class I use to manage reading from Modbus

public class ModbusRead {

    private static final String TAG = "MODBUS READ";

    ModbusClient mClientReadAll;

    public ModbusRead()
    {
//        IP = "192.168.124.2";
//        port = 502;
        mClientReadAll = new ModbusClient(Modbus.IP, Integer.valueOf(Modbus.port));
        mClientReadAll.setUnitIdentifier((byte)255);
    }

    public Runnable readAll()
    {
        return () -> {

                ReadAllFromModbus mReadAll = new ReadAllFromModbus();
                mReadAll.execute();
        };
    }

    public class ReadAllFromModbus extends AsyncTask<String, Void, String> {

        private final String TAG = "READ ALL FROM MODBUS";

        @Override
        protected String doInBackground(String... params) {

            try
            {
                mClientReadAll.Connect();

                // get all registers
                int[] registerBlock = mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_MODE.getRegister()- 1, 16);
                int[] wideRegisters = new int[] {
                        Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ACTUAL_POSITION.getRegister() - 1, 2)),
                        Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_TARGET_POSITION.getRegister() - 1, 2)),
                        Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ROM_DELTA.getRegister() - 1, 2)),
                        Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_REWIND_ZERO.getRegister() - 1, 2))
                };
                int[] tensionRegister = mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ACTUAL_TENSION.getRegister() - 1, 1);

                Modbus.updateAllRegisters(registerBlock, wideRegisters, tensionRegister);

            }
            catch (Exception e)
            {
                Log.i(TAG, "ERROR IN GETTING ALL REGISTERS LOOP: " + e.getMessage());
                e.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);

            try
            {
                mClientReadAll.Disconnect();
            }
            catch(Exception e)
            {
                Log.i(TAG, "ERROR IN DISCONNECTING");
            }
        }
    }
}

The relevant part of my Dashboard class that would handle starting the thread that does all the modbus reading

How would I go about forcing the ModbusRead class to use the Ethernet here?

    ModbusRead modbusRead = new ModbusRead();

    final ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);

    final NetworkRequest requestEthernet = new NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
            .build();

    final ConnectivityManager.NetworkCallback cbEthernet = new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(Network network) {

            // connectivityManager.bindProcessToNetwork(network);

            try
            {
                // Modbus.IP = "192.168.124.2"
                // Modbus.port = 502
                Log.i(TAG, "TRYING TO BIND SOCKET...");

                InetAddress address = InetAddress.getByName(Modbus.IP);

                Log.i(TAG, "ADDRESS: " + address.toString());

                Socket socket = new Socket(address, Modbus.port);

                Log.i(TAG, "SOCKET CREATED..." + socket.getInetAddress());

                network.bindSocket(socket);

                Log.i(TAG, "BOUND ETHERNET");
            }
            catch (Exception e)
            {
                e.printStackTrace();
                Log.i(TAG, "EXCEPTION: " + e.getMessage());
            }
        }
    };

    connectivityManager.requestNetwork(requestEthernet, cbEthernet);

    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    executorService.scheduleAtFixedRate(modbusRead.readAll(), 2000, 250, TimeUnit.MILLISECONDS);
Jake
  • 41
  • 3
  • This is possible. but the app's themselves need to explicitly request a particular network type. I.e., if your motor controller app wants to use Wifi for some particular operations, it needs to let Android know that by making a request specifically for Wifi. Here is an example solution here for reference: https://stackoverflow.com/a/67081087/2267817 – Always Learning Jun 10 '22 at 20:43
  • @AlwaysLearning, thank you for your answer! Do you happen to know how I would integrate your solution into my project (using the provided code above)? – Jake Jun 14 '22 at 15:52
  • Hi @Jake, you need to file two 'NetworkRequest' objects as mentioned in the referenced answer. Everything for how to do so is listed so you should be good to go. – Always Learning Jun 14 '22 at 16:09
  • @AlwaysLearning, I guess I don't understand what exactly I'm supposed to do. I have the code from the post you linked, and the callbacks are being called but I'm still unsure of how I'm supposed to force the modbus stuff to use the local ethernet connection? Right now, it is just giving me errors saying the connection timed out because I assume its trying to use the wifi connection to connect to the specified local IP address/port. I don't have any experience in Java networking so and I'm a bit of a beginner anyway so this is all a bit confusing to me... – Jake Jun 15 '22 at 14:29
  • Hi @Jake, I updated the referenced answer to include how to use the network that is returned. Hopefully it helps. – Always Learning Jun 15 '22 at 17:51
  • @AlwaysLearning, you've definitely put me on the right track! I can use the bindProcessToNetwork() call and the ethernet appears to work (though of course wifi will not work then). My last question for you would be that when I try and bind a socket it appears to hang? I've updated my code snippet and the log statement "SOCKET CREATED..." is never called, though no error is ever thrown either. Is there anything that sticks out to you there? I know the address/port for the motor controller is correct. Thanks for all the help you've given me so far :) – Jake Jun 16 '22 at 14:41
  • Have you tried to bind to a socket using the default constructor: `Socket socket = new Socket` as opposed to the one you are currently using when passing in the address/port? – Always Learning Jun 16 '22 at 17:01
  • @AlwaysLearning, I can make a socket like that but it doesn't do anything? I don't know if I'm understanding the network side of this correctly... So the modbus library I'm using is going to open a new connection to the motor controller using the IP address and port I have in the code above, that means I want the app to send anything addressed to that socket over ethernet. So shouldn't I be binding the socket the Modbus library is going to use to this ethernet network? – Jake Jun 16 '22 at 19:38
  • If you bind to the socket, it'll be to the network serving the underlying ethernet interface. If however you have additional requirements (e.g. needs to use a specific port, etc.), you may need to set the port as you are doing now. At the end of the day, it's just a plain Java socket and thankfully, there's a lot of data out there on how to use sockets to connect to networks. Here's one example: https://stackoverflow.com/q/7384678 Hope that helps! – Always Learning Jun 16 '22 at 20:04
  • @AlwaysLearning, unfortunately I cannot get it to work, no matter what I try it appears to fail. I've posted a new question with some more details [here](https://stackoverflow.com/questions/72664814/using-java-connectivitymanager-to-allow-android-to-use-both-wifi-and-local-eth) if you wanted to consider this problem further, otherwise thanks for the help you've given me so far, I do appreciate it. – Jake Jun 17 '22 at 21:12
  • Yeah, sure thing and if you found the original answer I posted above in the comment thread, please feel free to upvote it. Thanks and best of luck, sounds like you are really close. – Always Learning Jun 17 '22 at 23:29

0 Answers0