Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Using serial port on android
Forum Updated to NodeBB v4.3 + New Features

Using serial port on android

Scheduled Pinned Locked Moved Solved Mobile and Embedded
3 Posts 3 Posters 5.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    chaz
    wrote on 28 Nov 2023, 14:22 last edited by chaz
    #1

    Hi,
    I am porting a Qt application to Android. A major feature of the application relies on using the QSerialPort module, which is not officially supported by Qt Android and it only works on rooted devices which is not a solution for me. Is there a way to port my application without having to make large changes to my code (like switching to BT instead of QSerialPort)?

    I have seen a patch mentioned before, I think it is this one, https://codereview.qt-project.org/c/qt/qtserialport/+/84338/2 . Is this still the way to make QSerialPort work in Qt 5.15.15 or is there another way?

    Kind Regards
    Chaz.

    J L 2 Replies Last reply 28 Nov 2023, 14:25
    0
    • C chaz
      28 Nov 2023, 14:22

      Hi,
      I am porting a Qt application to Android. A major feature of the application relies on using the QSerialPort module, which is not officially supported by Qt Android and it only works on rooted devices which is not a solution for me. Is there a way to port my application without having to make large changes to my code (like switching to BT instead of QSerialPort)?

      I have seen a patch mentioned before, I think it is this one, https://codereview.qt-project.org/c/qt/qtserialport/+/84338/2 . Is this still the way to make QSerialPort work in Qt 5.15.15 or is there another way?

      Kind Regards
      Chaz.

      L Offline
      L Offline
      lemons
      wrote on 29 Nov 2023, 10:51 last edited by lemons
      #3

      I had the same issue for an FTDI usb device and ended up re-writing the interface with JNI.

      For the android part I used this package:
      https://github.com/mik3y/usb-serial-for-android/

      For this package I had to switch to OpenJDK 18, in order to use the required gradle version.

      As the JNI part is static, I used the singleton pattern to build an asynchronous interface.

      Depending on your current implementation / usage of QSerialPort, you might be able to simply swap out the QSerialPort for a JNI wrapper class on Android.

      In total this looks something like this:

      • mydevice.h
      • mydevice.cpp
      • android/src/com/mycompany/mydevice/SerialHelper.java
      • changes in AndroidManifest.xml
      • changes in build.gradle

      In the following some snippets. I tried to reduce the snippets but to still cover the JNI parts.

      // mydevice.h
      // JNI methods
      public:
          static void JNICALL javaResponseReady(JNIEnv *env, jobject obj, jbyteArray byteArray);
          static void JNICALL javaConnectedStateChanged(JNIEnv *env, jobject obj, jboolean state);
          static void JNICALL javaErrorOccured(JNIEnv *env, jobject obj, jstring error);
          static void JNICALL javaMyDeviceAttached(JNIEnv *env, jobject obj, jboolean state);
      	
      private:
          void qtResponseReady(QByteArray qByteArray);
          void qtConnectedStateChanged(bool state);
          void qtErrorOccurred(QString errorMessage);
      
      // mydevice.cpp
      void MyDevice::connectDevice()
      {
          QAndroidJniObject activity = QtAndroid::androidActivity();
          QAndroidJniObject context = QtAndroid::androidContext();
      
          if (activity.isValid() && context.isValid()) {
              QAndroidJniObject::callStaticMethod<void>(
                  "com/mycompany/mydevice/SerialHelper",
                  "connectToDevice",
                  "(Landroid/content/Context;II)V",
                  context.object(),
                  MY_DEVICE_VID,
                  MY_DEVICE_PID
              );
          }
      }
      void MyDevice::sendCommand(QByteArray command)
      {
          if (command.isEmpty())
              return;
      
          activeCommand.clear();
          activeCommand = command;
      
          QAndroidJniObject javaCommand = QAndroidJniObject::fromString(QString(command));
          QAndroidJniObject::callStaticMethod<void>(
              "com/mycompany/mydevice/SerialHelper",
              "sendCommand",
              "(Ljava/lang/String;)V",
              javaCommand.object<jstring>()
          );
      }
      
      void MyDevice::javaResponseReady(JNIEnv *env, jobject obj, jbyteArray byteArray)
      {
          jbyte *elems = env->GetByteArrayElements(byteArray, 0);
          jsize len = env->GetArrayLength(byteArray);
          QByteArray qByteArray(reinterpret_cast<char*>(elems), len);
          env->ReleaseByteArrayElements(byteArray, elems, 0);
      
          MyDevice &instance = MyDevice::getInstance();
          instance.qtResponseReady(qByteArray);
      }
      
      void MyDevice::javaConnectedStateChanged(JNIEnv *env, jobject obj, jboolean state)
      {
          MyDevice &instance = MyDevice::getInstance();
          instance.qtConnectedStateChanged((bool) state);
      }
      
      void MyDevice::javaErrorOccured(JNIEnv *env, jobject obj, jstring error)
      {
          const char* utfStr = env->GetStringUTFChars(error, 0);
          QString qStr = QString::fromUtf8(utfStr);
          env->ReleaseStringUTFChars(error, utfStr);
      
          MyDevice &instance = MyDevice::getInstance();
          instance.qtErrorOccurred(qStr);
      }
      
      void MyDevice::javaMyDeviceAttached(JNIEnv *env, jobject obj, jboolean state)
      {
          MyDevice &instance = MyDevice::getInstance();
          if(state){
              instance.connectDevice();
          } else {
              instance.disconnectDevice();
          }
      }
      
      JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
      {
          JNIEnv* env;
          if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
              return -1;
          }
      
          JNINativeMethod methods[] {
              {"javaResponseReady", "([B)V", reinterpret_cast<void*>(MyDevice::javaResponseReady)},
              {"javaConnectedStateChanged", "(Z)V", reinterpret_cast<void*>(MyDevice::javaConnectedStateChanged)},
              {"javaErrorOccured", "(Ljava/lang/String;)V", reinterpret_cast<void*>(MyDevice::javaErrorOccured)},
              {"javaMyDeviceAttached", "(Z)V", reinterpret_cast<void*>(MyDevice::javaMyDeviceAttached)}
          };
      
          jclass clazz = env->FindClass("com/mycompany/mydevice/SerialHelper");
          if (!clazz) {
              return -1;
          }
      
          if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(JNINativeMethod)) < 0) {
              return -1;
          }
      
          return JNI_VERSION_1_6;
      }
      
      // SerialHelper.java
      package com.mycompany.mydevice;
      
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      
      import android.app.PendingIntent;
      import android.content.BroadcastReceiver;
      import android.content.Context;
      import android.content.Intent;
      import android.content.IntentFilter;
      import android.hardware.usb.UsbDevice;
      import android.hardware.usb.UsbDeviceConnection;
      import android.hardware.usb.UsbManager;
      import android.util.Log;
      
      import com.hoho.android.usbserial.driver.FtdiSerialDriver;
      import com.hoho.android.usbserial.driver.UsbSerialPort;
      import com.hoho.android.usbserial.driver.UsbSerialDriver;
      import com.hoho.android.usbserial.driver.ProbeTable;
      import com.hoho.android.usbserial.driver.UsbSerialProber;
      import com.hoho.android.usbserial.util.HexDump;
      import com.hoho.android.usbserial.util.SerialInputOutputManager;
      
      import java.io.ByteArrayOutputStream;
      import java.io.IOException;
      import java.util.Arrays;
      import java.util.List;
      
      public class SerialHelper extends org.qtproject.qt5.android.bindings.QtActivity {
          private static ExecutorService executorService = Executors.newSingleThreadExecutor();
      
          private static final String ACTION_USB_PERMISSION = "com.mycompany.mydevice.USB_PERMISSION";
          private static UsbManager usbManager;
          private static UsbSerialPort serialPort;
      
          private static final int WRITE_WAIT_MILLIS = 2000;
          private static final int READ_WAIT_MILLIS = 2000;
      
          public static native void javaResponseReady(byte[] response);
          public static native void javaConnectedStateChanged(boolean state);
          public static native void javaErrorOccured(String error);
          public static native void javaMyDeviceAttached(boolean state);
      
      
          public static void closeDeviceConnection() {
              executorService.submit(new Runnable() {
                  @Override
                  public void run() {
                      if (serialPort == null) {
                          javaErrorOccured("Serial port is not initialized. Nothing to close.");
                          return;
                      }
      
                      try {
                          serialPort.close();
                          serialPort = null;
                          javaConnectedStateChanged(false);
                          return;
                      } catch (IOException e) {
                          javaErrorOccured("CLOSE PORT EXCEPTION");
                          return;
                      }
                  }
              });
          }
      
          public static void connectToDevice(Context context, int vid, int pid) {
              executorService.submit(new Runnable() {
                  @Override
                  public void run() {
                      // Create custom prober for given VID and PID
                      ProbeTable customTable = new ProbeTable();
                      customTable.addProduct(vid, pid, FtdiSerialDriver.class);
                      UsbSerialProber prober = new UsbSerialProber(customTable);
      
                      // Find all available drivers from attached devices.
                      UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
                      List<UsbSerialDriver> drivers = prober.findAllDrivers(manager);
                      if (drivers.isEmpty()) {
                          javaErrorOccured("No Device found");
                          return;
                      }
      
                      // Open a connection to the first available driver.
                      UsbSerialDriver driver = drivers.get(0);
                      UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
                      if (connection == null) {
                          PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
                          manager.requestPermission(driver.getDevice(), permissionIntent);
                          javaErrorOccured("Permission request sent. Awaiting response...");
                          return;
                      }
                      UsbSerialPort port = driver.getPorts().get(0);
                      try {
                          port.open(connection);
                          try {
                              port.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
                          } catch (UnsupportedOperationException e){
                              javaErrorOccured("UNSUPPORTED OPERATION EXCEPTION");
                              return;
                          }
                      } catch (Exception e) {
                          javaErrorOccured("OPEN PORT EXCEPTION");
                          return;
                      }
      
                      usbManager = manager;
                      serialPort = port;
                      javaConnectedStateChanged(true);
                  }
              });
          }
      
      
          public static void sendCommand(String command) {
              executorService.submit(new Runnable() {
                  @Override
                  public void run() {
                      if (serialPort == null) {
                          javaConnectedStateChanged(false);
                          javaErrorOccured("Serial port is not initialized. Call connectToDevice() first.");
                          return;
                      }
      
                      try {
                          serialPort.write(command.getBytes(), WRITE_WAIT_MILLIS);
                      } catch (Exception e) {
                          javaErrorOccured("WRITE EXCEPTION");
                          javaConnectedStateChanged(false);
                          return;
                      }
      
                      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                      byte[] buffer = new byte[8192];
      
                      try {
      		    // Read until command terminator found
                          while (true) {
                              int len = serialPort.read(buffer, READ_WAIT_MILLIS);
                              if (len > 0) {
                                  outputStream.write(buffer, 0, len);
      
      		            
                                  boolean exit = false;
      
      		            // ADD EXIT CONDITION / response termination pattern (e.g. \r\n)
      		
                                  if(exit){
                                      byte[] originalArray = outputStream.toByteArray();
      				// -2 => terminator (e.g. \r\n) removed before sending to C++
                                      byte[] trimmedArray = Arrays.copyOf(originalArray, originalArray.length - 2);
      
                                      javaResponseReady(trimmedArray);
                                      return;
                                  }
                              }
                          }
                      } catch (IOException e) {
                          javaErrorOccured("READ EXCEPTION");
                          javaConnectedStateChanged(false);
                          return;
                      }
                  }
              });
          }
      
          private static final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
              public void onReceive(Context context, Intent intent) {
                  String action = intent.getAction();
                  if (ACTION_USB_PERMISSION.equals(action)) {
                      synchronized (this) {
                          UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
      
                          if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                              if (device != null) {
                                  javaMyDeviceAttached(true);
                                  int vid = device.getVendorId();
                                  int pid = device.getProductId();
                                  connectToDevice(context, vid, pid);
                              }
                          }
                      }
                  }
              }
          };
      }
      
      // build.gradle
      buildscript {
          repositories {
              google()
              mavenCentral()
              maven { url 'https://jitpack.io' }
          }
      
          dependencies {
              classpath 'com.android.tools.build:gradle:7.2.1'
          }
      }
      
      repositories {
          google()
          mavenCentral()
          maven { url 'https://jitpack.io' }
      }
      
      apply plugin: 'com.android.application'
      
      dependencies {
          implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
          implementation 'androidx.core:core:1.3.2'
          implementation 'androidx.legacy:legacy-support-v4:1.0.0'
          implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32"
          implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.72"
          implementation 'com.github.mik3y:usb-serial-for-android:v3.6.0'
      }
      
      <!-- AndroidManifest.xml -->
      <uses-permission android:name="android.permission.USB_PERMISSION"/>
      <uses-permission android:name="android.permission.USB_HOST"/>
      
      <!-- for automatically opening the app when the device is connected -->
      <!-- inside <activity> -->
      <intent-filter>
          <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
      </intent-filter>
      <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter"/>
      
      <!-- android/res/xml/device_filter.xml -->
      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <usb-device vendor-id="YOUR_VID" product-id="YOUR_PID" />
           <!--  if you have multiple devices -->
          <usb-device vendor-id="YOUR_VID" product-id="YOUR_PID_SECOND_DEVICE" />
      </resources>
      
      
      1 Reply Last reply
      3
      • C chaz
        28 Nov 2023, 14:22

        Hi,
        I am porting a Qt application to Android. A major feature of the application relies on using the QSerialPort module, which is not officially supported by Qt Android and it only works on rooted devices which is not a solution for me. Is there a way to port my application without having to make large changes to my code (like switching to BT instead of QSerialPort)?

        I have seen a patch mentioned before, I think it is this one, https://codereview.qt-project.org/c/qt/qtserialport/+/84338/2 . Is this still the way to make QSerialPort work in Qt 5.15.15 or is there another way?

        Kind Regards
        Chaz.

        J Offline
        J Offline
        J.Hilk
        Moderators
        wrote on 28 Nov 2023, 14:25 last edited by
        #2

        @chaz AFAIK your device would still have to be rooted to use any SerialPort library and you said:

        @chaz said in Using serial port on android:

        it only works on rooted devices which is not a solution for me


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        1 Reply Last reply
        0
        • C chaz
          28 Nov 2023, 14:22

          Hi,
          I am porting a Qt application to Android. A major feature of the application relies on using the QSerialPort module, which is not officially supported by Qt Android and it only works on rooted devices which is not a solution for me. Is there a way to port my application without having to make large changes to my code (like switching to BT instead of QSerialPort)?

          I have seen a patch mentioned before, I think it is this one, https://codereview.qt-project.org/c/qt/qtserialport/+/84338/2 . Is this still the way to make QSerialPort work in Qt 5.15.15 or is there another way?

          Kind Regards
          Chaz.

          L Offline
          L Offline
          lemons
          wrote on 29 Nov 2023, 10:51 last edited by lemons
          #3

          I had the same issue for an FTDI usb device and ended up re-writing the interface with JNI.

          For the android part I used this package:
          https://github.com/mik3y/usb-serial-for-android/

          For this package I had to switch to OpenJDK 18, in order to use the required gradle version.

          As the JNI part is static, I used the singleton pattern to build an asynchronous interface.

          Depending on your current implementation / usage of QSerialPort, you might be able to simply swap out the QSerialPort for a JNI wrapper class on Android.

          In total this looks something like this:

          • mydevice.h
          • mydevice.cpp
          • android/src/com/mycompany/mydevice/SerialHelper.java
          • changes in AndroidManifest.xml
          • changes in build.gradle

          In the following some snippets. I tried to reduce the snippets but to still cover the JNI parts.

          // mydevice.h
          // JNI methods
          public:
              static void JNICALL javaResponseReady(JNIEnv *env, jobject obj, jbyteArray byteArray);
              static void JNICALL javaConnectedStateChanged(JNIEnv *env, jobject obj, jboolean state);
              static void JNICALL javaErrorOccured(JNIEnv *env, jobject obj, jstring error);
              static void JNICALL javaMyDeviceAttached(JNIEnv *env, jobject obj, jboolean state);
          	
          private:
              void qtResponseReady(QByteArray qByteArray);
              void qtConnectedStateChanged(bool state);
              void qtErrorOccurred(QString errorMessage);
          
          // mydevice.cpp
          void MyDevice::connectDevice()
          {
              QAndroidJniObject activity = QtAndroid::androidActivity();
              QAndroidJniObject context = QtAndroid::androidContext();
          
              if (activity.isValid() && context.isValid()) {
                  QAndroidJniObject::callStaticMethod<void>(
                      "com/mycompany/mydevice/SerialHelper",
                      "connectToDevice",
                      "(Landroid/content/Context;II)V",
                      context.object(),
                      MY_DEVICE_VID,
                      MY_DEVICE_PID
                  );
              }
          }
          void MyDevice::sendCommand(QByteArray command)
          {
              if (command.isEmpty())
                  return;
          
              activeCommand.clear();
              activeCommand = command;
          
              QAndroidJniObject javaCommand = QAndroidJniObject::fromString(QString(command));
              QAndroidJniObject::callStaticMethod<void>(
                  "com/mycompany/mydevice/SerialHelper",
                  "sendCommand",
                  "(Ljava/lang/String;)V",
                  javaCommand.object<jstring>()
              );
          }
          
          void MyDevice::javaResponseReady(JNIEnv *env, jobject obj, jbyteArray byteArray)
          {
              jbyte *elems = env->GetByteArrayElements(byteArray, 0);
              jsize len = env->GetArrayLength(byteArray);
              QByteArray qByteArray(reinterpret_cast<char*>(elems), len);
              env->ReleaseByteArrayElements(byteArray, elems, 0);
          
              MyDevice &instance = MyDevice::getInstance();
              instance.qtResponseReady(qByteArray);
          }
          
          void MyDevice::javaConnectedStateChanged(JNIEnv *env, jobject obj, jboolean state)
          {
              MyDevice &instance = MyDevice::getInstance();
              instance.qtConnectedStateChanged((bool) state);
          }
          
          void MyDevice::javaErrorOccured(JNIEnv *env, jobject obj, jstring error)
          {
              const char* utfStr = env->GetStringUTFChars(error, 0);
              QString qStr = QString::fromUtf8(utfStr);
              env->ReleaseStringUTFChars(error, utfStr);
          
              MyDevice &instance = MyDevice::getInstance();
              instance.qtErrorOccurred(qStr);
          }
          
          void MyDevice::javaMyDeviceAttached(JNIEnv *env, jobject obj, jboolean state)
          {
              MyDevice &instance = MyDevice::getInstance();
              if(state){
                  instance.connectDevice();
              } else {
                  instance.disconnectDevice();
              }
          }
          
          JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
          {
              JNIEnv* env;
              if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
                  return -1;
              }
          
              JNINativeMethod methods[] {
                  {"javaResponseReady", "([B)V", reinterpret_cast<void*>(MyDevice::javaResponseReady)},
                  {"javaConnectedStateChanged", "(Z)V", reinterpret_cast<void*>(MyDevice::javaConnectedStateChanged)},
                  {"javaErrorOccured", "(Ljava/lang/String;)V", reinterpret_cast<void*>(MyDevice::javaErrorOccured)},
                  {"javaMyDeviceAttached", "(Z)V", reinterpret_cast<void*>(MyDevice::javaMyDeviceAttached)}
              };
          
              jclass clazz = env->FindClass("com/mycompany/mydevice/SerialHelper");
              if (!clazz) {
                  return -1;
              }
          
              if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(JNINativeMethod)) < 0) {
                  return -1;
              }
          
              return JNI_VERSION_1_6;
          }
          
          // SerialHelper.java
          package com.mycompany.mydevice;
          
          import java.util.concurrent.ExecutorService;
          import java.util.concurrent.Executors;
          
          import android.app.PendingIntent;
          import android.content.BroadcastReceiver;
          import android.content.Context;
          import android.content.Intent;
          import android.content.IntentFilter;
          import android.hardware.usb.UsbDevice;
          import android.hardware.usb.UsbDeviceConnection;
          import android.hardware.usb.UsbManager;
          import android.util.Log;
          
          import com.hoho.android.usbserial.driver.FtdiSerialDriver;
          import com.hoho.android.usbserial.driver.UsbSerialPort;
          import com.hoho.android.usbserial.driver.UsbSerialDriver;
          import com.hoho.android.usbserial.driver.ProbeTable;
          import com.hoho.android.usbserial.driver.UsbSerialProber;
          import com.hoho.android.usbserial.util.HexDump;
          import com.hoho.android.usbserial.util.SerialInputOutputManager;
          
          import java.io.ByteArrayOutputStream;
          import java.io.IOException;
          import java.util.Arrays;
          import java.util.List;
          
          public class SerialHelper extends org.qtproject.qt5.android.bindings.QtActivity {
              private static ExecutorService executorService = Executors.newSingleThreadExecutor();
          
              private static final String ACTION_USB_PERMISSION = "com.mycompany.mydevice.USB_PERMISSION";
              private static UsbManager usbManager;
              private static UsbSerialPort serialPort;
          
              private static final int WRITE_WAIT_MILLIS = 2000;
              private static final int READ_WAIT_MILLIS = 2000;
          
              public static native void javaResponseReady(byte[] response);
              public static native void javaConnectedStateChanged(boolean state);
              public static native void javaErrorOccured(String error);
              public static native void javaMyDeviceAttached(boolean state);
          
          
              public static void closeDeviceConnection() {
                  executorService.submit(new Runnable() {
                      @Override
                      public void run() {
                          if (serialPort == null) {
                              javaErrorOccured("Serial port is not initialized. Nothing to close.");
                              return;
                          }
          
                          try {
                              serialPort.close();
                              serialPort = null;
                              javaConnectedStateChanged(false);
                              return;
                          } catch (IOException e) {
                              javaErrorOccured("CLOSE PORT EXCEPTION");
                              return;
                          }
                      }
                  });
              }
          
              public static void connectToDevice(Context context, int vid, int pid) {
                  executorService.submit(new Runnable() {
                      @Override
                      public void run() {
                          // Create custom prober for given VID and PID
                          ProbeTable customTable = new ProbeTable();
                          customTable.addProduct(vid, pid, FtdiSerialDriver.class);
                          UsbSerialProber prober = new UsbSerialProber(customTable);
          
                          // Find all available drivers from attached devices.
                          UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
                          List<UsbSerialDriver> drivers = prober.findAllDrivers(manager);
                          if (drivers.isEmpty()) {
                              javaErrorOccured("No Device found");
                              return;
                          }
          
                          // Open a connection to the first available driver.
                          UsbSerialDriver driver = drivers.get(0);
                          UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
                          if (connection == null) {
                              PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
                              manager.requestPermission(driver.getDevice(), permissionIntent);
                              javaErrorOccured("Permission request sent. Awaiting response...");
                              return;
                          }
                          UsbSerialPort port = driver.getPorts().get(0);
                          try {
                              port.open(connection);
                              try {
                                  port.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
                              } catch (UnsupportedOperationException e){
                                  javaErrorOccured("UNSUPPORTED OPERATION EXCEPTION");
                                  return;
                              }
                          } catch (Exception e) {
                              javaErrorOccured("OPEN PORT EXCEPTION");
                              return;
                          }
          
                          usbManager = manager;
                          serialPort = port;
                          javaConnectedStateChanged(true);
                      }
                  });
              }
          
          
              public static void sendCommand(String command) {
                  executorService.submit(new Runnable() {
                      @Override
                      public void run() {
                          if (serialPort == null) {
                              javaConnectedStateChanged(false);
                              javaErrorOccured("Serial port is not initialized. Call connectToDevice() first.");
                              return;
                          }
          
                          try {
                              serialPort.write(command.getBytes(), WRITE_WAIT_MILLIS);
                          } catch (Exception e) {
                              javaErrorOccured("WRITE EXCEPTION");
                              javaConnectedStateChanged(false);
                              return;
                          }
          
                          ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                          byte[] buffer = new byte[8192];
          
                          try {
          		    // Read until command terminator found
                              while (true) {
                                  int len = serialPort.read(buffer, READ_WAIT_MILLIS);
                                  if (len > 0) {
                                      outputStream.write(buffer, 0, len);
          
          		            
                                      boolean exit = false;
          
          		            // ADD EXIT CONDITION / response termination pattern (e.g. \r\n)
          		
                                      if(exit){
                                          byte[] originalArray = outputStream.toByteArray();
          				// -2 => terminator (e.g. \r\n) removed before sending to C++
                                          byte[] trimmedArray = Arrays.copyOf(originalArray, originalArray.length - 2);
          
                                          javaResponseReady(trimmedArray);
                                          return;
                                      }
                                  }
                              }
                          } catch (IOException e) {
                              javaErrorOccured("READ EXCEPTION");
                              javaConnectedStateChanged(false);
                              return;
                          }
                      }
                  });
              }
          
              private static final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
                  public void onReceive(Context context, Intent intent) {
                      String action = intent.getAction();
                      if (ACTION_USB_PERMISSION.equals(action)) {
                          synchronized (this) {
                              UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
          
                              if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                                  if (device != null) {
                                      javaMyDeviceAttached(true);
                                      int vid = device.getVendorId();
                                      int pid = device.getProductId();
                                      connectToDevice(context, vid, pid);
                                  }
                              }
                          }
                      }
                  }
              };
          }
          
          // build.gradle
          buildscript {
              repositories {
                  google()
                  mavenCentral()
                  maven { url 'https://jitpack.io' }
              }
          
              dependencies {
                  classpath 'com.android.tools.build:gradle:7.2.1'
              }
          }
          
          repositories {
              google()
              mavenCentral()
              maven { url 'https://jitpack.io' }
          }
          
          apply plugin: 'com.android.application'
          
          dependencies {
              implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
              implementation 'androidx.core:core:1.3.2'
              implementation 'androidx.legacy:legacy-support-v4:1.0.0'
              implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32"
              implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.72"
              implementation 'com.github.mik3y:usb-serial-for-android:v3.6.0'
          }
          
          <!-- AndroidManifest.xml -->
          <uses-permission android:name="android.permission.USB_PERMISSION"/>
          <uses-permission android:name="android.permission.USB_HOST"/>
          
          <!-- for automatically opening the app when the device is connected -->
          <!-- inside <activity> -->
          <intent-filter>
              <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
          </intent-filter>
          <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter"/>
          
          <!-- android/res/xml/device_filter.xml -->
          <?xml version="1.0" encoding="utf-8"?>
          <resources>
              <usb-device vendor-id="YOUR_VID" product-id="YOUR_PID" />
               <!--  if you have multiple devices -->
              <usb-device vendor-id="YOUR_VID" product-id="YOUR_PID_SECOND_DEVICE" />
          </resources>
          
          
          1 Reply Last reply
          3
          • C chaz has marked this topic as solved on 5 Dec 2023, 10:50

          1/3

          28 Nov 2023, 14:22

          • Login

          • Login or register to search.
          1 out of 3
          • First post
            1/3
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved