【Android】SerialPortFinder学习笔记,显示串口列表

显示串口列表这个操作还不涉及底层的东西,因为Android与Linux相似,有串口设备就会在/dev目录下生成一个文件,比如/dev/ttyS0之类的,在谷歌的ndroid-serialport-api项目中,有一个SerialPortFinder.java方法,这个方法是不涉及底层的,没有native方法,也不需要c和h文件,所以我觉得Android串口入门,应该先从这个文件开始了解。

一、准备工作

1、新建一个工程
[image:013658FC-53F3-4DAB-9ED8-A6D7F4F86631-38535-0001F78575A5C84D/1E49030B-84C5-487B-9A25-AD6F4E173CE9.png]
2、选择Empty Activity程序
[image:46EDEF71-7664-430B-9FA5-065FF81505DF-38535-0001F78A3257C0F1/B9879563-4657-4BAA-BAB0-9D0CC21ECF43.png]

3、随便起个名字
[image:43B3258E-884B-48CE-992B-C735503989CB-38535-0001F7A55561685D/78E4AEA9-014B-43E9-9D75-5C4A03DA3A18.png]

4、然后将SerialPortFinder.java复制到你的目录下
[image:10F9CE45-47FF-413F-9837-B0D68F8F4DA7-38535-0001F7C04F0B5AC1/C681A273-5B7D-4219-9D96-BBB1F1B63E9B.png]
这个文件可以在
https://github.com/cepr/android-serialport-api
下载,其中该文件在
android-serialport-api-master/android-serialport-api/project/src/android_serialport_api/SerialPortFinder.java

然后我们就可以使用了。

二、getAllDevicesPath()

2.1 函数说明

getAllDevicesPath()
它会返回一系列的串口名称给你,你只要拿一个字符串数组接住它就可以了

String[] devices=new SerialPortFinder().getAllDevicesPath();

之后你将devices中的字符串数组,用循环取出来,然后以TextView的方式显示出来也可以,你会发现一堆”/dev/ttyS0”,”/dev/ttyS1”之类的,这些就是串口路径,注意,Android和Linux相似,与Windows不相似,Android操作串口时操作路径,而Windows是串口名称“COMx”,示例如下:
Linux:SerialPort(“/dev/ttyS1”,9600,N,8,1)
Windows:SerialPort(“COM1”,9600,N,8,1)

这个方法的内容如下:

    public String[] getAllDevicesPath() {
        Log.d(TAG, "获取所有串口地址");
        Vector<String> devices = new Vector<>();
        try {
            // Parse each driver
            for (Driver driver : getDrivers()) {
                for (File file : driver.getDevices()) {
                    String device = file.getAbsolutePath();
                    devices.add(device);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return devices.toArray(new String[0]);
    }

2.2 函数详解

里面主要使用了SerialPortFinder.java中的

getDrivers()

以及
Driver类下的

getDevices()

这两个方法看起来很相似,实际上是有本质的区别,首先getDrivers()获取到的是Drivers(注意后缀s),而一个Drivers中包含多个driver,一个driver中包含多个device(File),使用driver.getDevices()可以获得Devices(注意后缀s),即多个device。

以各个变量的串口数量来排序如下:

Drivers>driver==Devices>device(1个)

getDrivers()操作的路径是

/proc/tty/drivers

而getDevices()操作的路径是

/dev

/dev下一个ttySX是一个串口device(File),那么多个device就是串口集合Devices,一个串口集合又以driver表示在/proc/tty/drivers中,getDrivers()就是获取串口集合driver的集合,所以不管是后面的getAllDevices()方法还是getAllDevicesPath()方法,都会用两个循环来取串口设备device(File)。

for (Driver driver : getDrivers()) {
                for (File file : driver.getDevices()) {
					……
				}
            }

2.3 使用ListView显示串口列表

为了方便我们选中某个就进去,然后操作它,我们还是把它放在ListView里。
我们写一个ListView用来显示串口列表
1、将原本的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">

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/id_list"/>

</LinearLayout> 

2、然后在同目录下新建一个item.layout
[image:ED26CAF1-99D3-4CD4-ADB3-0092C91C6BE1-38535-0001F97F72684ED7/90A3CA1A-6110-40EA-BC63-F62EB599AD79.png]

内容如下:

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/id_item_text"
        android:textSize="32sp"/>

</LinearLayout> 

3、本来想用ListAdapter做适配器的,不过感觉里面太多方法用不上,还是BaseAdapter简单一点,实现如下:
MainActivity.java

package com.a;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final String[] devices=new SerialPortFinder().getAllDevicesPath();

        ListView listView=findViewById(R.id.id_list);

        BaseAdapter bA=new BaseAdapter() {
            @Override
            public int getCount() {
                return devices.length;
            }

            @Override
            public Object getItem(int position) {
                return devices[position];
            }

            @Override
            public long getItemId(int position) {
                return position;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                if (convertView==null)
                    convertView=getLayoutInflater().inflate(R.layout.item_layout,null);
                TextView textView=convertView.findViewById(R.id.id_item_text);
                textView.setText(devices[position]);

                return convertView;
            }
        };
        listView.setAdapter(bA);

    }
}

4、效果如下:
[image:5895D541-7B0D-4F74-BA04-24C424C256CA-38535-0002072A153D4A53/6DA08B4E-50B6-4C1F-92B7-41ABCC09B902.png]
补充:截图方式,点击左下角logcat,拉高,有一个照相机图标,点击即可。
[image:24B09473-CC53-4236-8A84-4F54E266A5D7-38535-00020738C89AA5BC/E371C4B5-A119-4BA2-B8B6-161453FD8D8C.png]

三、getAllDevices()

函数getAllDevices()其实就是把device和driver结合起来,

deviceName (driverName)

将原来的getAllDevicesPath()函数改为getAllDevices()函数

final String[] devices=new SerialPortFinder().getAllDevices();

显示如下:
[image:F8241450-86A8-49BC-B7CE-7CE0D11B30B2-38535-00021556DDE0017F/15018DE5-83CB-431D-9F3E-013B87522AEB.png]

四、获取文件读写权限

如果用过串口设备的小伙伴知道,一些设备往往有多个串口,而有一些是不能被使用的,比如上面的GS,他们表现出来的状态就是不可读不可写,那么我们如何识别这种状态呢?

我们在onCreate的
final String[] devices=new SerialPortFinder().getAllDevicesPath();
后添加如下内容,对文件的可读可写进行判断

final List<String> data = new ArrayList<>();
        if (devices.length > 0) {
            for (String device : devices) {

                File file = new File(device);
                String path = file.getAbsolutePath();

                StringBuilder permission = new StringBuilder();
                permission.append("[");
                permission.append(file.canRead() ? " 可读" : "不可读");
                permission.append(file.canWrite() ? "  可写 " : " 不可写 ");
                permission.append(file.canExecute() ? "可执行" : "不可执行");
                permission.append("]");

                String msg = "(" + path + ")" + " 权限:" + permission;
                data.add(msg);
            }
        }

并将BaseAdapter中的TextView获取文本的方式修改如下:

textView.setText(data.get(position));

MainActivity.java完整代码

package com.a;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final String[] devices=new SerialPortFinder().getAllDevicesPath();

        final List<String> data = new ArrayList<>();
        if (devices.length > 0) {
            for (String device : devices) {

                File file = new File(device);
                String path = file.getAbsolutePath();

                StringBuilder permission = new StringBuilder();
                permission.append("[");
                permission.append(file.canRead() ? " 可读" : "不可读");
                permission.append(file.canWrite() ? "  可写 " : " 不可写 ");
                permission.append(file.canExecute() ? "可执行" : "不可执行");
                permission.append("]");

                String msg = "(" + path + ")" + " 权限:" + permission;
                data.add(msg);
            }
        }

        ListView listView=findViewById(R.id.id_list);

        BaseAdapter bA=new BaseAdapter() {
            @Override
            public int getCount() {
                return devices.length;
            }

            @Override
            public Object getItem(int position) {
                return devices[position];
            }

            @Override
            public long getItemId(int position) {
                return position;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                if (convertView==null)
                    convertView=getLayoutInflater().inflate(R.layout.item_layout,null);
                TextView textView=convertView.findViewById(R.id.id_item_text);
                textView.setText(data.get(position));

                return convertView;
            }
        };
        listView.setAdapter(bA);

    }
}

显示效果:
[image:FAC20946-1173-48E4-A2F4-C1333722E77E-38535-000216033EBCC159/492BCDA5-FBC7-46D2-A920-5A628F8D6888.png]

#technology/Android/SerialPort

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值