android 串口通信实例分析,用的时开源的android-serialport-api
这个是用android ndk实现的串口通信,我把他做了一个简化,适合于一般的程序的串口通信移植,欢迎拍砖~~~~~~~~~
先说jni接口吧,原本文件太多,其实只需要SerialPort.c和Android.mk就可以实现
Serialport.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <termios.h>
- #include <errno.h>
- #include <jni.h>
- #include <android/log.h>
-
- #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "", __VA_ARGS__))
-
-
-
- static speed_t getBaudrate(jint baudrate)
- {
- switch(baudrate) {
- case 0: return B0;
- case 50: return B50;
- case 75: return B75;
- case 110: return B110;
- case 134: return B134;
- case 150: return B150;
- case 200: return B200;
- case 300: return B300;
- case 600: return B600;
- case 1200: return B1200;
- case 1800: return B1800;
- case 2400: return B2400;
- case 4800: return B4800;
- case 9600: return B9600;
- case 19200: return B19200;
- case 38400: return B38400;
- case 57600: return B57600;
- case 115200: return B115200;
- case 230400: return B230400;
- case 460800: return B460800;
- case 500000: return B500000;
- case 576000: return B576000;
- case 921600: return B921600;
- case 1000000: return B1000000;
- case 1152000: return B1152000;
- case 1500000: return B1500000;
- case 2000000: return B2000000;
- case 2500000: return B2500000;
- case 3000000: return B3000000;
- case 3500000: return B3500000;
- case 4000000: return B4000000;
- default: return -1;
- }
- }
-
-
-
-
-
-
-
-
-
-
- JNIEXPORT jobject JNICALL Java_com_huangcheng_serial_SerialPort_open
- (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)
- {
- int fd;
- speed_t speed;
- jobject mFileDescriptor;
-
-
- {
- speed = getBaudrate(baudrate);
- if (speed == -1) {
-
- LOGI("Invalid baudrate");
- return NULL;
- }
- }
-
-
- {
- jboolean iscopy;
- const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
- LOGI("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
- fd = open(path_utf, O_RDWR | flags);
- LOGI("open() fd = %d", fd);
- (*env)->ReleaseStringUTFChars(env, path, path_utf);
- if (fd == -1)
- {
-
- LOGI("Cannot open port");
-
- return NULL;
- }
- }
-
-
- {
- struct termios cfg;
- LOGI("Configuring serial port");
- if (tcgetattr(fd, &cfg))
- {
- LOGI("tcgetattr() failed");
- close(fd);
-
- return NULL;
- }
-
- cfmakeraw(&cfg);
- cfsetispeed(&cfg, speed);
- cfsetospeed(&cfg, speed);
-
- if (tcsetattr(fd, TCSANOW, &cfg))
- {
- LOGI("tcsetattr() failed");
- close(fd);
-
- return NULL;
- }
- }
-
-
- {
- jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
- jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
- jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
- mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
- (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
- }
-
- return mFileDescriptor;
- }
-
-
-
-
-
-
-
-
- JNIEXPORT void JNICALL Java_com_huangcheng_serial_SerialPort_close
- (JNIEnv *env, jobject thiz)
- {
- jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
- jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
-
- jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
- jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");
-
- jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
- jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
-
- LOGI("close(fd = %d)", descriptor);
- close(descriptor);
- }
Android.mk
- LOCAL_PATH := $(call my-dir)
-
- include $(CLEAR_VARS)
-
- LOCAL_MODULE := serial_port
- LOCAL_SRC_FILES := SerialPort.c
-
- LOCAL_LDLIBS := -llog
- include $(BUILD_SHARED_LIBRARY)
然后,直接在目录下ndk-build一下,便可得到我们需要的lib库文件。看看怎么调用吧,首先在SerialPort.java中实现打开和关闭串口,引用了lib 库
- package com.huangcheng.serial;
-
- 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;
-
- import android.util.Log;
-
- 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 {
-
- 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, flags);
- if (mFd == null) {
- Log.e(TAG, "native open returns null");
- throw new IOException();
- }
- mFileInputStream = new FileInputStream(mFd);
- mFileOutputStream = new FileOutputStream(mFd);
- }
-
-
- public InputStream getInputStream() {
- return mFileInputStream;
- }
-
- public OutputStream getOutputStream() {
- return mFileOutputStream;
- }
-
-
- private native static FileDescriptor open(String path, int baudrate, int flags);
- public native void close();
- static {
- System.loadLibrary("serial_port");
- }
- }
然后他做了一个很聪明的控制串口打开和关闭的类Application.java,继承自android.app.Application 这样,他便可以在所有的Activity类中调用实现串口打开和关闭。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package com.huangcheng.serial;
-
- import java.io.File;
- import java.io.IOException;
- import java.security.InvalidParameterException;
-
- public class Application extends android.app.Application {
-
- private SerialPort mSerialPort = null;
-
- public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {
- if (mSerialPort == null) {
-
- mSerialPort = new SerialPort(new File("/dev/ttyUSB0"),19200, 0);
- }
- return mSerialPort;
- }
-
- public void closeSerialPort() {
- if (mSerialPort != null) {
- mSerialPort.close();
- mSerialPort = null;
- }
- }
- }
最后写了一个类SerialPortActivity.java实现串口打开和关闭,串口数据通过Input/OutputStrean流来读取和发送,所有继承这个类的Activiy就可以实现串口读取或者发送。
最后,是一个测试Activity实现串口收发,ConsoleActivity.java
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package com.huangcheng.serial;
-
- import java.io.IOException;
-
- import com.huangcheng.zigbeeview.R;
-
- import android.os.Bundle;
- import android.view.KeyEvent;
- import android.widget.EditText;
- import android.widget.TextView;
- import android.widget.TextView.OnEditorActionListener;
-
- public class ConsoleActivity extends SerialPortActivity {
-
- EditText mReception;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.console);
-
-
- mReception = (EditText) findViewById(R.id.EditTextReception);
-
- EditText Emission = (EditText) findViewById(R.id.EditTextEmission);
- Emission.setOnEditorActionListener(new OnEditorActionListener() {
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- int i;
- CharSequence t = v.getText();
- char[] text = new char[t.length()];
- for (i=0; i<t.length(); i++) {
- text[i] = t.charAt(i);
- }
- try {
- mOutputStream.write(new String(text).getBytes());
- mOutputStream.write('\n');
- } catch (IOException e) {
- e.printStackTrace();
- }
- return false;
- }
- });
- }
-
- @Override
- protected void onDataReceived(final byte[] buffer, final int size) {
- runOnUiThread(new Runnable() {
- public void run() {
- if (mReception != null) {
- mReception.append(new String(buffer, 0, size));
- }
- }
- });
- }
- }
我会把android-serialport-api源码上传,大家可以根据我的这个博客自己简化一下,就可以直接移植到需要到程序上去了,绝对可用!