2012年1月15日 星期日

[ Android RS232 ] 在Android系統下實作RS232應用程式

有讀者反應希望能公開RS232 UART的原始程式碼,經本人向長高科技反應,得到該公司的授權,將該公司提供的UART原始程式碼公開。
首先,在UART Android應用程式是由兩支程式所組成:Uart_Control.java及Linuxc.java。Uart_Control.java 是UART應用程式的主程式,其原始程式如下:


package tw.com.dmatek.dma6410xp.uart;

import java.util.Timer;
import java.util.TimerTask;

import tw.com.dmatek.dma6410xp.R;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;

public class Uart_Control extends Activity {

TextView view1,view2,view;

Spinner spinner1;

String receiveMsg;
String Msg,str="liwei",ReStr;
EditText editmsg;
Button myButton0,myButton1,myButton2,myButton3,myButton4;
private boolean sign1;
public int num=1;
public int fd,set,i=-1,ss=0;
int p;

private static final String[] countriesStr =
 { "B1200", "B2400", "B4800", "B9600","B19200","B38400","B57600","B115200","B230400","B921600"};


private Spinner mySpinner;
 private ArrayAdapter adapter;

private Button.OnClickListener myButton0_listener=new Button.OnClickListener()
{

public void onClick(View arg0) {
// TODO Auto-generated method stub

if(i>0)
{
Linuxc.closeUart(0);
}
i=1;
fd=Linuxc.openUart(1);
if(fd>0)
    {
    setTitle("open device sucess!"+String.valueOf(fd));
    Linuxc.setUart(ss);
    sign1=true;
    }
    else
    {
    setTitle("open device false!"+fd);
    sign1=false;
    }
view1.setText("The current UART 1?");

}

};

private Button.OnClickListener myButton1_listener=new Button.OnClickListener()
{

public void onClick(View v) {
// TODO Auto-generated method stub

if(i>0)
{
Linuxc.closeUart(0);
}
i=2;
fd=Linuxc.openUart(2);
if(fd>0)
    {

    setTitle("open device sucess!"+String.valueOf(fd));
    Linuxc.setUart(ss);
    sign1=true;
    }
    else{
    setTitle("open device false!"+fd);
    sign1=false;
    }
    view1.setText("The current UART 2?");

}

};

private Button.OnClickListener myButton2_listener=new Button.OnClickListener()
{

public void onClick(View v) {
// TODO Auto-generated method stub

view.setText(null);
}

};

private Button.OnClickListener myButton3_listener=new Button.OnClickListener()
{

public void onClick(View v) {
// TODO Auto-generated method stub
timer.cancel();
Linuxc.closeUart(0);
finish();
// System.exit(0);
}

};

private Button.OnClickListener myButton4_listener=new Button.OnClickListener()
{

public void onClick(View v)
{
// TODO Auto-generated method stub
Msg=editmsg.getText().toString();
Linuxc.sendMsgUart(Msg);
}

};

Timer timer = new Timer();

TimerTask task = new TimerTask()
{
public void run()
{
runOnUiThread(new Runnable()
{
public void run()
{
if (sign1)
{
ReStr=Linuxc.receiveMsgUart();
if(ReStr!=null)
{
view.append(ReStr);
view.append("\n");
ReStr=null;
}


}

}
});
}
};

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.uart);              
     
     
       
     
        timer.schedule(task, 1000, 10);
     
        view1=(TextView)findViewById(R.id.uart_textview);
        view=(TextView)findViewById(R.id.uart_view);
        editmsg=(EditText)findViewById(R.id.uart_edit);
        editmsg.setWidth(200);
        mySpinner=(Spinner)findViewById(R.id.uart_mode);
     
        myButton0=(Button)findViewById(R.id.uart_button0);
        myButton1=(Button)findViewById(R.id.uart_button1);
        myButton2=(Button)findViewById(R.id.uart_button2);
        myButton3=(Button)findViewById(R.id.uart_button3);
        myButton4=(Button)findViewById(R.id.uart_button4);
     
     
     
        myButton0.setOnClickListener(myButton0_listener);  
        myButton1.setOnClickListener(myButton1_listener);
        myButton2.setOnClickListener(myButton2_listener);
        myButton3.setOnClickListener(myButton3_listener);
        myButton4.setOnClickListener(myButton4_listener);
     
        adapter = new ArrayAdapter(this,
                android.R.layout.simple_spinner_item, countriesStr);
         
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

       
            mySpinner.setAdapter(adapter);
         
            mySpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener()
            {

              public void onItemSelected(AdapterView arg0, View arg1, int arg2,
                  long arg3)
              {
           
             
   
                if(fd>0)  Linuxc.setUart(arg2);
                ss=arg2;
            arg0.setVisibility(View.VISIBLE);
              }

              public void onNothingSelected(AdapterView arg0)
              {
                // TODO Auto-generated method stub
              }

            });

     
     
   
    }
}

Linuxc.java則是用來連接SO的檔案,其原始程式如下:

package tw.com.dmatek.dma6410xp.uart;

import android.util.Log;

public class Linuxc {
static
{
try
{
System.loadLibrary("uart");
Log.i("JIN","Trying to load libuart.so");
}
catch(UnsatisfiedLinkError ule)
{
Log.e("JIN","WARNING:could not load libuart.so");
}
}
public static native int openUart(int i);
public static native void closeUart(int i);
public static native int setUart(int i);
public static native int sendMsgUart(String msg);
public static native String  receiveMsgUart();

}

資源檔uart.xml原始程式如下:

  xml version="1.0" encoding="utf-8" ?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/uart_index">
  <TextView android:id="@+id/uart_textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="DMA-6410XP desk to UART item" android:textSize="30px" android:textColor="#ffffffff" android:layout_centerHorizontal="true" android:layout_alignParentTop="true" />
- <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/uart_scrollview" android:layout_width="520px" android:layout_height="230px" android:layout_marginTop="35px" android:layout_below="@+id/uart_textview" android:layout_alignParentRight="true" android:layout_marginRight="30px" android:background="#ffffffff">
  <TextView android:id="@+id/uart_view" android:layout_above="@+id/uart_text" android:layout_width="fill_parent" android:layout_height="fill_parent" android:textColor="#ff000000" android:textSize="20px" android:text="" />
  ScrollView>
  <TextView android:id="@+id/uart_view1" android:layout_width="wrap_content" android:layout_height="40px" android:layout_below="@+id/uart_scrollview" android:layout_centerHorizontal="true" android:layout_marginTop="30px" android:layout_marginLeft="50px" android:layout_marginRight="50px" android:text="" />
  <EditText android:id="@+id/uart_edit" android:layout_width="350px" android:layout_height="65px" android:layout_marginTop="40px" android:layout_marginRight="40px" android:layout_below="@+id/uart_scrollview" android:layout_alignLeft="@+id/uart_scrollview" />
  <Button android:id="@+id/uart_button1" android:layout_width="100px" android:layout_height="wrap_content" android:layout_below="@+id/uart_button0" android:layout_marginTop="15px" android:layout_marginLeft="70px" android:text="UART 2" />
  <Button android:id="@+id/uart_button0" android:layout_width="100px" android:layout_height="wrap_content" android:layout_alignTop="@+id/uart_scrollview" android:layout_marginLeft="70px" android:text="UART 1" />
  <Button android:id="@+id/uart_button2" android:layout_width="100px" android:layout_height="wrap_content" android:layout_marginLeft="70px" android:layout_alignBottom="@+id/uart_scrollview" android:text="CLEAN" />
  <Button android:id="@+id/uart_button3" android:layout_width="100px" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/uart_edit" android:layout_marginBottom="30dip" android:layout_marginLeft="70dip" android:text="EXIT" />
  <Spinner android:id="@+id/uart_mode" android:layout_width="100px" android:layout_height="wrap_content" android:layout_below="@+id/uart_button1" android:layout_marginTop="15px" android:layout_marginLeft="70px" />
  <Button android:id="@+id/uart_button4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/uart_edit" android:layout_toRightOf="@+id/uart_edit" android:layout_alignRight="@+id/uart_scrollview" android:text="SEND" />
  RelativeLayout>


上述三個檔案可以產生UART.apk

除了APK檔案外,還需要SO函式庫,其原始程式包括:tw_com_dmatek_dma6410xp_uart_Linuxc及tw_com_dmatek_dma6410xp_uart_Linuxc.h

tw_com_dmatek_dma6410xp_uart_Linuxc.c的原始程式如下:

#include
#include
#include
#include
#include
#include "tw_com_dmatek_dma6410xp_uart_Linuxc.h"
#include
#include
#include
#include
#include
#include
//#include


#include
#undef  TCSAFLUSH
#define TCSAFLUSH  TCSETSF
#ifndef _TERMIOS_H_
#define _TERMIOS_H_
#endif


int fd;
struct termios newtio,oldtio;


JNIEXPORT jint JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_openUart(JNIEnv *env,jobject mc,jint i)
{
if(i==1)
{
fd=open("/dev/ttySAC1",O_RDWR|O_NOCTTY|O_NDELAY);//O_NOCTTY 
return fd;
}
else if(i==2)
{
fd=open("/dev/ttySAC2",O_RDWR|O_NOCTTY|O_NDELAY);
return fd;
}
else if(i==3)
        {
        fd=open("/dev/ttySAC3",O_RDWR|O_NDELAY|O_NOCTTY);
        return fd;
        }
return fd;
}


JNIEXPORT void JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_closeUart(JNIEnv *env,jobject mc,jint i)
{
close(fd);
}


JNIEXPORT jint JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_setUart(JNIEnv *env,jobject mc,jint i)
{


int speed_arr[]={B1200,B2400,B4800,B9600,B19200,B38400,B57600,B115200,B230400,B921600};


tcgetattr(fd,&oldtio);
tcgetattr(fd,&newtio);
cfsetispeed(&newtio,speed_arr[i]);
cfsetospeed(&newtio,speed_arr[i]);
newtio.c_lflag=0; 
newtio.c_cflag = speed_arr[i] | CS8 | CREAD | CLOCAL;
newtio.c_iflag= BRKINT | IGNPAR | IGNCR | IXON | IXOFF | IXANY ;
newtio.c_oflag=02;
newtio.c_line=0;
newtio.c_cc[7]=255;
newtio.c_cc[4]=0;
newtio.c_cc[5]=0;

if(tcsetattr(fd,TCSANOW,&newtio)<0)
{
printf("tcsetattr fail !\n");
exit(1);
}
return fd;
     


}


JNIEXPORT jint JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_sendMsgUart(JNIEnv *env,jobject mc,jstring str)
{
int len;
const char *buf;
buf=(*env)->GetStringUTFChars(env,str,NULL);
len= (*env)->GetStringLength(env,str );
write(fd,buf,len);
(*env)->ReleaseStringUTFChars(env, str, buf);
}


JNIEXPORT jstring JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_receiveMsgUart(JNIEnv *env,jobject mc)
{
char buffer[255];
char buf[255];
int len,i=0,k=0;
memset(buffer,0,sizeof(buffer));
memset(buf,0,sizeof(buf));
printf("\n");
len=read(fd,buffer,255);
if (len>0)
{
__android_log_print(ANDROID_LOG_INFO,"len","len =%d, buffer[0]=%c,buffer[1]=%c\n",len,buffer[0],buffer[1]);
__android_log_print(ANDROID_LOG_INFO,"buffer","buffer=%s\n",buffer);
//return (*env)->NewStringUTF(env,buffer);
}
else
return NULL;
}

tw_com_dmatek_dma6410xp_uart_Linuxc.h的原始程式如下:


/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class tw_com_dmatek_dma6410xp_uart_Linuxc */


#ifndef _Included_tw_com_dmatek_dma6410xp_uart_Linuxc
#define _Included_tw_com_dmatek_dma6410xp_uart_Linuxc
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     tw_com_dmatek_dma6410xp_uart_Linuxc
 * Method:    openUart
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_openUart
  (JNIEnv *, jobject, jint);


/*
 * Class:     tw_com_dmatek_dma6410xp_uart_Linuxc
 * Method:    closeUart
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_closeUart
  (JNIEnv *, jobject, jint);


/*
 * Class:     tw_com_dmatek_dma6410xp_uart_Linuxc
 * Method:    setUart
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_setUart
  (JNIEnv *, jobject,jint);


/*
 * Class:     tw_com_dmatek_dma6410xp_uart_Linuxc
 * Method:    sendMsgUart
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_sendMsgUart
  (JNIEnv *, jobject, jstring);


/*
 * Class:     tw_com_dmatek_dma6410xp_uart_Linuxc
 * Method:    receiveMsgUart
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_tw_com_dmatek_dma6410xp_uart_Linuxc_receiveMsgUart
  (JNIEnv *, jobject);


#ifdef __cplusplus
}
#endif
#endif




8 則留言:

  1. 請問一下我將
    tw_com_dmatek_dma6410xp_uart_Linuxc.h
    tw_com_dmatek_dma6410xp_uart_Linuxc.c
    丟到jni下去做ndk-build
    出現以下error

    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:1:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:2:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:3:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:4:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:5:10: error: #include expects "FILENAME" or
    In file included from jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:6:
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.h:2:10: error: #include expects "FILENAME" or
    In file included from jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:6:
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.h:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jint'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.h:25: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'void'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.h:34: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jint'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.h:43: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jint'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.h:52: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jstring'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:7:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:8:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:9:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:10:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:11:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:12:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:16:10: error: #include expects "FILENAME" or
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:28: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jint'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:49: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'void'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:55: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jint'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:87: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jint'
    jni/tw_com_dmatek_dma6410xp_uart_Linuxc.c:98: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jstring'

    android.mk

    LOCAL_MODULE := tw_com_dmatek_dma6410xp_uart_Linuxc
    LOCAL_SRC_FILES := tw_com_dmatek_dma6410xp_uart_Linuxc.c
    是不是我沒載入到一些東西?

    回覆刪除
  2. #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <unistd.h>
    #include "tw_dmatek_uart_Linuxc.h"
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <stdint.h>
    #include <termios.h>
    #include <android/log.h>
    //#include <time.h>

    #include <sys/ioctl.h>
    #undef TCSAFLUSH
    #define TCSAFLUSH TCSETSF
    #ifndef _TERMIOS_H_
    #define _TERMIOS_H_
    #endif

    回覆刪除
    回覆
    1. 您好,最近我在學習ndk jni的開發環境,我想請問的是我想在android上實作一套專案已由C所撰寫完成,我想將之移植到android,透過NDK。 (先姑且不論直接將功能以java完成的這個方案)

      只是我必須要用這隻程式去抓取GPS的資訊,是不是就必須像此專案一樣,必須要自己撰寫一個符合手機的drive去接收呢?

      刪除
    2. GPS訊號大多都是透過UART(RS-232)進來的,所以可以不用寫驅動,直接將程式指定到GPS所指定的com port就行了。這樣的實驗,可以參考本部落格中:Java Native Interface (JNI) Android實戰篇(使用NDK) -- HelloUart
      文章後面有實作:
      開發平台 <--> PL-2303 <--> GPS接收器

      刪除
  3. 您好,我對Android UART上很有興趣,不知道方便提供project demo嗎?
    我已經寫了一個藍芽版的.
    希望能夠加入usb的功能~

    回覆刪除
  4. 現在FTDI有相關方案, Android USB 轉串口, FT312D, FT231X(PC,Android 雙用)
    FTDI官網有開發包, 有API可調用, 可在google play 下載APK, 或打Passiontech, 下載安卓超級終端

    回覆刪除
  5. 想請教一下
    tw_com_dmatek_dma6410xp_uart_Linuxc.h這個檔案是否與
    Android.mk是相似的?

    回覆刪除