• QT 绿米QTA协议 (二)AS


     几圈年轮    Android 串口通信(一)  giuhub demo 地址 https://github.com/MickJson/AndroidUSBSerialPort

    一.PowerUpdate

    1.1.UI

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="7"
            android:gravity="center"
            android:orientation="horizontal">
    
            <ScrollView
                android:id="@+id/sv_send"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="5"
                android:background="@drawable/bg_white_stroke">
    
                <TextView
                    android:id="@+id/tv_send"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="@string/receive_hint"
                    android:padding="@dimen/margin_small"
                    android:textColor="@android:color/black"
                    android:textSize="@dimen/text_tv" />
            </ScrollView>
    
            <ScrollView
                android:id="@+id/sv_result"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="5"
                android:background="@drawable/bg_white_stroke">
    
                <TextView
                    android:id="@+id/tv_result"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="@string/receive_hint"
                    android:padding="@dimen/margin_small"
                    android:textColor="@android:color/black"
                    android:textSize="@dimen/text_tv" />
            </ScrollView>
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.5"
            android:gravity="center"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/btn_start"
                style="@style/average_vertical_widget"
                android:text="@string/start_test" />
    
            <Button
                android:id="@+id/btn_close"
                style="@style/average_vertical_widget"
                android:text="@string/close_port" />
    
        </LinearLayout>
    
    </LinearLayout>
    

     styles.xml

    <resources>
        <!--font Style-->
        <style name="average_vertical_widget">
            <item name="android:layout_width">0dp</item>
            <item name="android:layout_height">match_parent</item>
            <item name="android:layout_weight">1</item>
            <item name="android:gravity">center</item>
            <item name="android:textSize">@dimen/text_size</item>
            <item name="android:textColor">@android:color/black</item>
        </style>
    
    </resources>

    1.2.android_serialport_api 串口工具类

    package android_serialport_api;
    
    import android.util.Log;
    
    import java.io.File;
    import java.io.FileDescriptor;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    public class SerialPort {
    
        private static final String TAG = "SerialPort";
    
        /*
         * Do not remove or rename the field mFd: it is used by native method close();
         */
        private FileDescriptor mFd;
        private FileInputStream mFileInputStream;
        private FileOutputStream mFileOutputStream;
    
        public SerialPort(File device, int baudrate, int dataBits, int stopBits, char parity) throws SecurityException, IOException {
    
            /* Check access permission */
            if (!device.canRead() || !device.canWrite()) {
                try {
                    /* Missing read/write permission, trying to chmod the file */
                    Process su;
                    su = Runtime.getRuntime().exec("/system/bin/su");
                    String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
                            + "exit\n";
                    su.getOutputStream().write(cmd.getBytes());
                    if ((su.waitFor() != 0) || !device.canRead()
                            || !device.canWrite()) {
                        throw new SecurityException();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new SecurityException();
                }
            }
            mFd = open(device.getAbsolutePath(), baudrate, dataBits, stopBits, parity);
            if (mFd == null) {
                Log.e(TAG, "native open returns null");
                throw new IOException();
            }
            mFileInputStream = new FileInputStream(mFd);
            mFileOutputStream = new FileOutputStream(mFd);
        }
    
        // Getters and setters
        public InputStream getInputStream() {
            return mFileInputStream;
        }
    
        public OutputStream getOutputStream() {
            return mFileOutputStream;
        }
    
        public void Write_Rs485_Length(int count) {
            write_rs485_length(count);
        }
    
        // JNI(调用java本地接口,实现串口的打开和关闭)
        /**串口有五个重要的参数:串口设备名,波特率,检验位,数据位,停止位
         其中检验位一般默认位NONE,数据位一般默认为8,停止位默认为1*/
        /**
         * @param path     串口设备的据对路径
         * @param baudrate 波特率
         * @param dataBits 数据位
         * @param stopBits 停止位
         * @param parity   校验位
         */
        private native static FileDescriptor open(String path, int baudrate, int dataBits, int stopBits, char parity);
    
        public native void close();
    
        public native void write_rs485_length(int count);
    
        static {//加载jni下的C文件库
            Log.i(TAG, "loadLibrary..............gatsby");
            System.loadLibrary("serial_port");
        }
    }
    

     二.qtcreator  -> AS

    2.1.UartTest

    package com.lvmi.powerupdate;
    
    import android.content.Context;
    import android.os.Handler;
    import android.os.Looper;
    import android.util.Log;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    import android_serialport_api.SerialPort;
    
    public class UartTest {
    
        private final Context mContext;
        byte[] Save_Data;                // 保存的载入数据
        byte[] Temp_file_Data;           // 临时文件数据
        byte[] file_arry;                // 文件数据
        byte[] Send_Data;                // 发送数据
        byte Data_Number;                 // 数据编码
        int flag_EOT;                    // 结束命令标记
        int file_ChkData;                // 文件校验
        int NAck_Cnt;                    // NAck次数
        int Ack_Cnt;                     // Ack次数
        private OnSerialListener mOnSerialListener;
        public String DEV_TTYS4 = "/dev/ttyS4";
        private boolean isOpened = false;
        private OutputStream mOutputStream;
        private InputStream mInputStream;
        private final ExecutorService mThreadPoolExecutor = Executors.newCachedThreadPool();
    
        public UartTest(Context mContext) {
            super();
            this.mContext = mContext;
        }
    
        public void StartUartTest() {
            openSerialPort(DEV_TTYS4);
            Btn_Open_File();
            Btn_Sand_Data();//启动
        }
    
        //打开文件
        public void Btn_Open_File() {
            int val;
            file_arry = getBytesByFile(mContext, "QT573-LVMI-APP.bin");
    
            val = file_arry.length % 128;
            if (val != 0) {
                val = 128 - val;
                //最后一包数据补24个0
                byte[] chrVal2 = new byte[val];
                for (int i = 0; i < val; i++) {
                    chrVal2[i] = (byte)0;
                }
                file_arry = addBytes(file_arry, chrVal2);
                file_ChkData = Dev_CRC16(file_arry);
                //must F229
                Log.d("gatsby", "file_ChkData -> " + Integer.toHexString(file_ChkData));
    
            }
        }
    
        //启动
        public void Btn_Sand_Data() {
    
            // 清除 计数 接收文本 保存数据
            NAck_Cnt = 0;
            Ack_Cnt = 0;
            Save_Data = null;
    
            // 开始接收数据
            isOpened = true;
    
            // 开始发送进入编译环境
            Data_Number = 0;               // 重新发送计数
            flag_EOT = 0;                  // 发送结束标记位重置
            Sand_Data((byte) 0x93);        // 发送
        }
    
        //发送数据
        public void Sand_Data(byte cmd) {
            //StringBuilder ba = new StringBuilder();
            byte[] ba = new byte[133];
            int ChkData;//0xffff
            byte val;//0xff
            String sendData = null;
    
            if (cmd == 0x01) {
    
                byte[] data;
    
                ba[0] = cmd;
                Log.d("gatsby", "Data_Number ->" + Data_Number);
                val = (byte) ~Data_Number;
                ba[1] = (byte) Data_Number;
                ba[2] = (byte) val;
    
                for (int i = 0; i < Send_Data.length; i++) {
                    ba[i + 3] = (byte) Send_Data[i];
                }
    
                //System.arraycopy(Send_Data, 0, data, 0, Send_Data.length);
                data = Send_Data;
                Log.d("gatsby", "data->" + data.length);
    
                // 数据校验
                ChkData = CRC16(data, 128);
                Log.d("gatsby", "ChkData->" + ChkData);
    
                val = (byte) (ChkData & 0xff);
                ba[Send_Data.length + 3] = (byte) val;
    
                val = (byte) ((ChkData >> 8) & 0xff);
                ba[Send_Data.length + 4] = (byte) val;
    
                //打印看发送数据是否正确
    //            for (int i = 0; i < ba.length; i++) {
    //                Log.d("gatsby", "i--> " + (i) + " ba ->"+ Integer.toHexString(ba[i] & 0xff));
    //            }
                sendSerialPort(ba);
    
                if (flag_EOT == 0) {
                    Log.d("gatsby", "Sand Packet " + Data_Number);
                    sendData = "Send Packet " + Data_Number;
                }
                // 发送校验
                else if (flag_EOT == 1) {
                    Log.d("gatsby", "Sand Check");
                    sendData = "Send Check";
                }
    
                if (mOnSerialListener != null) {
                    mOnSerialListener.onSendData(sendData);
                }
            } else {
                byte[] ba2 = new byte[1];
                ba2[0] = (byte) cmd;
                sendSerialPort(ba2);
                Log.d("gatsby", "cmd ->" + Integer.toHexString(cmd & 0xff));
                if (cmd == (byte) 0x93) {
                    Log.d("gatsby", "Sand_Data will be send data ");
                } else if (cmd == (byte) 0x04) {
                    Log.d("gatsby", "Sand_Data End ");
                    isOpened = false;
                }
            }
        }
    
        public void openSerialPort(String devType) {
            if (!"".equals(devType) && new File(devType).exists()) {
                Log.d("gatsby", "isOpenedSerialPort");
                try {
                    //串口配置:9600 数据位8   起始位1  停止位1   奇校验
                    SerialPort mSerialPort = new SerialPort(new File(DEV_TTYS4), 9600, 8, 1, 'O');
                    mOutputStream = mSerialPort.getOutputStream();
                    mInputStream = mSerialPort.getInputStream();
                    mThreadPoolExecutor.execute(new ReceiveDataThread());
    
                    isOpened = true;
                } catch (IOException e) {
                    e.printStackTrace();
                    if (mOnSerialListener != null) {
                        mOnSerialListener.onSerialOpenException(e);
                    }
                }
            }
        }
    
        /**
         * 串口 发送字符串
         */
        public void Sand_Data_QString(String st) {
            st += "\r\n";
            byte[] ba = st.getBytes();
            sendSerialPort(ba);
        }
    
        /**
         * 串口 发送byte[]
         */
        public void sendSerialPort(byte[] sendbyte) {
            if (!isOpened) {
                return;
            }
            try {
                mOutputStream.write(sendbyte);
                mOutputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //5s 未接收数据 提示升级失败 Android11 提示过时 换Looper写法
        Handler handler = new Handler(Looper.myLooper());
        private final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if (Data_Number == 1) {
                    if (mOnSerialListener != null) {
                        mOnSerialListener.onUpdateError();
                    }
                }
            }
        };
    
        /**
         * 串口返回数据内容读取
         */
        private class ReceiveDataThread extends Thread {
            @Override
            public void run() {
                super.run();
                int val;//uint8_t
                String SendStr = null;
                String ReciveStr = null;
                boolean start_flag = false;
                byte[] ba = new byte[1024];
                while (isOpened) {
                    String resSaveData;
                    if (mInputStream != null) {
                        try {
                            int size = mInputStream.read(ba);
                            if (size > 0) {
                                resSaveData = new String(ba, 0, size);
                                Log.d("gatsby", "receiver str = " + resSaveData);
                                Save_Data = resSaveData.getBytes();
                                if (resSaveData.equals("Apply OTA\r\n")) {
                                    Log.d("gatsby", "Apply OTA");
                                    SendStr = "OTA";
                                    start_flag = true;
                                    ReciveStr = "Apply OTA";
                                    Sand_Data_QString(SendStr);
                                } else if (resSaveData.equals("Ready\r\n")) {
                                    Log.d("gatsby", "Ready");
                                    SendStr = "Start";
                                    ReciveStr = "Ready";
                                    Sand_Data_QString(SendStr);
                                    NAck_Cnt = 0;
                                    Ack_Cnt = 0;
                                    Data_Number = 0;        // 重新发送计数
                                    flag_EOT = 0;           // 发送结束标记位重置
                                    Temp_file_Data = file_arry;
                                }
                                // NACK
                                else if (Save_Data[0] == 0x15) {
                                    NAck_Cnt++;
                                    if (Data_Number == 0) {
                                        Data_Number = 1;
                                        // 首次发送
                                        Log.d("gatsby", "(NAck) Ready Receive");
                                        ReciveStr = "(NAck) Ready Receive";
                                        Send_Data = cutBytes(Temp_file_Data);
                                        Sand_Data((byte) 0x01);
                                    } else if (Data_Number > 0) {
                                        Log.d("gatsby", "(NAck) Ready Packet Error");
                                        ReciveStr = "(NAck) Ready Receive";
                                        Send_Data = cutBytes(Temp_file_Data);
                                        Sand_Data((byte) 0x01);
                                    }
                                    handler.postDelayed(runnable, 6000);
                                }
                                // ACK
                                else if (Save_Data[0] == 0x06) {
                                    Ack_Cnt++;
                                    Data_Number++;
                                    //Log.d("gatsby", "(Ack) Receive ->" + Save_Data[0]);
                                    //Log.d("gatsby", "flag_EOT->" + flag_EOT);
                                    Log.d("gatsby", "Temp_file_Data aaa->" + Temp_file_Data.length);
                                    if (Temp_file_Data.length > 128) {
    
                                        Temp_file_Data = removeBytes(Temp_file_Data, Temp_file_Data.length - 128);
                                        Log.d("gatsby", "Temp_file_Data bbb->" + Temp_file_Data.length);
                                        // 发送数据
                                        Send_Data = cutBytes(Temp_file_Data);
                                        if (Temp_file_Data.length == 128) {
                                            Temp_file_Data = removeBytes(Temp_file_Data, 0);
                                        }
                                        Sand_Data((byte) 0x01);
                                        Log.d("gatsby", "(Ack) Receive Packet " + (Data_Number - 1) + " Success");
                                        ReciveStr = "(Ack) Receive Packet " + (Data_Number - 1) + " Success";
                                    } else {
                                        // 发送校验
                                        if (flag_EOT == 0) {
                                            flag_EOT = 1;
                                            val = (byte) (file_ChkData & 0xff);
                                            Send_Data[0] = (byte) val;
                                            val = (byte) ((file_ChkData >> 8) & 0xff);
                                            Send_Data[1] = (byte) val;
                                            for (int i = 0; i < 126; i++) {
                                                Send_Data[i + 2] = (byte) 0;
                                            }
                                            Sand_Data((byte) 0x01);
                                            Log.d("gatsby", "EOT (Ack) Receive Packet " + (Data_Number - 1) + " Success");
                                            ReciveStr = "(Ack) Receive Packet " + (Data_Number - 1) + " Success";
                                        }
                                        // 发送EOT 完成
                                        else if (flag_EOT == 1) {
                                            flag_EOT = 2;
                                            Sand_Data((byte) 0x04);
                                            Log.d("gatsby", "(Ack) Receive Check");
                                            ReciveStr = "(Ack) Receive Check";
                                        }
                                    }
                                }
                                //设置监听
                                if (mOnSerialListener != null) {
                                    mOnSerialListener.onReceivedData(ReciveStr);
                                    if (start_flag) {
                                        mOnSerialListener.onSendData(SendStr);
                                        if (SendStr.equals("Start")) {
                                            start_flag = false;
                                        }
                                    }
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
        /**
         * 关闭串口
         */
        public void closeSerialPort() {
            try {
                if (mOutputStream != null)
                    mOutputStream.close();
                if (mInputStream != null)
                    mInputStream.close();
                isOpened = false;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 设置串口监听
         *
         * @param onSerialListener 串口监听
         */
        public void setOnSerialListener(OnSerialListener onSerialListener) {
            this.mOnSerialListener = onSerialListener;
        }
    
        /**
         * 串口监听
         */
        public interface OnSerialListener {
    
            /**
             * 串口打开异常
             */
            void onSerialOpenException(Exception e);
    
            /**
             * 串口数据发送
             */
            void onSendData(String sendData);
    
            /**
             * 串口数据返回
             */
            void onReceivedData(String receivedData);
    
    
            /**
             * 上位机下发后若5S未接收MCU数据 上位机退出升级过程
             */
            void onUpdateError();
    
        }
    
        /**
         * CRC校验 128字节
         */
        public int CRC16(byte[] u8pArray, int u8Size) {
            int val;//0xff
            int i, j;
            int CurVal;//0xffff
            int CrcReg = 0xFFFF;
    
            for (i = 0; i < u8Size; i++) {
                //CurVal = u8pArray[i] << 8;  uint8_t
                val = u8pArray[i] & 0xff;
                CurVal = val << 8;
    
                for (j = 0; j < 8; j++) {
                    if ((short) (CrcReg ^ CurVal) < 0) {
                        CrcReg = (((CrcReg << 1) & 0xffff) ^ 0x1021);
                    } else {
                        CrcReg = (CrcReg << 1) & 0xffff;
                    }
                    CurVal <<= 1;
                }
            }
            return CrcReg;
        }
    
        /**
         * CRC校验
         */
        public int Dev_CRC16(byte[] ba) {
            int val;//0xff
            int i, j;
            int CurVal;//0xffff
            int CrcReg = 0xFFFF;
    
            for (i = 0; i < ba.length; i++) {
                //uint8_t -> int
                val = ba[i] & 0xff;
                CurVal = val << 8;
    
                for (j = 0; j < 8; j++) {
                    if ((short) (CrcReg ^ CurVal) < 0) {
                        CrcReg = (((CrcReg << 1) & 0xffff) ^ 0x1021);
                        //Log.d("gatsby","file_arry i-> " + i + " CrcReg -> " + CrcReg);
                    } else {
                        CrcReg = (CrcReg << 1) & 0xffff;
                    }
                    CurVal <<= 1;
                }
            }
            return CrcReg;
        }
    
        /**
         * 两个字节数组合并
         */
        public byte[] addBytes(byte[] firstData, byte[] secondData) {
            byte[] mergeData = new byte[firstData.length + secondData.length];
            System.arraycopy(firstData, 0, mergeData, 0, firstData.length);
            System.arraycopy(secondData, 0, mergeData, firstData.length, secondData.length);
            return mergeData;
        }
    
        /**
         * 字节数组 截取首128字节 128
         */
        public byte[] cutBytes(byte[] Data) {
            byte[] cutData = new byte[128];
            System.arraycopy(Data, 0, cutData, 0, cutData.length);
            return cutData;
        }
    
        /**
         * 字节数组 移除首128字节 128
         */
        public byte[] removeBytes(byte[] Data, int removeLength) {
            byte[] removeData = new byte[removeLength];
            System.arraycopy(Data, 128, removeData, 0, removeData.length);
            return removeData;
        }
    
        /**
         * 获取assets文件流 转byte数组
         */
        public byte[] getBytesByFile(Context context, String fileName) {
            try {
                InputStream inStream = context.getResources().getAssets().open(fileName);
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len;
                while ((len = inStream.read(buffer)) != -1) {
                    outStream.write(buffer, 0, len);
                }
                outStream.close();
                inStream.close();
                return outStream.toByteArray();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
    }
    

     MainActivity  回调刷新UI 数据

    package com.lvmi.powerupdate;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ScrollView;
    import android.widget.TextView;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener, UartTest.OnSerialListener {
    
        private ScrollView  sv_send,sv_result;
        private Button btn_start, btn_close;
        private TextView tv_Send, tv_Result;
        private UartTest uartTest;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initData();
            initView();
        }
    
        private void initData() {
            if (uartTest == null) {
                uartTest = new UartTest(this);
                uartTest.setOnSerialListener(this);
            }
        }
    
        private void initView() {
            sv_send = (ScrollView) findViewById(R.id.sv_send);
            sv_result = (ScrollView) findViewById(R.id.sv_result);
            tv_Send = (TextView) findViewById(R.id.tv_send);
            tv_Result = (TextView) findViewById(R.id.tv_result);
            btn_start = (Button) findViewById(R.id.btn_start);
            btn_start.setOnClickListener(this);
            btn_close = (Button) findViewById(R.id.btn_close);
            btn_close.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btn_start:
                    tv_Send.setText("");
                    tv_Result.setText("");
                    btn_start.setEnabled(false);
                    uartTest.StartUartTest();
                    break;
                case R.id.btn_close:
                    uartTest.closeSerialPort();
                    btn_start.setEnabled(true);
                    break;
            }
        }
    
        @Override
        public void onSerialOpenException(Exception e) {
            showData("串口打开失败",tv_Send);
        }
    
        @Override
        public void onSendData(String sendData) {
            showData(sendData, tv_Send);
            if(sendData.equals("Send Check")){
                showData("已成功发送完数据包 ", tv_Send);
                btn_start.setEnabled(true);
            }
            sv_send.fullScroll(ScrollView.FOCUS_DOWN);
        }
    
        @Override
        public void onReceivedData(String receivedData) {
            showData(receivedData, tv_Result);
            if(receivedData.equals("(Ack) Receive Check")){
                showData("已接受完数据,升级成功 ", tv_Result);
            }
            sv_result.fullScroll(ScrollView.FOCUS_DOWN);
        }
    
        @Override
        public void onUpdateError() {
            showData("未接收MCU数据,升级失败", tv_Result);
        }
    
        private void showData(final String str, TextView tv) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    tv.append(str + "\n");
                }
            });
        }
    
    }
    

      

  • 相关阅读:
    51nod——1174 区间中最大的数(ST)
    「学习笔记」Ubuntu 下手动安装 Emacs
    [学习笔记] 2-SAT
    「解题报告」 [JXOI2017]数列 (DP)
    「解题报告」 [UOJ#62] 怎样跑得更快 (莫比乌斯反演)
    「学习笔记」杜教筛
    「学习笔记」Dirichlet卷积 莫比乌斯函数 莫比乌斯反演
    「学习笔记」向量外积(叉乘)
    网络流24题
    「解题报告」[网络流24题] 16.数字梯形问题 (最大费用最大流)
  • 原文地址:https://www.cnblogs.com/crushgirl/p/15807034.html
Copyright © 2020-2023  润新知