Android 12.0 工厂模式增加串口功能测试
最近接到项目需求需要增加一个串口功能测试项,具体修改参考如下:
1./vendor/freeme/packages/apps/FreemeFactoryTest/res/values/strings.xml
+ <string name="uhf_label">UART</string>
+ <string name="uhf_hint">Uart data to send.</string>
+ <string name="send_transmit_power_data">Send</string>
2./vendor/freeme/packages/apps/FreemeFactoryTest/res/layout/uhf.xml
<?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:background="@drawable/main_background"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large"
android:text="@string/uhf_hint" />
<Button
android:id="@+id/send_transmit_power"
android:text="@string/send_transmit_power_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:hint="Uart data to send."
android:textSize="20sp"
android:id="@+id/get_transmit_power">
</TextView>
</LinearLayout>
<include layout="@layout/common_bottom_bar"/>
</LinearLayout>
3./vendor/freeme/packages/apps/FreemeFactoryTest/AndroidManifest.xml
+ <activity
+ android:name=".serial.UHF"
+ android:label="@string/uhf_label"
+ android:screenOrientation="portrait" />
4./vendor/freeme/packages/apps/FreemeFactoryTest/jni/com_freeme_factory_serial_SerialPort.cpp
#include "jni.h"
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include <strings.h>
#include "android/log.h"
static const char *TAG="serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
#ifndef _Included_com_freeme_factory_serial_SayHello
#define _Included_com_freeme_factory_serial_SayHello
#ifdef __cplusplus
extern "C" {
#endif
int fd;
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;
}
}
int set_opt(jint nBits, jchar nEvent, jint nStop ,speed_t speed)
{
LOGE("set_opt: nBits=%d, nEvent=%c, nStop=%d", nBits, nEvent, nStop);
struct termios newtio;
if(tcgetattr(fd, & newtio) != 0)
{
LOGE("setup serial failure");
return -1;
}
bzero( & newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD;
switch(nBits)
{
case 7:
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |= CS8;
break;
default:
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |= CS8;
break;
}
switch(nEvent)
{
case 'o':
case 'O':
newtio.c_cflag |= (PARODD | PARENB);
newtio.c_iflag |= INPCK;
break;
case 'e':
case 'E':
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
newtio.c_iflag |= INPCK;
break;
case 'N':
case 'n':
newtio.c_cflag &= ~PARENB;
break;
default:
newtio.c_cflag &= ~PARENB;
break;
}
cfsetispeed(&newtio, speed);
cfsetospeed(&newtio, speed);
switch(nStop)
{
case 1:
newtio.c_cflag &= ~CSTOPB;
break;
case 2:
newtio.c_cflag |= CSTOPB;
break;
default:
newtio.c_cflag &= ~CSTOPB;
break;
}
newtio.c_cc[VTIME] = 100;
newtio.c_cc[VMIN] = 0;
tcflush(fd, TCIFLUSH);
if(tcsetattr(fd, TCSANOW, & newtio) != 0)
{
LOGE("options set error");
close(fd);
return -1;
}
LOGE("options set success");
return 1;
}
/*
* Class: android_serialport_SerialPort
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_com_freeme_factory_serial_SerialPort_open
(JNIEnv *env, jobject thiz, jstring path, jint baudrate,
jint databits, jint stopbits, jchar parity)
{
speed_t speed;
jobject mFileDescriptor;
{
speed = getBaudrate(baudrate);
LOGE("set_opt: baudrate=%d", baudrate);
LOGE("set_opt: nSpeed=%d", speed);
if (speed == -1)
{
/* TODO: throw an exception */
LOGE("Invalid baudrate");
return NULL;
}
}
/* Opening device */
{
jint flags = 0;
jboolean iscopy;
const char *path_utf = env->GetStringUTFChars(path, &iscopy);
LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
fd = open(path_utf, O_RDWR|O_NOCTTY|O_NONBLOCK);
LOGD("open() fd = %d", fd);
env->ReleaseStringUTFChars(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, &cfg))
{
LOGE("tcgetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
cfmakeraw(&cfg);
//cfsetispeed(&cfg, speed);
//cfsetospeed(&cfg, speed);
set_opt(databits, parity, stopbits,speed);
//if (tcsetattr(fd, TCSANOW, &cfg))
//{
//LOGE("tcsetattr() failed");
//close(fd);
/* TODO: throw an exception */
//return NULL;
//}
}
/* Create a corresponding file descriptor */
{
jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
mFileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
env->SetIntField(mFileDescriptor, descriptorID, (jint)fd);
}
return mFileDescriptor;
}
/*
* Class: cedric_serial_SerialPort
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_freeme_factory_serial_SerialPort_close
(JNIEnv *env, jobject thiz)
{
jclass SerialPortClass = env->GetObjectClass(thiz);
jclass FileDescriptorClass = env->FindClass("java/io/FileDescriptor");
jfieldID mFdID = env->GetFieldID(SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = env->GetFieldID(FileDescriptorClass, "descriptor", "I");
jobject mFd = env->GetObjectField(thiz, mFdID);
jint descriptor = env->GetIntField(mFd, descriptorID);
LOGD("close(fd = %d)", descriptor);
close(descriptor);
}
#ifdef __cplusplus
}
#endif
#endif
5./vendor/freeme/packages/apps/FreemeFactoryTest/jni/Android.mk
LOCAL_SRC_FILES := \
+ com_freeme_factory_serial_SerialPort.cpp
6./vendor/freeme/packages/apps/FreemeFactoryTest/src/com/freeme/factory/FactoryTest.java
+import com.freeme.factory.serial.UHF;
public void testItem(int item) {
+ case TestConfig.TEST_ITEM_UHF:
+ intent.setClass(this, UHF.class);
+ startActivityForResult(intent, item);
+ break;
7./vendor/freeme/packages/apps/FreemeFactoryTest/src/com/freeme/factory/config/TestConfig.java
+ public static final boolean TEST_EN_UHF = true;
+ public static final int TEST_ITEM_UHF = 62;
private static final int[] kTestItems_Full = {
+ TEST_ITEM_UHF,
static {
/* -- TODO: Custom */
+ __disable_feature(TEST_ITEM_UHF, TEST_EN_UHF);
public static String getNameByItemId(Context c, int id) {
+ case TEST_ITEM_UHF:
+ resid = R.string.uhf_label;
+ break;
8./vendor/freeme/packages/apps/FreemeFactoryTest/src/com/freeme/factory/serial/SerialPort.java
package com.freeme.factory.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";
/*
* Do not remove or rename the field mFd: it is used by native method close();
*/
private FileDescriptor mFd;
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
public SerialPort(File device, int baudrate) throws SecurityException, IOException {
mFd = open(device.getAbsolutePath(), baudrate);
if (mFd == null) {
Log.e(TAG, "native open returns null");
throw new IOException();
}
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
mFd = open(device.getAbsolutePath(), baudrate, 8, 1, 'N');
if (mFd == null) {
Log.e(TAG, "native open returns null");
throw new IOException();
}
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
public SerialPort(File device, int baudrate, int dataBits, int stopBits, char parity) throws SecurityException, IOException {
mFd = open(device.getAbsolutePath(), baudrate, dataBits, stopBits, parity);
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);
private native static FileDescriptor open(String path, int baudrate, int flags);
private native static FileDescriptor open(String path, int baudrate, int dataBits, int stopBits, char parity);
public native void close();
static {
System.loadLibrary("jni_factory_speaker");
}
}
9./vendor/freeme/packages/apps/FreemeFactoryTest/src/com/freeme/factory/serial/UHF.java
package com.freeme.factory.serial;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.RadioButton;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import com.freeme.factory.base.BaseTest;
import com.freeme.factory.FactoryTest;
import com.freeme.factory.R;
public class UHF extends BaseTest{
private static final String TAG = "UHF";
private static final int MSG_TRANSMIT_POWER = 0;
private static boolean isFlagSerial = false;
private TextView mGetTransmitPower ;
private Button mSendTransmitPower ;
private FileOutputStream mOutputStream;
private FileInputStream mInputStream;
private SerialPort mSerialPort;
private String strData = "";
private byte[] get_transmit_power_cmd = {input data};
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TRANSMIT_POWER:
mSendTransmitPower.setEnabled(true);
sendString(byteToStr(get_transmit_power_cmd, get_transmit_power_cmd.length));
break;
default:
break;
}
Log.e(TAG, "handleMessage---> " + msg.what);
receive(msg.what);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.uhf);
mGetTransmitPower = (TextView) findViewById(R.id.get_transmit_power);
mSendTransmitPower = (Button) findViewById(R.id.send_transmit_power);
mSendTransmitPower.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mSendTransmitPower.setEnabled(false);
mGetTransmitPower.setText("");
mHandler.sendEmptyMessageDelayed(MSG_TRANSMIT_POWER, 1000);
}
});
//writeFile("/sys/switch_power/uhf_power", "1");
SetupSerial();
testActionCompleted(false);
}
private void sendString(String sendData) {
if (!isFlagSerial || mOutputStream == null) {
return;
}
try {
Log.d(TAG, "sendString ---> sendData " + sendData );
mOutputStream.write(hex2byte(sendData));
mOutputStream.flush();
Toast.makeText(getApplicationContext(), "=> " + getFileAddSpace(sendData), Toast.LENGTH_SHORT).show();
Log.e(TAG, "=> " + getFileAddSpace(sendData));
} catch (IOException e) {
e.printStackTrace();
}
}
private void receive(int type) {
if (isFlagSerial) {
try {
byte[] readData = new byte[4096];
if (mInputStream == null) {
return;
}
int size = mInputStream.read(readData);
Log.d(TAG, "receive---> size " + size );
if (size > 0) {
strData = byteToStr(readData, size);
strData = getFileAddSpace(strData);
Log.d(TAG, "receive---> strData " + strData);
onDataReceived(strData, type);
testActionCompleted(true);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void onDataReceived(String strData, int type) {
runOnUiThread(new Runnable() {
public void run() {
if (mGetTransmitPower != null && type == 0) {
mGetTransmitPower.append(strData);
Log.e(TAG, "<= " + getFileAddSpace(strData));
}
}
});
}
private void SetupSerial() {
try {
mSerialPort = new SerialPort(new File("UART PATH"), 115200, 8, 1, 'N');
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
isFlagSerial = true;
Log.e(TAG, "SetupSerial---> " + mSerialPort);
if (mSerialPort != null) {
mInputStream = (FileInputStream) mSerialPort.getInputStream();
mOutputStream = (FileOutputStream) mSerialPort.getOutputStream();
Log.e(TAG, "SetupSerial---> mInputStream " + mInputStream);
Log.e(TAG, "SetupSerial---> mOutputStream " + mOutputStream);
}
}
private void writeFile(String psam_path, String val) {
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(psam_path);
if (fileWriter != null) {
fileWriter.write(val);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fileWriter != null) {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy...");
resetSerial();
super.onDestroy();
}
private void waitFor(int seconds) {
try {
Thread.sleep(seconds);
} catch (InterruptedException ignore) {
// ignore exception
}
}
private void resetSerial() {
isFlagSerial = false;
//writeFile("/sys/switch_power/uhf_power", "0");
//writeFile(PSAM_CONTROL1_PATH, "0");
}
private String getFileAddSpace(String replace) {
String regex = "(.{2})";
return replace.replaceAll(regex, "$1 ");
}
private static byte[] hex2byte(String hex) {
String digital = "0123456789ABCDEF";
String hex1 = hex.replace(" ", "");
char[] hex2char = hex1.toCharArray();
byte[] bytes = new byte[hex1.length() / 2];
byte temp;
for (int p = 0; p < bytes.length; p++) {
temp = (byte) (digital.indexOf(hex2char[2 * p]) * 16);
temp += digital.indexOf(hex2char[2 * p + 1]);
bytes[p] = (byte) (temp & 0xff);
Log.d(TAG,"hex2byte " + bytes[p]);
}
return bytes;
}
private static String byteToStr(byte[] b, int size) {
String ret = "";
for (int i = 0; i < size; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
private static String getSum16(byte[] msg, int length) {
long mSum = 0;
byte[] mByte = new byte[length];
for (byte byteMsg : msg) {
long mNum = ((long) byteMsg >= 0) ? (long) byteMsg : ((long) byteMsg + 256);
mSum += mNum;
}
for (int liv_Count = 0; liv_Count < length; liv_Count++) {
mByte[length - liv_Count - 1] = (byte) (mSum >> (liv_Count * 8) & 0xff);
}
return byteToStr(msg, length) + byteToStr(mByte, mByte.length).substring(byteToStr(mByte, mByte.length).length() - 4, byteToStr(mByte, mByte.length).length());
}
}
重新编译验证,修改生效,工厂模式已增加串口功能测试