背景
全志平台Android4.4系统
公司原有的wince显示屏已经不能满足公司业务需求,使用android系统开发我司下一代产品。
由于android系统功能强大,可应用的范围不止步于显示屏一个产品。为考虑产品的可维护性,现重新设计一套系统框架,以满足开发项目的需求。
架构图
描述
考过驾照的都知道一套流程,科目二科目三是需要上传学时的,到省平台审核到学时到一定时长才能预约考试
主要制定了和终端MCU模块的通信,以及按照省平台的要求和平台进行tcp的通信。
本篇着重描述MUC通信过程
代码走向
myApp-----------
动态注册一个广播MyReceiver ,同时另一个App发送MCU请求
IntentFilter updateIntent = new IntentFilter();
updateIntent.addAction(ACTION_00_01);// mcu信息查询
updateIntent.addAction(ACTION_10_00);// 实时信息
updateIntent.addAction(ACTION_10_17);// 读取身份证
updateIntent.addAction(ACTION_20_02);// 读IC卡
mCardBroadcast = new Hst55Receiver();
registerReceiver(mCardBroadcast, updateIntent);
/* 打包发送 */
public void handOutCommand(Context context) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setAction(Constant.MCU_SEND_ACTION);
/*Log.i("MCUCMD","test_data");
Log.i("MCUCMD",StringUtils.byteToString(readHead())+"\n"+GetCmdLen());
for(byte b:readHead()){
Log.i("MCUCMD",b+"");
}*/
intent.putExtra("size", GetCmdLen());
intent.putExtra("data", readHead());
intent.putExtra("reSend", reSend);
context.sendBroadcast(intent, null);
}
在一个app启动时,也启动了另外一个app的service
APPlication
if (isHst55Running == false) {
CatchApplication.showLog("主界面启动hst55");
HelpFuns.StartExternalService(context, "com.hst.cz.hst55", "com.hst.cz.hst55.ServiceRun");
}
<service
android:name="com.hst.cz.hst55.ServiceRun"
android:exported="true" >//这属性表明了支持另外的应用启动这个服务
</service>
恰好这个service里面是动态的注册了广播MCU请求广播
try {
getSerialPort();// 获取端口
mOutputStream = mSerialPort.getOutputStream();// 获取输出流
mInputStream = mSerialPort.getInputStream();// 获取输入流
/* Create a receiving thread */
mReadThread = new ReadThread();// 创建线程
mReadThread.start();// 开始运行
} catch (SecurityException e) {
} catch (IOException e) {
} catch (InvalidParameterException e) {
}
if (mSerialPort != null) {
IntentFilter filter = new IntentFilter();
filter.addAction(Constant.MCU_SEND_ACTION); // 添加动态广播的Action
sendReceiver.setOutputStream(mOutputStream, getApplicationContext());
registerReceiver(sendReceiver, filter);//然后,receiver接受到了MCU请求,开始和MCU模块通信
}
里面的OutputStream是程序对mcu的写入流
SerialPort
{
private FileOutputStream mFileOutputStream;
public SerialPort(File device, int baudrate, int flags)
{
/* 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);//这个open方法是通过jni访问底层MCU
if (mFd == null)
{
Log.e(TAG, "native open returns null");
// throw new IOException();
}
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
}
service也会开启线程来轮询MCU发回来的信息
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
byte[] buffer = new byte[2048];
int size = 0;
byte[] bufferTemp = new byte[2048];
int sizeTemp = 0;
while (!isInterrupted())// 串口如果有数据
{
try {
if (mInputStream == null)
return;
sizeTemp = mInputStream.read(bufferTemp, 0, 2000);// 读取
if (sizeTemp > 0) {
if (size + sizeTemp <= buffer.length) {
System.arraycopy(bufferTemp, 0, buffer, size, sizeTemp);
size += sizeTemp;
onDataReceived(buffer, size);// 转发
size = 0;
} else {
size = 0;
}
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
也会开启线程来给最初调用最初的app注册的接收者
new Thread() {
public void run() {
while (true) {
while (comCmdArray.size() > 0) {
McuCmd tmp = comCmdArray.get(0);
if (tmp != null) {
handOutCommand(tmp);//发送广播
}
comCmdArray.remove(0);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
请求App的MyReceiver的定义如下
public class Hst55Receiver extends BroadcastReceiver {
private static HandleCmdMcu handleCmdMcu = new HandleCmdMcu();
@Override
public void onReceive(Context context, Intent intent) {
handleCmdMcu.putIntent(intent, context);
}
}
public void putIntent(Intent intent, Context context) {
int size = intent.getIntExtra("size", 0);
if (size > 0) {
setContext(context);
McuCmd cmd = new McuCmd();
byte hp[] = intent.getByteArrayExtra("data");
cmd.initStmCmd(hp, size);
McuHandleCmd(cmd);//从这里即开始了接口回调
}
}
接口回调
/*
* 电源设备管理
*/
private void getCardInfo(McuCmd cmd) {
GetCardInfo.getCardInfo(context, cmd);
if (mGetCardInfoLintener != null) {
mGetCardInfoLintener.getCardInfo();
}
}
@Override
public void McuHandleCmd(McuCmd cmd) {
switch (cmd.GetSubOrder()) {
case 0x02: {
getCardInfo(cmd);
}
break;
}
}
UI界面在回调,显示卡片信息