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
Qt 6.11 is out! See what's new in the release blog

Using serial port on android

Scheduled Pinned Locked Moved Solved Mobile and Embedded
3 Posts 3 Posters 8.3k 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 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.HilkJ L 2 Replies Last reply
    0
    • C chaz

      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 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

        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.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on 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

          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 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

          • Login

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