Android 串口开发(一) 串口读写操作,安卓多线程面试题

84 阅读4分钟

mDevices.add(files[i]);

}

}

}

return mDevices;

}

public String getName() {

return mDriverName;

}

}

private static final String TAG = "SerialPort";

private Vector mDrivers = null;

Vector getDrivers() throws IOException {

if (mDrivers == null) {

mDrivers = new Vector();

LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));

String l;

while ((l = r.readLine()) != null) {

// Issue 3:

// Since driver name may contain spaces, we do not extract driver name with split()

String drivername = l.substring(0, 0x15).trim();

String[] w = l.split(" +");

if ((w.length >= 5) && (w[w.length - 1].equals("serial"))) {

Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length - 4]);

mDrivers.add(new Driver(drivername, w[w.length - 4]));

}

}

r.close();

}

return mDrivers;

}

public String[] getAllDevices() {

Vector devices = new Vector();

// Parse each driver

Iterator itdriv;

try {

itdriv = getDrivers().iterator();

while (itdriv.hasNext()) {

Driver driver = itdriv.next();

Iterator itdev = driver.getDevices().iterator();

while (itdev.hasNext()) {

String device = itdev.next().getName();

String value = String.format("%s (%s)", device, driver.getName());

devices.add(value);

}

}

} catch (IOException e) {

e.printStackTrace();

}

return devices.toArray(new String[devices.size()]);

}

//获取设备上所有的串口节点

public String[] getAllDevicesPath() {

Vector devices = new Vector();

// Parse each driver

Iterator itdriv;

try {

itdriv = getDrivers().iterator();

while (itdriv.hasNext()) {

Driver driver = itdriv.next();

Iterator itdev = driver.getDevices().iterator();

while (itdev.hasNext()) {

String device = itdev.next().getAbsolutePath();

devices.add(device);

}

}

} catch (IOException e) {

e.printStackTrace();

}

return devices.toArray(new String[devices.size()]);

}

}

这个类一般不用,不占主要作用,主要用于可以获取设备上的所有可用的串口节点,用来选择设置,根据需求添加

public class SerialPort {

private static final String TAG = "SerialPort";

private FileDescriptor mFd;

private FileInputStream mFileInputStream;

private FileOutputStream mFileOutputStream;

public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {

//检查访问权限,如果没有读写权限,进行文件操作,修改文件访问权限

if (!device.canRead() || !device.canWrite()) {

try {

//通过挂载到linux的方式,修改文件的操作权限

Process su = Runtime.getRuntime().exec("/system/bin/su");

String cmd = "chmod 777 " + 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, flags);

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;

}

// JNI(调用java本地接口,实现串口的打开和关闭)

/**

  • 串口有五个重要的参数:串口设备名,波特率,检验位,数据位,停止位

  • 其中检验位一般默认位NONE,数据位一般默认为8,停止位默认为1

*/

/**

  • @param path 串口设备的绝对路径

  • @param baudrate 波特率

  • @param flags 校验位

*/

private native static FileDescriptor open(String path, int baudrate, int flags);

public native void close();

static {//加载jni下的C文件库

System.loadLibrary("serial_port");

}

}

这个SerialPort类是开源的,没有经过修改,Android可以,里面的直接调用,native方法直接和C通信,我们做Android的不需要管

jni目录下放着c源码和h头文件,

jniLibs下面放的就是so库。

注意:因为用的谷歌原生so库,所以SerialPort类的包名一定要是android_serialport_api,如果想修改这个包名,就需要重新生成对应的so库

public class SerialPortUtil {

public static String TAG = "SerialPortUtil";

/**

  • 标记当前串口状态(true:打开,false:关闭)

**/

public static boolean isFlagSerial = false;

public static SerialPort serialPort = null;

public static InputStream inputStream = null;

public static OutputStream outputStream = null;

public static Thread receiveThread = null;

public static String strData = "";

public static Handler mHandler;

/**

  • 打开串口

*/

public static boolean open() {

boolean isopen = false;

if(isFlagSerial){

LogUtils.e(TAG,"串口已经打开,打开失败");

return false;

}

try {

serialPort = new SerialPort(new File("/dev/ttyS3"), 115200, 0);

inputStream = serialPort.getInputStream();

outputStream = serialPort.getOutputStream();

receive();

isopen = true;

isFlagSerial = true;

} catch (IOException e) {

e.printStackTrace();

isopen = false;

}

return isopen;

}

/**

  • 关闭串口

*/

public static boolean close() {

if(isFlagSerial){

LogUtils.e(TAG,"串口关闭失败");

return false;

}

boolean isClose = false;

LogUtils.e(TAG, "关闭串口");

try {

if (inputStream != null) {

inputStream.close();

}

if (outputStream != null) {

outputStream.close();

}

isClose = true;

isFlagSerial = false;//关闭串口时,连接状态标记为false

} catch (IOException e) {

e.printStackTrace();

isClose = false;

}

return isClose;

}

/**

  • 发送串口指令

*/

public static void sendString(String data, Handler handler) {

mHandler = handler;

if (!isFlagSerial) {

LogUtils.e(TAG, "串口未打开,发送失败" + data);

return;

}

try {

outputStream.write(ByteUtil.hex2byte(data));

outputStream.flush();

LogUtils.e(TAG, "sendSerialData:" + data);

} catch (IOException e) {

e.printStackTrace();

LogUtils.e(TAG, "发送指令出现异常");

}

}

/**

  • 接收串口数据的方法

*/

public static void receive() {

if (receiveThread != null && !isFlagSerial) {

return;

}

receiveThread = new Thread() {

@Override

public void run() {

while (isFlagSerial) {

try {

byte[] readData = new byte[32];

if (inputStream == null) {

return;

}

int size = inputStream.read(readData);

if (size > 0 && isFlagSerial) {

strData = ByteUtil.byteToStr(readData, size);

LogUtils.e(TAG, "readSerialData:" + strData);

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

};

receiveThread.start();

}

}

这个类就比较重要了,打开串口、关闭串口、读写操作,都在这个类里面写了详细的注释,另外下面在贴一个工具类出来

package com.sqy.scancode.util;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.util.Base64;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import Decoder.BASE64Decoder;

import Decoder.BASE64Encoder;

/**

  • Created by Administrator on 2018/6/15.

*/

public class ByteUtil {

/**

  • 字符串转化成为16进制字符串

  • @param s

  • @return

*/

public static String strTo16(String s) {

String str = "";

for (int i = 0; i < s.length(); i++) {

int ch = (int) s.charAt(i);

String s4 = Integer.toHexString(ch);

str = str + s4;

}

return str;

}

/**

  • 16进制转换成为string类型字符串

  • @param s

  • @return

*/

public static String hexStringToString(String s) {

if (s == null || s.equals("")) {

return null;

}

s = s.replace(" ", "");

byte[] baKeyword = new byte[s.length() / 2];

for (int i = 0; i < baKeyword.length; i++) {

try {

baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));

} catch (Exception e) {

e.printStackTrace();

}

}

try {

s = new String(baKeyword, "UTF-8");

new String();

} catch (Exception e1) {

e1.printStackTrace();

}

return s;

}

/**

  • 向串口发送数据转为字节数组

*/

public static byte[] hex2byte(String hex) {

String digital = "0123456789ABCDEF";

String hex1 = hex.replace(" ", "");

最后

都说三年是程序员的一个坎,能否晋升或者提高自己的核心竞争力,这几年就十分关键。

技术发展的这么快,从哪些方面开始学习,才能达到高级工程师水平,最后进阶到Android架构师/技术专家?我总结了这 5大块;

我搜集整理过这几年阿里,以及腾讯,字节跳动,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

Android架构视频+BAT面试专题PDF+学习笔记​》

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望**这份系统化的技术体系**对大家有一个方向参考。

2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。