2010-07-13 31 views
1

我將一個linux應用程序移植到android上,它運行在beagle板上。Android-Beagleboard上的串口編程

我的應用程序必須訪問串口(send/recv)。 是否可以使用應用程序讀取/寫入串行端口,除非android是「root」的?

回答

0

我已經爲Android寫了一個SerialPortChannel類。它使用JNA

// Copyright 2015 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland 
// www.source-code.biz, www.inventec.ch/chdh 
// 
// This module is multi-licensed and may be used under the terms of any of the following licenses: 
// 
// LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html 
// EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal 
// 
// Please contact the author if you need another license. 
// This module is provided "as is", without warranties of any kind. 
// 
// Home page: http://www.source-code.biz/snippets/java/SerialPortChannel 

package biz.source_code.utils; 

import java.io.FileDescriptor; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.lang.reflect.Method; 
import java.nio.ByteBuffer; 
import java.nio.channels.ByteChannel; 
import java.nio.channels.FileChannel; 
import java.util.Arrays; 
import java.util.List; 
import com.sun.jna.LastErrorException; 
import com.sun.jna.Library; 
import com.sun.jna.Native; 
import com.sun.jna.Pointer; 
import com.sun.jna.Structure; 

/** 
* A serial port channel for Android. 
* 
* <p>This class uses JNA to access a serial port device (TTY) of the Android operating system. 
*/ 
public class SerialPortChannel implements ByteChannel { 

private boolean   isOpen; 
private int    fileHandle; 
private FileDescriptor  fileDescriptor; 
private FileInputStream rxStream; 
private FileOutputStream txStream; 
private FileChannel  rxChannel; 
private FileChannel  txChannel; 

/** 
* Creates a serial port channel. 
* 
* @param fileName 
* The file name of the serial port device, e.g. "/dev/ttyO2". 
* @param baudRate 
* The baud rate for the serial port, e.g. 9600. 
* @param blocking 
* <code>true</code> for blocking i/o or <code>false</code> for non-blocking i/o. 
*/ 
public SerialPortChannel (String fileName, int baudRate, boolean blocking) throws IOException { 
    staticInit(); 
    try { 
     open(fileName, baudRate, blocking); } 
    finally { 
     if (!isOpen) { 
     close2(); }}} 

private void open (String fileName, int baudRate, boolean blocking) throws IOException { 
    int mode = LibcDefs.O_RDWR | (blocking ? 0 : LibcDefs.O_NONBLOCK); 
    fileHandle = libc.open(fileName, mode); 
    fileDescriptor = createFileDescriptor(fileHandle); 
    configureSerialPort(baudRate); 
    rxStream = new FileInputStream(fileDescriptor); 
    txStream = new FileOutputStream(fileDescriptor); 
    rxChannel = rxStream.getChannel(); 
    txChannel = txStream.getChannel(); 
    isOpen = true; } 

private void configureSerialPort (int baudRate) throws IOException { 
    termios cfg = new termios(); 
    LibcDefs.tcgetattr(fileHandle, cfg); 
    LibcDefs.cfmakeraw(cfg); 
    int baudRateCode = encodeBaudRate(baudRate); 
    LibcDefs.cfsetospeed(cfg, baudRateCode); 
    LibcDefs.tcsetattr(fileHandle, cfg); } 

@Override public boolean isOpen() { 
    return isOpen; } 

@Override public void close() throws IOException { 
    if (!isOpen) { 
     return; } 
    isOpen = false; 
    close2(); } 

private void close2() throws IOException { 
    if (fileHandle != 0) { 
     libc.close(fileHandle); } 
    if (rxStream != null) { 
     rxStream.close(); } 
    if (txStream != null) { 
     txStream.close(); }} 

@Override public int read (ByteBuffer buf) throws IOException { 
    return rxChannel.read(buf); } 

public int read (byte[] buf) throws IOException { 
    return read(ByteBuffer.wrap(buf)); } 

@Override public int write (ByteBuffer buf) throws IOException { 
    return txChannel.write(buf); } 

public int write (byte[] buf, int pos, int len) throws IOException { 
    return write(ByteBuffer.wrap(buf, pos, len)); } 

public int write (byte[] buf) throws IOException { 
    return write(buf, 0, buf.length); } 

private static int encodeBaudRate (int baudRate) { 
    switch (baudRate) { 
     case 0:  return 0000000; 
     case 50:  return 0000001; 
     case 75:  return 0000002; 
     case 110:  return 0000003; 
     case 134:  return 0000004; 
     case 150:  return 0000005; 
     case 200:  return 0000006; 
     case 300:  return 0000007; 
     case 600:  return 0000010; 
     case 1200: return 0000011; 
     case 1800: return 0000012; 
     case 2400: return 0000013; 
     case 4800: return 0000014; 
     case 9600: return 0000015; 
     case 19200: return 0000016; 
     case 38400: return 0000017; 
     case 57600: return 0010001; 
     case 115200: return 0010002; 
     case 230400: return 0010003; 
     case 460800: return 0010004; 
     case 500000: return 0010005; 
     case 576000: return 0010006; 
     case 921600: return 0010007; 
     case 1000000: return 0010010; 
     case 1152000: return 0010011; 
     case 1500000: return 0010012; 
     case 2000000: return 0010013; 
     case 2500000: return 0010014; 
     case 3000000: return 0010015; 
     case 3500000: return 0010016; 
     case 4000000: return 0010017; 
     default: throw new IllegalArgumentException("Unsupported baud rate " + baudRate + "."); }} 

//------------------------------------------------------------------------------ 

private static Libc  libc; 
private static Method fileDescriptorSetInt; 
private static boolean staticInitDone; 

private static interface Libc extends Library { 

    // fcntl.h 
    int open(String path, int mode) throws LastErrorException; 

    // unistd.h 
    int close(int fileHandle) throws LastErrorException; 
    int ioctl(int fileHandle, int request, Pointer p) throws LastErrorException; } 

private static class LibcDefs { 

    // fcntl.h 
    static final int O_RDWR  = 00000002; 
    static final int O_NONBLOCK = 00004000; 

    // ioctls.h 
    static final int TCGETS = 0x5401;      // for ARM and X86, Mips is 0x540d 
    static final int TCSETS = 0x5402; 

    // termios.h 
    static final int IGNBRK = 0000001; 
    static final int BRKINT = 0000002; 
    static final int PARMRK = 0000010; 
    static final int ISTRIP = 0000040; 
    static final int INLCR = 0000100; 
    static final int IGNCR = 0000200; 
    static final int ICRNL = 0000400; 
    static final int IXON = 0002000; 
    static final int OPOST = 0000001; 
    static final int ISIG = 0000001; 
    static final int ICANON = 0000002; 
    static final int ECHO = 0000010; 
    static final int ECHONL = 0000100; 
    static final int IEXTEN = 0100000; 
    static final int CBAUD = 0010017; 
    static final int CSIZE = 0000060; 
    static final int PARENB = 0000400; 
    static final int CS8 = 0000060; 
    private static void tcgetattr (int fileHandle, termios cfg) throws IOException { 
     if (libc.ioctl(fileHandle, TCGETS, cfg.getPointer()) != 0) { 
     throw new IOException("tcgetattr failed."); } 
     cfg.read(); } 
    private static void tcsetattr (int fileHandle, termios cfg) throws IOException { 
     cfg.write(); 
     if (libc.ioctl(fileHandle, TCSETS, cfg.getPointer()) != 0) { 
     throw new IOException("tcsetattr failed."); }} 
    private static void cfmakeraw (termios cfg) { 
     cfg.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); 
     cfg.c_oflag &= ~OPOST; 
     cfg.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); 
     cfg.c_cflag &= ~(CSIZE|PARENB); 
     cfg.c_cflag |= CS8; } 
    private static void cfsetospeed (termios cfg, int baudRateCode) { 
     cfg.c_cflag = (cfg.c_cflag & ~CBAUD) | (baudRateCode & CBAUD); }} 

private static class termios extends Structure { 
    public int c_iflag; 
    public int c_oflag; 
    public int c_cflag; 
    public int c_lflag; 
    public byte c_line; 
    public byte[] c_cc = new byte[32];      // actual length depends on platform (currently 19 for ARM and X86, 23 for Mips) 
    @Override protected List<?> getFieldOrder() { 
     return Arrays.asList("c_iflag", "c_oflag", "c_cflag", "c_lflag", "c_line", "c_cc"); }} 

private static synchronized void staticInit() { 
    if (staticInitDone) { 
     return; } 
    libc = (Libc)Native.loadLibrary("c", Libc.class); 
    try { 
     fileDescriptorSetInt = FileDescriptor.class.getDeclaredMethod("setInt$", int.class); } 
    catch (Exception e) { 
     throw new RuntimeException(e); } 
    staticInitDone = true; } 

// This method is Android-specific and does not work with the normal Java runtime library. 
private static FileDescriptor createFileDescriptor (int fileHandle) { 
    FileDescriptor fileDescriptor = new FileDescriptor(); 
    try { 
     fileDescriptorSetInt.invoke(fileDescriptor, fileHandle); } 
    catch (Exception e) { 
     throw new RuntimeException(e); } 
    return fileDescriptor; } 

} 
+0

雖然此鏈接可以回答這個問題,最好是在這裏有答案的主要部件,並提供鏈接以供參考。如果鏈接頁面更改,則僅鏈接答案可能會失效。 – 2015-05-10 23:19:00

+0

好的,我在回答中包含了源代碼,但它有點大,我可能會在未來擴展該模塊。 – 2015-08-02 01:01:08