本例子来自实际的出租车项目,
背景:
客户下载Android/iOS客户端订车系统,出租车司机的Driver系统接受订单后,驾驶至目的地,客户上车,计价器off/on,客户下车。Android程序需要读取计价器的off/on状态,进行后继处理。
解决方案:
利用开源的android-serialport-api项目(http://code.google.com/p/android-serialport-api/),重新连接usb线到Adapter(USB to RS232 adapters,参考http://code.google.com/p/android-serialport-api/wiki/android_to_rs232_guideline?tm=6。),连接后如下图:
编码:
android-serialport-api项目包装了串行接口的通讯,因此我们不需要关心jni的调用等一系列的过程。自带的sample实例,演示了怎样读取串行口的信号码,代码也比较简单,稍微修改拿过来使用即可。直接上代码
SerialApplication.java
package com.whyonly.serial;
import java.io.File;
import java.io.IOException;
import java.security.InvalidParameterException;
import android.app.Application;
import android.content.SharedPreferences;
import android.location.Location;
import android.preference.PreferenceManager;
import android.util.Log;
import android_serialport_api.SerialPort;
import android_serialport_api.SerialPortFinder;
public class SerialApplication extends Application{
private static final String TAG = "SerialApplication";
private SharedPreferences mPrefs;
@Override
public void onCreate(){
Log.d(TAG,"load....");
super.onCreate();
//will save the values to Preference later.
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
}
public SharedPreferences getmPrefs() {
return mPrefs;
}
public String getUserId() {
// TODO Auto-generated method stub
return null;
}
//for serial port
public SerialPortFinder mSerialPortFinder = new SerialPortFinder();
private SerialPort mSerialPort = null;
public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {
if (mSerialPort == null) {
/* Read serial port parameters */
//SharedPreferences sp = getSharedPreferences("android_serialport_api.sample_preferences", MODE_PRIVATE);
SharedPreferences sp = ((SerialApplication)this.getApplicationContext()).getmPrefs();
String path = sp.getString("DEVICE", "");
int baudrate = Integer.decode(sp.getString("BAUDRATE", "-1"));
/* Check parameters */
if ( (path.length() == 0) || (baudrate == -1)) {
throw new InvalidParameterException();
}
/* Open the serial port */
mSerialPort = new SerialPort(new File(path), baudrate, 0);
}
return mSerialPort;
}
public void closeSerialPort() {
if (mSerialPort != null) {
mSerialPort.close();
mSerialPort = null;
}
}
}
MainActivity.java
package com.whyonly.serial;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private USBSerialHelper usbSerialHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
usbSerialHelper = new USBSerialHelper(MainActivity.this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void flag(int onoff) {
//the message returned from serial port, do anything you want.
Log.d(TAG,"onoff:"+onoff);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG,"onDestroy()");
stopUSBSerial();
}
private void stopUSBSerial() {
if(usbSerialHelper != null){
usbSerialHelper.onDestroy();
}
}
}
USBSerialHelper.java
package com.whyonly.serial;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;
import android_serialport_api.SerialPort;
public class USBSerialHelper {
private MainActivity activity;
protected SerialApplication mApplication;
protected SerialPort mSerialPort;
protected OutputStream mOutputStream;
private InputStream mInputStream;
private ReadThread mReadThread;
public USBSerialHelper(final MainActivity mActivity){
this.activity = mActivity;
mApplication = (SerialApplication) mActivity.getApplication();
Preferences.saveUSBSetting(mActivity);
start();
}
public void start(){
try {
mSerialPort = mApplication.getSerialPort();
mOutputStream = mSerialPort.getOutputStream();
mInputStream = mSerialPort.getInputStream();
/* Create a receiving thread */
mReadThread = new ReadThread();
mReadThread.start();
} catch (SecurityException e) {
DisplayError(R.string.error_security);
} catch (IOException e) {
DisplayError(R.string.error_unknown);
} catch (InvalidParameterException e) {
DisplayError(R.string.error_configuration);
}
}
private void DisplayError(int resourceId) {
DialogUtil.showWarningDialog(activity, resourceId);
}
private String lastStatus = "";//1:flag off;2:flag on;0 power off
private void onDataReceived(final byte[] buffer, final int size) {
activity.runOnUiThread(new Runnable() {
public void run() {
//receive serial number from usb serial device.
String signal = new String(buffer, 0, size);
if(signal.length()>0){
String status = signal.substring(0,1);
if(!status.equals("0") && !lastStatus.equals(status)){
lastStatus = status;
if(status.equals("1")){//flag on status
activity.flag(1);
}else if(status.equals("2")){//flag off status
activity.flag(0);
}
}
}
}
});
}
public void onDestroy() {
if (mReadThread != null)
mReadThread.interrupt();
mApplication.closeSerialPort();
mSerialPort = null;
}
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
while(!isInterrupted()) {
int size;
try {
byte[] buffer = new byte[64];
if (mInputStream == null) return;
size = mInputStream.read(buffer);
if (size > 0) {
onDataReceived(buffer, size);
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
}
Preferences.java
package com.whyonly.serial;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
public class Preferences {
public static void saveUSBSetting(Context activity){
SharedPreferences pref = getAppPrefs(activity);
Editor editor = pref.edit();
editor.putString("DEVICE", "/dev/ttyUSB0");
editor.putString("BAUDRATE", "9600");
editor.commit();
}
public static SharedPreferences getAppPrefs(Context context) {
return ((SerialApplication)context.getApplicationContext()).getmPrefs();
}
}
DialogUtil.java
package com.whyonly.serial;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
public class DialogUtil {
public static void showWarningDialog(Context context,int messageid){
showWarningDialog(context,context.getResources().getString(messageid));
}
public static void showWarningDialog(Context context,String message){
String warningTitle = context.getResources().getString(R.string.defaultWarningTitle);
String warningButtonName = context.getResources().getString(R.string.defaultWarningButton);
showWarningDialog(context,warningTitle,message,warningButtonName);
}
private static void showWarningDialog(Context context,String title,String message,String positive){
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(title).setMessage(message);
builder.setPositiveButton(positive, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
}
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">serial</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string name="defaultWarningTitle">Taxi Driver</string>
<string name="defaultWarningButton">Yes</string>
<string name="error_configuration">Please configure your serial port first.</string>
<string name="error_security">You do not have read/write permission to the serial
port.</string>
<string name="error_unknown">The serial port can not be opened for an unknown
reason.</string>
</resources>
如需下载整个工程的代码,请到本人的资源列表(下载)。另外,本代码只供学习之用,因此比较简单,不能适用于于所有的串行情况,如果需要应用于工业,请自行处理。