The serial programming principle and realization way of Android development _android

Source: Internet
Author: User
Tags chmod int size
Referring to serial programming, we have to mention JNI, have to mention the file descriptor class in Javaapi: FileDescriptor. Below I separately to JNI, FileDescriptor as well as the serial port some knowledge point and the realization source code carries on the analysis explanation. Here is the main reference to open source project Android-serialport-api.

Serial programming needs to understand the basic knowledge: for serial port programming, we just have a series of serial settings, and then open the serial port, these operations we can refer to the Serial Debugging assistant source code for learning. In Java, if you want to achieve the ability to read and write the serial port only need to operate file Equipment class: FileDescriptor can, the other things are driven to complete without a lot of pipe! Of course, you want to know, it depends on the driver code. This is not intended to be a description of the driver, but only a brief explanation of how the application layer is implemented.

(i) JNI
About JNI article on the internet there are many, no longer explain, want to learn more about the friend can see the cloud stroll in the technical articles, write well, analysis is also very comprehensive, then in this humble text I emphasize 3 points:
1. How to package the compiled so file into the apk? (The method is very simple, directly in the engineering directory to create a new folder Libs/armeabi, copy so files to this directory)
2, name to pay attention to the place? (in the compiled so file, rename the file to: libfilename.so.) Where Filename.so is compiled into the file)
3, makefile File writing (needless to say, you can refer directly to the Package/apps directory to use JNI related items)
This is the key code:
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" > int fd;
speed_t speed;
Jobject Mfiledescriptor;

/* Check Arguments * *
{
Speed = Getbaudrate (baudrate);
if (speed = = 1) {
/* Todo:throw an exception * *
LOGE ("Invalid baudrate");
return NULL;
}
}

/* Opening Device * *
{
Jboolean iscopy;
const char *PATH_UTF = (*env)->getstringutfchars (env, Path, &iscopy);
LOGD ("Opening serial port%s with flags 0x%x", PATH_UTF, O_RDWR | flags);
FD = open (Path_utf, O_RDWR | flags);
LOGD ("open () fd =%d", FD);
(*env)->releasestringutfchars (env, Path, PATH_UTF);
if (fd = = 1)
{
/* Throw an exception * *
LOGE ("Cannot open port");
/* Todo:throw an exception * *
return NULL;
}
}

/* Configure Device * *
{
struct Termios cfg;
LOGD ("Configuring serial port");
if (Tcgetattr (FD, &AMP;CFG))
{
LOGE ("Tcgetattr () failed");
Close (FD);
/* Todo:throw an exception * *
return NULL;
}

Cfmakeraw (&AMP;CFG);
Cfsetispeed (&cfg, speed);
Cfsetospeed (&cfg, speed);

if (tcsetattr (FD, Tcsanow, &cfg))
{
LOGE ("tcsetattr () failed");
Close (FD);
/* Todo:throw an exception * *
return NULL;
}
}
</span>

(ii) Filedescritor
An instance of a file descriptor class is used as an opaque handle to a structure that is related to the base machine, which represents an open file, an open socket, or another source or receiver of bytes. The main practical purpose of a file descriptor is to create a fileinputstream or fileoutputstream that contains the structure. This is the description of the API, not very good understanding, in fact, can be simply understood as: Filedescritor is a file to read and write.
(iii) Implementation of serial communication details
1) Construction: Serialdemo Package Name: Org.winplus.serial, and in the engineering directory under the new JNI and Libs two folders and a org.winplus.serial.utils, as shown below:
2 Create a new class: Serialportfinder, add the following code:
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" >package org.winplus.serial.utils;

Import Java.io.File;
Import Java.io.FileReader;
Import java.io.IOException;
Import Java.io.LineNumberReader;
Import Java.util.Iterator;
Import Java.util.Vector;

Import Android.util.Log;

public class Serialportfinder {

private static final String TAG = "SerialPort";

Private vector<driver> mdrivers = null;

public class Driver {
Public Driver (string name, string root) {
Mdrivername = name;
Mdeviceroot = root;
}

Private String Mdrivername;
Private String Mdeviceroot;
Vector<file> mdevices = null;

Public vector<file> getDevices () {
if (mdevices = = null) {
Mdevices = new vector<file> ();
File dev = new file ("/dev");
file[] files = dev.listfiles ();
int i;
for (i = 0; i < files.length; i++) {
if (Files[i].getabsolutepath (). StartsWith (Mdeviceroot)) {
LOG.D (TAG, "Found new device:" + files[i]);
Mdevices.add (Files[i]);
}
}
}
return mdevices;
}

Public String GetName () {
return mdrivername;
}
}

Vector<driver> Getdrivers () throws IOException {
if (mdrivers = = null) {
Mdrivers = new vector<driver> ();
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 did 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<string> devices = new vector<string> ();
Parse each driver
Iterator<driver> Itdriv;
try {
Itdriv = Getdrivers (). iterator ();
while (Itdriv.hasnext ()) {
Driver Driver = Itdriv.next ();
iterator<file> 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<string> devices = new vector<string> ();
Parse each driver
Iterator<driver> Itdriv;
try {
Itdriv = Getdrivers (). iterator ();
while (Itdriv.hasnext ()) {
Driver Driver = Itdriv.next ();
iterator<file> 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 ());
}
}
</span>

The above class in the "Android-serialport-api Serial tool test essay" has detailed instructions, I will not say more.
3 new SerialPort class, this class is mainly used to load the so file, through JNI way to open the closed serial port
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" >package org.winplus.serial.utils;

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";

/*
* Do not remove or rename the field mfd:it be used by native method
* Close ();
*/
Private FileDescriptor mFd;
Private FileInputStream Mfileinputstream;
Private FileOutputStream Mfileoutputstream;

Public SerialPort (File device, int baudrate, int flags)
Throws SecurityException, IOException {

/* Check access Permission * *
if (!device.canread () | |!device.canwrite ()) {
try {
/* Missing read/write permission, trying to chmod the file * * *
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);
}

Getters and Setters
Public InputStream getInputStream () {
return mfileinputstream;
}

Public OutputStream Getoutputstream () {
return mfileoutputstream;
}

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

Public native void Close ();

static {
System.loadlibrary ("Serial_port");
}
}
</span>

4 Create a new MyApplication inheritance android.app.Application, used to initialize the serial port and close the serial port
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" >package org.winplus.serial;

Import Java.io.File;
Import java.io.IOException;
Import java.security.InvalidParameterException;

Import Org.winplus.serial.utils.SerialPort;
Import Org.winplus.serial.utils.SerialPortFinder;

Import android.content.SharedPreferences;

public class MyApplication extends Android.app.Application {
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);
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;
}
}
}
</span>

5 Create a new activity class inheriting abstract, mainly used to read the information of the serial port
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" >package org.winplus.serial;

Import java.io.IOException;
Import Java.io.InputStream;
Import Java.io.OutputStream;
Import java.security.InvalidParameterException;

Import Org.winplus.serial.utils.SerialPort;

Import android.app.Activity;
Import Android.app.AlertDialog;
Import Android.content.DialogInterface;
Import Android.content.DialogInterface.OnClickListener;
Import Android.os.Bundle;

Public abstract class Serialportactivity extends activity {
protected MyApplication mapplication;
protected SerialPort Mserialport;
protected OutputStream Moutputstream;
Private InputStream Minputstream;
Private Readthread Mreadthread;

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

/**
* Here's read to pay particular attention to, it will always wait for data, until the everlasting, lasting. If you want to determine whether to accept completion, only set the end of the identity, or for other special processing.
*/
Size = minputstream.read (buffer);
if (Size > 0) {
ondatareceived (buffer, size);
}
catch (IOException e) {
E.printstacktrace ();
Return
}
}
}
}

private void DisplayError (int ResourceID) {
Alertdialog.builder B = new Alertdialog.builder (this);
B.settitle ("Error");
B.setmessage (ResourceID);
B.setpositivebutton ("OK", new Onclicklistener () {
public void OnClick (Dialoginterface dialog, int which) {
SerialPortActivity.this.finish ();
}
});
B.show ();
}

@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Mapplication = (MyApplication) getapplication ();
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);
}
}

protected abstract void ondatareceived (final byte[] buffer, final int size);

@Override
protected void OnDestroy () {
if (mreadthread!= null)
Mreadthread.interrupt ();
Mapplication.closeserialport ();
Mserialport = null;
Super.ondestroy ();
}
}
</span>

6) Writing String.xml and baudrates.xml documents
To add in the String.xml file:
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" > <string name= "error_configuration" >please Configure your serial port first.</string>
<string name= "error_security" >you do not have read/write to the permission serial
<string name= "Error_unknown" >the serial port can not is opened for a unknown reason.</string>
</span>

Add in Baudrates.xml file
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" ><?xml version= "1.0" encoding= "Utf-8"?>
<resources>

<string-array name= "Baudrates_name" >
<item>50</item>
<item>75</item>
<item>110</item>
<item>134</item>
<item>150</item>
<item>200</item>
<item>300</item>
<item>600</item>
<item>1200</item>
<item>1800</item>
<item>2400</item>
<item>4800</item>
<item>9600</item>
<item>19200</item>
<item>38400</item>
<item>57600</item>
<item>115200</item>
<item>230400</item>
<item>460800</item>
<item>500000</item>
<item>576000</item>
<item>921600</item>
<item>1000000</item>
<item>1152000</item>
<item>1500000</item>
<item>2000000</item>
<item>2500000</item>
<item>3000000</item>
<item>3500000</item>
<item>4000000</item>
</string-array>
<string-array name= "Baudrates_value" >
<item>50</item>
<item>75</item>
<item>110</item>
<item>134</item>
<item>150</item>
<item>200</item>
<item>300</item>
<item>600</item>
<item>1200</item>
<item>1800</item>
<item>2400</item>
<item>4800</item>
<item>9600</item>
<item>19200</item>
<item>38400</item>
<item>57600</item>
<item>115200</item>
<item>230400</item>
<item>460800</item>
<item>500000</item>
<item>576000</item>
<item>921600</item>
<item>1000000</item>
<item>1152000</item>
<item>1500000</item>
<item>2000000</item>
<item>2500000</item>
<item>3000000</item>
<item>3500000</item>
<item>4000000</item>
</string-array>

</resources>
</span>

7 Start writing interface: Add two edit boxes to the Main.xml layout file, one to send commands and one to receive commands:
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" ><?xml version= "1.0" encoding= "Utf-8"?>
<linearlayout xmlns:android= "http://schemas.android.com/" Apk/res/android "
android:layout_width=" fill_parent
android:layout_height= "fill_parent"
Android:o rientation= "vertical" >

<edittext
android:id= "@+id/edittextreception"
Android:layout_width= " Fill_parent "
android:layout_height=" Fill_parent
android:layout_weight= "1"
android:gravity= "Top"
A ndroid:hint= "Reception"
Android:isscrollcontainer= "true"
android:scrollbarstyle= "Insideoverlay" >
& Lt;/edittext>

<edittext
android:id= "@+id/edittextemission"
android:layout_width= "Fill_paren" T "
android:layout_height=" wrap_content "
android:hint=" emission "
Android:lines=" 1 ">
</editte Xt>

</LinearLayout>
</span>

8 The implementation of the Serialdemoactivity class:
Copy Code code as follows:

<span style= "FONT-SIZE:18PX;" >package org.winplus.serial;

Import java.io.IOException;

Import Android.os.Bundle;
Import android.view.KeyEvent;
Import Android.widget.EditText;
Import Android.widget.TextView;
Import Android.widget.TextView.OnEditorActionListener;

public class Serialdemoactivity extends serialportactivity{
EditText mreception;

@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.main);

Settitle ("loopback test");
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));
}
}
});
}
}
</span>

Writing here, the code is basically finished. The following is to achieve the function of JNI layer, to achieve JNI, you must first generate the header file, header file generation is very simple, we compile the project, in the terminal input Javah Org.winplus.serial.utils.SerialPort will generate the header file: Org_ Winplus_serial_utils_serialport.h, the name of this header file can be arbitrarily named. We name it: SerialPort.h Copy to the new directory JNI, new serialport.c file, the code of these two files will not be posted. Go directly to the uploaded code.
(iv) the application of serial port, can realize scanning head, fingerprint identification and other peripheral USB serial port characteristics of the application
Also quite cumbersome, the above is only the open source project Android-serialport-api to understand this project please click here! That's it, it's too late to see Duke!
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.