背景
全志平臺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界面在回調,顯示卡片信息