qt on android for PL2303HXD USB to RS232

android 系统下很多终端设备并不具备直接的串口通讯,通过use转RS232/485转换设备实现串口通讯,PL2303HXD USB to RS232(集成的RS232-USB接口转换器)可实现android的串口通信,但Qt的QSerialPort并不适用,可通过调用PL2303HXD提供的java库实现。

备注:关于qt on android及java交互知识请参考《Qt on Android核心编程》和“extendsQtWithJava” demo。

1)下载:http://www.prolific.com.tw,本文样例的下载版本“PL2303HXD_Android-SDK_v10015_20170512.zip“

2)解压后,在SampleCode给出了单个端口和多个端口的样例,由于本人项目需要,直接研究使用多端口的样例如何结合到QT中实现usb转串口的通讯。

3)建立一个qt工程,在工程文件中添加android的配置要求,以下是我项目(pro)的部分配置:

android-g++ {
 QT += androidextras
    LIBS += -lgnustl_shared
    ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
    HEADERS += \
    javaSrc/qDebug2Logcat.h \
    javaSrc/simpleCustomEvent.h \
    javaSrc/javanative.h \
    
    SOURCES += \
    javaSrc/javanative.cpp \
    javaSrc/qDebug2Logcat.cpp \
    javaSrc/simpleCustomEvent.cpp \
    DISTFILES += \
   #android的xml配置   
   android/AndroidManifest.xml \ 
   #来自SampleCode/Multi port示例的libs   
   android/libs/android-support-v4.jar \
   #来自SampleCode/Multi port示例的libs
   android/libs/pl2303multilib.jar \ 
   android/res/xml/device_filter.xml \
   #java到qt的交互函数定义,qt中实现
   android/src/an/qt5/javagather/PL2303HXDNative.java \ 
   #多端口串口通信
   android/src/an/qt5/javagather/PL2303HXDSerialPort.java \
   #开机自启动需要 
   android/src/an/qt5/javagather/GatherBootUpReceiver.java \
   #串口采集参配及规约解析脚本
   android/assets/modbus.js \
   android/assets/tcp.js \
   android/assets/tcpPlay.js \
   android/assets/gather.xml \
   android/assets/gmap.xml
}
4)(PL2303HXDSerialPort.java)PL2303HXD的串口采集的java代码:

package an.qt5.javagather;
import java.io.IOException;
import tw.com.prolific.pl2303multilib.PL2303MultiLib;
import android.os.Bundle;
import android.os.Handler;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbManager;
import java.io.UnsupportedEncodingException;
//min and max
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import java.util.List;
import java.util.ArrayList;
class UARTSettingInfo {
        public int iPortIndex = 0;
        public PL2303MultiLib.BaudRate mBaudrate = PL2303MultiLib.BaudRate.B9600;
        public PL2303MultiLib.DataBits mDataBits = PL2303MultiLib.DataBits.D8;
        public PL2303MultiLib.Parity mParity = PL2303MultiLib.Parity.NONE;
        public PL2303MultiLib.StopBits mStopBits = PL2303MultiLib.StopBits.S1;
        public PL2303MultiLib.FlowControl mFlowControl = PL2303MultiLib.FlowControl.OFF;
}//class UARTSettingInfo
public class PL2303HXDSerialPort extends org.qtproject.qt5.android.bindings.QtActivity {
//public class PL2303HXDSerialPort extends Activity{
    private static PL2303MultiLib mSerialMulti;
    private static final int MAX_DEVICE_COUNT = 4;
    private static final String ACTION_USB_PERMISSION = "an.qt5.javagather.USB_PERMISSION";
    private static UARTSettingInfo gUARTInfoList[];
    private static boolean gThreadStop[] = new boolean[MAX_DEVICE_COUNT];
    private static boolean gRunningReadThread[] = new boolean[MAX_DEVICE_COUNT];
    private static boolean bDeviceOpened[] = new boolean[MAX_DEVICE_COUNT];
    private static final int ReadDataBufferSize = 256;
    private static boolean registerflag = false;
    private static final int DeviceIndex1 = 0;
    private static final int DeviceIndex2 = 1;
    private static final int DeviceIndex3 = 2;
    private static final int DeviceIndex4 = 3;
    private static final int readSleep = 100;
//    private static String TAG = "PL2303HXD_Gather_Log";
    private static PL2303HXDSerialPort m_instance;
    public PL2303HXDSerialPort(){
        m_instance = this;
    }
    //min
    public static void mini()
    {
        m_instance.moveTaskToBack(true);
    }
    //max
    public static void moveTaskToFrount(){
        if(!m_instance.isForeground(m_instance.getPackageName()))
        {
            ActivityManager am = (ActivityManager)m_instance.getSystemService(Context.ACTIVITY_SERVICE);
            am.moveTaskToFront(m_instance.getTaskId(),0);
        }
    }
    private boolean isForeground(String packageName){
        ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        if (appProcesses == null)
            return false;
        for (RunningAppProcessInfo appProcess : appProcesses) {
            // The name of the process that this object is associated with.
            if (appProcess.processName.equals(packageName)
                    && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return true;
            }
        }
        return false;
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        //super.onSaveInstanceState(outState);
    }
    private static int PLCInit(){
        PL2303HXDNative.OnNotify_LOG("pl2303 get service");
        try{
            // get service
            mSerialMulti = new PL2303MultiLib((UsbManager) m_instance.getSystemService(Context.USB_SERVICE),
                    m_instance, ACTION_USB_PERMISSION);
//            if you don't want to use Software Queue, below constructor to be used
//            mSerialMulti = new PL2303MultiLib((UsbManager) getSystemService(Context.USB_SERVICE),
//       	  	this, ACTION_USB_PERMISSION,false);
        }catch (Exception e) {
            e.printStackTrace();
            PL2303HXDNative.OnNotify_LOG("pl2303 get service Exception:"+e.toString());
            mSerialMulti = null;
            return 0;
        }
        try{
            gUARTInfoList = new UARTSettingInfo[MAX_DEVICE_COUNT];
            for(int i=0;i<MAX_DEVICE_COUNT;i++) {
                gUARTInfoList[i] = new UARTSettingInfo();
                gUARTInfoList[i].iPortIndex = i;
                gThreadStop[i] = false;
                gRunningReadThread[i] = false;
                bDeviceOpened[i] = false;
            }
        }catch (Exception e) {
            e.printStackTrace();
            PL2303HXDNative.OnNotify_LOG("pl2303 init UARTINfo Exception:"+e.toString());
            mSerialMulti = null;
            return 0;
        }
        m_instance.registerSerialMulti();
        PL2303HXDNative.OnNotify_LOG("Leave  PLCInit ");
        return 1;
    }
    private static int OpenUARTDevice(int index,int baudrate) {
        PL2303HXDNative.OnNotify_LOG("Enter OpenUARTDevice: "+String.valueOf(index));
        if(mSerialMulti==null) {
            if(0==PLCInit()){
                PL2303HXDNative.OnNotify_LOG("Error: mSerialMulti==null");
                return 2;
            }
        }
        if(!mSerialMulti.PL2303IsDeviceConnectedByIndex(index)) {
            PL2303HXDNative.OnNotify_LOG("Error: !AP_mSerialMulti.PL2303IsDeviceConnectedByIndex "+String.valueOf(index));
            return 3;
        }
        boolean res;
        UARTSettingInfo info = gUARTInfoList[index];
        switch(baudrate){
            case 1200:
            info.mBaudrate = PL2303MultiLib.BaudRate.B1200;
            break;
            case 2400:
            info.mBaudrate = PL2303MultiLib.BaudRate.B2400;
            break;
            case 4800:
            info.mBaudrate = PL2303MultiLib.BaudRate.B4800;
            break;
            case 9600:
            info.mBaudrate = PL2303MultiLib.BaudRate.B9600;
            break;
            case 19200:
            info.mBaudrate = PL2303MultiLib.BaudRate.B19200;
            break;
            case 38400:
            info.mBaudrate = PL2303MultiLib.BaudRate.B38400;
            break;
            case 57600:
            info.mBaudrate = PL2303MultiLib.BaudRate.B57600;
            break;
            case 115200:
            info.mBaudrate = PL2303MultiLib.BaudRate.B115200;
            break;
            default:
            PL2303HXDNative.OnNotify_LOG("Error: baudrate is not standard ,fail to PL2303OpenDevByUARTSetting");
            return 5;
        }
        PL2303HXDNative.OnNotify_LOG("UARTSettingInfo: index:"+String.valueOf(info.iPortIndex));
        res = mSerialMulti.PL2303OpenDevByUARTSetting(index, info.mBaudrate, info.mDataBits, info.mStopBits,
            info.mParity, info.mFlowControl);
        if( !res ) {
            PL2303HXDNative.OnNotify_LOG("Error: fail to PL2303OpenDevByUARTSetting");
            return 4;
        }
        bDeviceOpened[index] = true;
        if(!gRunningReadThread[index]) {
            UpdateDisplay(index);
        }
        PL2303HXDNative.OnNotify_LOG("Open ["+ mSerialMulti.PL2303getDevicePathByIndex(index) +"] successfully!");
        return 1;
    }//private void OpenUARTDevice(int index)
    private static void UpdateDisplay(int index) {
        gThreadStop[index] = false;
        gRunningReadThread[index] = true;
        if( DeviceIndex1==index ) {
            new Thread(ReadLoop1).start();
        } else if( DeviceIndex2==index ) {
            new Thread(ReadLoop2).start();
        } else if( DeviceIndex3==index ) {
            new Thread(ReadLoop3).start();
        }else if( DeviceIndex4==index ){
            new Thread(ReadLoop4).start();
        }else{
            PL2303HXDNative.OnNotify_LOG("closeUARTDevicel:"+String.valueOf(index));
        }
    }
    public static void closeUARTDevicel(int index){
        PL2303HXDNative.OnNotify_LOG("index is out [0,3]");
        if(null!=mSerialMulti){
            gThreadStop[index] = true;
        }
    }
    /**
    * 十六进制串转化为byte数组
    *
    * @return the array of byte
    */
    public static final byte[] hex2byte(String hex)
        throws IllegalArgumentException {
        if (hex.length() % 2 != 0) {
            throw new IllegalArgumentException();
        }
        char[] arr = hex.toCharArray();
        byte[] b = new byte[hex.length() / 2];
        for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
            String swap = "" + arr[i++] + arr[i];
            int byteint = Integer.parseInt(swap, 16) & 0xFF;
            b[j] = new Integer(byteint).byteValue();
        }
        return b;
    }
    /**
    * 字节数组转换为十六进制字符串
    *
    * @param b
    *            byte[] 需要转换的字节数组
    * @return String 十六进制字符串
    */
    public static final String byte2hex(byte b[],int realLength) {
        if (b == null) {
            throw new IllegalArgumentException(
                "Argument b ( byte array ) is null! ");
        }
        String stmp = "";
        StringBuilder sbHex=new StringBuilder();
        for (int n = 0; n < realLength; n++) {
            stmp = Integer.toHexString(b[n] & 0x000000FF);
            if (stmp.length() == 1) {
                sbHex.append("0");
                sbHex.append(stmp);
            } else if(stmp.length() == 2) {
                sbHex.append(stmp);
            }else{
                PL2303HXDNative.OnNotify_LOG("byte2hex : " + stmp.length());
            }
        }
        return sbHex.toString().toUpperCase();
    }
    private static void WriteToUARTDevice(int index,String strWrite) {
        PL2303HXDNative.OnNotify_LOG(String.valueOf(index)+" Enter WriteToUARTDevice");
        if(mSerialMulti==null)
        {
            PL2303HXDNative.OnNotify_LOG(String.valueOf(index)+" WriteToUARTDevice fail,mSerialMulti=null");
            return;
        }
        if(!mSerialMulti.PL2303IsDeviceConnectedByIndex(index)){
            PL2303HXDNative.OnNotify_LOG(String.valueOf(index)+" WriteToUARTDevice fail,mSerialMulti is unconect");
            return;
        }
        if( strWrite==null || "".equals(strWrite.trim()) ) { //str is empty
            PL2303HXDNative.OnNotify_LOG(String.valueOf(index)+" WriteToUARTDevice: no data to write");
            return;
        }
        PL2303HXDNative.OnNotify_LOG(String.valueOf(index)+" PL2303Multi Write(" + strWrite.length() + "):" + strWrite);
        int res = 0;
        try{
            res = mSerialMulti.PL2303Write(index, hex2byte(strWrite.trim()));
        }catch(Exception e){
            PL2303HXDNative.OnNotify_LOG("UnsupportedEncodingException");
        }
        if( res<0 ) {
            PL2303HXDNative.OnNotify_LOG(index+"w: fail to write: "+ res);
            return;
        }
        PL2303HXDNative.OnNotify_LOG(String.valueOf(index)+" Leave WriteToUARTDevice");
    } //private void WriteToUARTDevice(int index)
    @Override
    protected void onStart() {
        super.onStart();
        registerSerialMulti();
    }
    @Override
    protected void onRestart() {
        super.onRestart();
    }
    @Override
    protected void onResume() {
        super.onResume();
        registerSerialMulti();
    }//public void onResume()
    @Override
    protected void onPause() {
        super.onStart();
        registerSerialMulti();
    }
    @Override
    protected void onStop() {
        super.onStop();
        registerSerialMulti();
    }
    @Override
    protected void onDestroy() {
        unRegisterSerialMulti();
        super.onDestroy();
    }
    private void registerSerialMulti(){
        if(registerflag)
            return;
        if(mSerialMulti!=null) {
            int iDeviceCount = mSerialMulti.PL2303Enumerate();
            PL2303HXDNative.OnNotify_LOG("onResume for mSerialMulti iDeviceCount="+String.valueOf(iDeviceCount));
            if(0!=iDeviceCount){
                //register receiver for PL2303Multi_USB notification
                IntentFilter filter = new IntentFilter();
                filter.addAction(mSerialMulti.PLUART_MESSAGE);
                registerReceiver(PLMultiLibReceiver, filter);
                registerflag = true;
            }
        }
    }
    private void unRegisterSerialMulti(){
        if(mSerialMulti!=null) {
            for(int i=0;i<MAX_DEVICE_COUNT;i++) {
                gThreadStop[i] = true;
            }//First to stop app view-thread
            if(mSerialMulti.PL2303Enumerate()>0){
                unregisterReceiver(PLMultiLibReceiver);
                registerflag = false;
            }
            mSerialMulti.PL2303Release();
            mSerialMulti = null;
        }
    }
    private final BroadcastReceiver PLMultiLibReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals(mSerialMulti.PLUART_MESSAGE)){
               Bundle extras = intent.getExtras();
               if(extras!=null) {
                   String str = (String)extras.get(mSerialMulti.PLUART_DETACHED);
//                   DumpMsg("receive data:"+str);
                   int index = Integer.valueOf(str);
                   if(DeviceIndex1==index) {
                        bDeviceOpened[DeviceIndex1] = false;
                   } else if(DeviceIndex2==index) {
                        bDeviceOpened[DeviceIndex2] = false;
                   } else if(DeviceIndex3==index) {
                        bDeviceOpened[DeviceIndex3] = false;
                   }else if(DeviceIndex4==index){
                        bDeviceOpened[DeviceIndex4] = false;
                   }else{
                   }
                }
            }
        }//onReceive
    };
private static void DelayTime(int dwTimeMS) {
    //Thread.yield();
    long StartTime, CheckTime;
    if(0==dwTimeMS) {
        Thread.yield();
        return;
    }
    //Returns milliseconds running in the current thread
    StartTime = System.currentTimeMillis();
    do {
        CheckTime=System.currentTimeMillis();
        Thread.yield();
     } while( (CheckTime-StartTime)<=dwTimeMS);
}
private static int ReadLen1;
private static byte[] ReadBuf1 = new byte[ReadDataBufferSize];
private static Handler mHandler1 = new Handler();
private static Runnable ReadLoop1 = new Runnable() {
    public void run() {
        for (;;) {
            ReadLen1 = mSerialMulti.PL2303Read(DeviceIndex1, ReadBuf1);
            if (ReadLen1 > 0) {
                //ReadBuf1[ReadLen1] = 0;
                PL2303HXDNative.OnNotify_LOG("Read 1 Length : " + ReadLen1);
                mHandler1.post(new Runnable() {
                    public void run() {
                        String readBuf = byte2hex(ReadBuf1,ReadLen1);
                        PL2303HXDNative.OnNotify_MSG(DeviceIndex1,readBuf);
                    }//run
                });//Handler.post
            }//if (len > 0)
//            PL2303HXDNative.OnNotify_LOG("Read Index(1) readSleep: "+readSleep);
            DelayTime(readSleep);
            if (gThreadStop[DeviceIndex1]) {
                gRunningReadThread[DeviceIndex1] = false;
                return;
            }//if
        }//for(...)
    }//run
};//Runnable
private static int ReadLen2;
private static byte[] ReadBuf2 = new byte[ReadDataBufferSize];
private static Handler mHandler2 = new Handler();
private static Runnable ReadLoop2 = new Runnable() {
    public void run() {
        for (;;) {
            ReadLen2 = mSerialMulti.PL2303Read(DeviceIndex2, ReadBuf2);
            if (ReadLen2 > 0) {
                //ReadBuf2[ReadLen2] = 0;
                PL2303HXDNative.OnNotify_LOG("Read 2 Length : " + ReadLen2);
                mHandler2.post(new Runnable() {
                    public void run() {
                        String readBuf = byte2hex(ReadBuf2,ReadLen2);
                        PL2303HXDNative.OnNotify_MSG(DeviceIndex1,readBuf);
                    }//run
                });//Handler.post
            }//if (len > 0)
            DelayTime(readSleep);
            if (gThreadStop[DeviceIndex2]) {
                gRunningReadThread[DeviceIndex2] = false;
                return;
            }//if
        }//for(...)
    }//run
};//Runnable
private static int ReadLen3;
private static byte[] ReadBuf3 = new byte[ReadDataBufferSize];
private static Handler mHandler3 = new Handler();
private static Runnable ReadLoop3 = new Runnable() {
    public void run() {
        for (;;) {
            ReadLen3 = mSerialMulti.PL2303Read(DeviceIndex3, ReadBuf3);
            if (ReadLen3 > 0) {
                //ReadBuf3[ReadLen3] = 0;
                PL2303HXDNative.OnNotify_LOG("Read 3 Length : " + ReadLen3);
//                    String readBuf = byte2hex(ReadBuf3,ReadLen3);
//                    PL2303HXDNative.OnNotify_MSG(1,readBuf);
                mHandler3.post(new Runnable() {
                    public void run() {
                        String readBuf = byte2hex(ReadBuf3,ReadLen3);
                        PL2303HXDNative.OnNotify_MSG(DeviceIndex1,readBuf);
                    }//run
                });//Handler.post
            }//if (len > 0)
            DelayTime(readSleep);
            if (gThreadStop[DeviceIndex3]) {
                gRunningReadThread[DeviceIndex3] = false;
                return;
            }//if
        }//for(...)
    }//run
};//Runnable
private static int ReadLen4;
private static byte[] ReadBuf4 = new byte[ReadDataBufferSize];
private static Handler mHandler4 = new Handler();
private static Runnable ReadLoop4 = new Runnable() {
    public void run() {
        for (;;) {
            ReadLen4 = mSerialMulti.PL2303Read(DeviceIndex4, ReadBuf4);
            if (ReadLen4 > 0) {
                //ReadBuf4[ReadLen4] = 0;
                PL2303HXDNative.OnNotify_LOG("Read 4 Length : " + ReadLen4);
                mHandler4.post(new Runnable() {
                    public void run() {
                        String readBuf = byte2hex(ReadBuf4,ReadLen4);
                        PL2303HXDNative.OnNotify_MSG(DeviceIndex1,readBuf);
                    }//run
                });//Handler.post
            }//if (len > 0)
            DelayTime(readSleep);
            if (gThreadStop[DeviceIndex4]) {
                gRunningReadThread[DeviceIndex4] = false;
                return;
            }//if
        }//for(...)
    }//run
};//Runnable
}
5)(PL2303HXDNative.java)定义java到Qt的调用函数:

package an.qt5.javagather;
import java.lang.String;

public class PL2303HXDNative
{
    public static native void OnNotify_MSG(int index,String msg);
    public static native void OnNotify_LOG(String log);
}
6)(javanative.h/cpp)在QT中实现java到Qt的调用函数及注册函数:

#ifndef JAVANATIVE_H
#define JAVANATIVE_H

bool registerNativeMethods();

#endif // JAVANATIVE_H

#include "javanative.h"
#include "simpleCustomEvent.h"

#include <QApplication>
#include <QDebug>

#ifdef ANDROID
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>
#include <jni.h>
#endif

namespace GVAL_Gather {
    extern QObject *g_listener;
}

static void OnNotify_MSG(JNIEnv *env, jobject /*thiz*/,int index,jstring msg)
{
    try{
        QString qmsg;
        const char *nativeString = env->GetStringUTFChars(msg, 0);
        qmsg = QString("%1").arg(nativeString);
        env->ReleaseStringUTFChars(msg, nativeString);
        qDebug() << "msg=" << qmsg;
        QCoreApplication::postEvent(GVAL_Gather::g_listener, new SimpleCustomEvent(1, qmsg,index));
    }catch(...){
        qDebug() << "OnNotify_MSG Exception";
    }
}

static void OnNotify_LOG(JNIEnv *env, jobject /*thiz*/,jstring log)
{
    try{
        QString qlog;
        const char *nativeString = env->GetStringUTFChars(log, 0);
        qlog = nativeString;
        env->ReleaseStringUTFChars(log, nativeString);
        qDebug() << "log=" << qlog;
        QCoreApplication::postEvent(GVAL_Gather::g_listener, new SimpleCustomEvent(2, qlog));
    }catch(...){
        qDebug() << "OnNotify_LOG Exception";
    }
}

bool registerNativeMethods()
{
    try{
        JNINativeMethod methods[] {
            {"OnNotify_MSG", "(ILjava/lang/String;)V", (void*)OnNotify_MSG},
            {"OnNotify_LOG", "(Ljava/lang/String;)V", (void*)OnNotify_LOG}
        };

        const char *classname = "an/qt5/javagather/PL2303HXDNative";
        jclass clazz;
        QAndroidJniEnvironment env;

        QAndroidJniObject javaClass(classname);
        clazz = env->GetObjectClass(javaClass.object<jobject>());
        qDebug() << "find PL2303HXDNative - " << clazz;
        bool result = false;
        if(clazz)
        {
            jint ret = env->RegisterNatives(clazz,
                                            methods,
                                            sizeof(methods) / sizeof(methods[0]));
            env->DeleteLocalRef(clazz);
            qDebug() << "RegisterNatives return - " << ret;
            result = ret >= 0;
        }
        if(env->ExceptionCheck())
            env->ExceptionClear();
        return result;
    }catch(...){
        qDebug() << "registerNativeMethods Exception";
        return false;
    }
}
7)(simpleCustomEvent.h/cpp)java交互的QEvent事件

#ifndef SIMPLECUSTOMEVENT_H
#define SIMPLECUSTOMEVENT_H
#include <QEvent>
#include <QString>

class SimpleCustomEvent : public QEvent
{
public:
    SimpleCustomEvent(int arg1 = 0, const QString &arg2 = QString(),int arg3 = 0);
    ~SimpleCustomEvent();

    static Type eventType();

    int m_arg1;
    QString m_arg2;
    int m_arg3;
private:
    static Type m_evType;
};

#endif // SIMPLECUSTOMEVENT_H
#include "simpleCustomEvent.h"

QEvent::Type SimpleCustomEvent::m_evType = (QEvent::Type)QEvent::None;

SimpleCustomEvent::SimpleCustomEvent(int arg1, const QString &arg2, int arg3)
    : QEvent(eventType()), m_arg1(arg1), m_arg2(arg2), m_arg3(arg3)
{}

SimpleCustomEvent::~SimpleCustomEvent()
{

}

QEvent::Type SimpleCustomEvent::eventType()
{
    if(m_evType == QEvent::None)
    {
        m_evType = (QEvent::Type)registerEventType();
    }
    return m_evType;
}
8)通过QEvent事件实现及注册绑定

bool GatherMgr::event(QEvent *et)
{
#ifdef ANDROID
    if(et->type() == SimpleCustomEvent::eventType())
    {
        SimpleCustomEvent *sce = (SimpleCustomEvent*)et;
        if(sce->m_arg1 == 1)//msg
        {
            displayMsg(QString("port[%1] ReadData(%2):%3")
                       .arg(sce->m_arg3).arg(sce->m_arg2.length()).arg(sce->m_arg2));
            emit notify_MsgAndroid(sce->m_arg2,sce->m_arg3);
        }
        else if(sce->m_arg1 == 2)//log
        {
            displayMsg(sce->m_arg2);
        }
        else
        {
            displayMsg("unkown_info");
        }
        return true;
    }
#endif
    return QWidget::event(et);
}
#ifdef ANDROID
    SimpleCustomEvent::eventType();
    registerNativeMethods();
#endif
    GatherMgr gatherMgr;
#ifdef ANDROID
    GVAL_Gather::g_listener = qobject_cast<QObject*>(&gatherMgr);
#endif
9)Qt到java函数的调用实现,项目涉及的业务、通信解析、跨平台相关的处理就不展示了:

#ifdef ANDROID
#include <QtAndroidExtras/QAndroidJniObject>
#include <QAndroidJniEnvironment>
#include<unistd.h>
#endif
void SerialPort::openSerialPort()
{
#ifndef ANDROID
...
#else
    jint javaIndex = serialconfig.name.toInt();
    jint javaBaudRate = (int)serialconfig.baudRate;
    jint ret = QAndroidJniObject::callStaticMethod<jint>("an/qt5/javagather/PL2303HXDSerialPort",
                                            "OpenUARTDevice",
                                            "(II)I",
                                            javaIndex,
                                            javaBaudRate);
    QAndroidJniEnvironment env;
    if(env->ExceptionCheck()){
        qDebug()<<"openSerialPort Exception!";
        ret = 3;
        env->ExceptionClear();
    }
    if(1!=ret){
        qDebug() << (QObject::tr("Open error,ret(%1),Index(%2)").arg(ret).arg(serialconfig.name));
        serialState = false;
    }else{
        serialState = true;
    }
#endif
}

void SerialPort::closeSerialPort()
{
#ifndef ANDROID
...
#else
    if(serialState){
        jint javaIndex = serialconfig.name.toInt();
        QAndroidJniObject::callStaticMethod<void>("an/qt5/javagather/PL2303HXDSerialPort",
                                                  "closeUARTDevicel"
                                                  ,"(I)V"
                                                  ,javaIndex);
        serialState = false;
        QAndroidJniEnvironment env;
        if(env->ExceptionCheck()){
            qDebug()<<"closeSerialPort Exception!";
            env->ExceptionClear();
        }
    }
#endif
}

void SerialPort::sendMsg(QString cmd,bool u16f)
{
//    qDebug() << "cmd="<<cmd;
//    emit logNotify("16bit="+cmd);
    try{
#ifndef ANDROID
...
#else
//    qDebug() << QString("get cmd! cmd.size=%1").arg(cmd.size());
    if(!serialState)
    {
        openSerialPort();
        if (!serialState){
            qDebug() << "send cmd fail,serial isn't open!";
            m_PortState.m_bExit=true;
            return;
        }
    }
    if(serialState){
        m_PortState.m_bExit=false;
//        qDebug() << QString("send cmd for serial write! cmd.size=%1").arg(cmd.size());
        emit logNotify(QString("gather(%1) send cmd for serial write! cmd.size=%2,cmd=%3")
                       .arg(gatherID).arg(cmd.size()).arg(cmd));
        jint javaIndex = serialconfig.name.toInt();
        QAndroidJniObject javaMsg = QAndroidJniObject::fromString(cmd);
        QAndroidJniObject::callStaticMethod<void>("an/qt5/javagather/PL2303HXDSerialPort",
                                                  "WriteToUARTDevice"
                                                  ,"(ILjava/lang/String;)V"
                                                  ,javaIndex
                                                  , javaMsg.object<jstring>());
        QAndroidJniEnvironment env;
        if(env->ExceptionCheck()){
            qDebug()<<"SerialPort writeData Exception!";
            env->ExceptionClear();
            m_PortState.m_wf=false;
        }else{
            oldDownCmd = cmd;
            m_PortState.m_wf=true;
        }
    }
#endif
    }catch(...){
        qDebug()<<QString("SerialPort::sendMsg(%1,%2) Exception!").arg(cmd).arg(u16f);
    }
}
10)程序的开机自启动及通知相关:

package an.qt5.javagather;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class GatherBootUpReceiver extends BroadcastReceiver
{
    // 系统启动完成
    static final String ACTION = "android.intent.action.BOOT_COMPLETED";
    @Override
    public void onReceive(Context context, Intent intent)
    {
        // 当收听到的事件是“BOOT_COMPLETED”时,就创建并启动相应的Activity和Service
        if (intent.getAction().equals(ACTION)) {
            // 开机启动的Activity
            Intent boot = new Intent(context, PL2303HXDSerialPort.class);
            boot.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(boot);
        }
    }

}
 </activity>
    <receiver android:enabled="true" android:name="an.qt5.javagather.GatherBootUpReceiver"        android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </receiver>
    <!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
</application>
11)android的usb授权:

<application>
   <activity>
     <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
          <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" />
  </activity>
</application>
<uses-feature android:name="android.hardware.usb.host"/>

关于PL2303 usb 的串口通讯,实际项目使用中根据实际需要需要进行通讯报文采集等待、报文分帧等细节处理,本文项目使用主要参考了PL2303的demo和《Qt on Android核心编程》的extendsQtWithJava样例迎合自身项目要求进行实现,在项目测试中表现得稳定性、通讯效率与QSerialPort的串口通讯并无多大差别(更严格的压力测试没深化)。



上一篇:Qt Style Sheets(qt样式表)


下一篇:Cross Entropy Loss 交叉熵损失函数公式推导