您的位置:首页 > 移动开发 > Android开发

Android4.4 RIL的AT命令增加流程

2015-01-17 23:03 295 查看
首先,感谢http://blog.csdn.net/guoleimail/article/details/41649537这篇博文的出现,文中不仅列出了大部分要修改的代码,还给出了原理阐述。本文作为该博文的补充,将所有修改的地方全部给出,由上层应用逐级往下调用,但类之间的关系不作说明,想弄清楚的朋友可以看看下面的链接
http://blog.csdn.net/youbang321/article/details/7803023
http://www.elexcon.com/news/54715.html
http://blog.csdn.net/arnoldlu/article/details/9189939
http://blog.sina.com.cn/s/blog_682793a50100jeo5.html
http://www.cnblogs.com/jesse123/p/3167519.html
http://www.redwolf-blog.com/?p=966
http://yelinsen.iteye.com/blog/848137
http://yelinsen.iteye.com/blog/848129
http://blog.163.com/fengxuedong_fxd/blog/static/71926306201181933443646/
http://blog.csdn.net/forlong401/article/details/5403379

frameworks\base\telephony\java\android\telephony\TelephonyManager.java

在尾部增加

/**
* Send AT command via sync tunnel, it should return result until the command execute completely.
* @param cmd AT command
* @param time max time for executing at command, unit is ms.
* return is result of AT.
*/
public String AtCommandSendSync(String cmd, int time){
try {
return getITelephony().AtCommandSendSync(cmd, time);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
}

/**
* Send AT command via unsync tunnel, it should return true or false when AT command has been send.
* @param cmd AT command
* return boolean
*/
public boolean AtCommandSendUnSync(String cmd){
try {
return getITelephony().AtCommandSendUnSync(cmd);
} catch (RemoteException ex) {
return false;
} catch (NullPointerException ex) {
return false;
}
}

frameworks\base\telephony\java\com\android\internal\telephony\ITelephony.aidl

在尾部增加

/**
* Execute AT command via unsync tunnel
* @param cmd AT command to execute
* execute successfully return true,
* AT command result will send by broadcast with action android.intent.action.AtCommand.result
*/
boolean AtCommandSendUnSync(String cmd);

/**
* Execute AT command via sync tunnel
* @param cmd AT command, time is timeout of process unit is ms
*/
String AtCommandSendSync(String cmd, int time);

frameworks\base\telephony\java\com\android\internal\telephony\RILConstants.java

在尾部增加

int RIL_REQUEST_SEND_AT = 114;
...
int RIL_UNSOL_RESPONSE_TUNNEL_AT = 1038;

注意,两个id必须在已有的基础上按顺序递增添加。

frameworks\opt\telephony\src\java\com\android\internal\telephony\Phone.java

在尾部增加

//Add AT tunnel
void sendAtToModem(String at_string, Message result);



frameworks\opt\telephony\src\java\com\android\internal\telephony\PhoneBase.java

增加一个成员变量,表示主动上发的消息

protected static final int EVENT_UNSOL_AT_TUNNEL                = 31;


在尾部增加

@Override
public void sendAtToModem(String at_string, Message result){
Log.e(LOG_TAG, "sendAtToModem Error! This function is only for GSMPhone.");
}



frameworks\opt\telephony\src\java\com\android\internal\telephony\PhoneProxy.java

在尾部增加

@Override
public void sendAtToModem(String at_string, Message result) {
mActivePhone.sendAtToModem(at_string, result);
}


如果是2G网络,修改frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GSMPhone.java

如果是3G网络,比如CDMA2000,修改frameworks\opt\telephony\src\java\com\android\internal\telephony\cdma\CDMAPhone.java

在构造函数增加

mCi.registerForAtTunnel(this, EVENT_UNSOL_AT_TUNNEL, null);


在dispose函数中添加

mCi.unregisterForAtTunnel(this);

在handleMessage中添加

case EVENT_UNSOL_AT_TUNNEL:
ar = (AsyncResult)msg.obj;
log("receive EVENT_UNSOL_AT_TUNNEL done");
if (ar.exception == null) {
String result = (String)ar.result;
log("result = " + result);
sendResultBroadcast(result);
}
break;

在尾部添加

private void sendResultBroadcast(String result) {
Intent intent = new Intent("android.intent.action.AtCommand.result");
intent.putExtra("result", result);
mContext.sendBroadcast(intent);
}

@Override
public void sendAtToModem(String at_string, Message result) {
mCi.sendAtToModem(at_string, result);
}


frameworks\opt\telephony\src\java\com\android\internal\telephony\CommandsInterface.java

在尾部添加

//Add for AT tunnel to modem
void sendAtToModem(String at_string, Message result);
void registerForAtTunnel(Handler h, int what, Object obj);
void unregisterForAtTunnel(Handler h);

frameworks\opt\telephony\src\java\com\android\internal\telephony\sip\SipCommandInterface.java

在尾部添加

@Override
public void sendAtToModem(String at_string, Message result){

}

frameworks\opt\telephony\src\java\com\android\internal\telephony\test\SimulatedCommands.java

在尾部添加

@Override
public void sendAtToModem(String at_string, Message result){

}

frameworks\opt\telephony\src\java\com\android\internal\telephony\BaseCommands.java

import android.os.Message;

添加一个成员变量,用于注册处理主动上发的消息

protected Registrant mAtTunnelRegistrant;


在尾部添加

/**
* Sets the handler for AT sync tunnel
*
* @param h Handler for notification message.
* @param what User-defined message code.
* @param obj User object.
*/
@Override
public void registerForAtTunnel(Handler h, int what, Object obj) {
mAtTunnelRegistrant = new Registrant(h, what, obj);
}

@Override
public void unregisterForAtTunnel(Handler h) {
mAtTunnelRegistrant.clear();
}

@Override
public void sendAtToModem(String at_string, Message result) {
}

frameworks\opt\telephony\src\java\com\android\internal\telephony\RIL.java

在processSolicited中添加

case RIL_REQUEST_SEND_AT: ret =  responseString(p); break;

在processUnsolicited中添加

case RIL_UNSOL_RESPONSE_TUNNEL_AT: ret =  responseString(p); break;
case RIL_UNSOL_RESPONSE_TUNNEL_AT: {
if (RILJ_LOGD) unsljLogRet(response, ret);

if (mAtTunnelRegistrant != null) {
mAtTunnelRegistrant.notifyRegistrant(
new AsyncResult (null, ret, null));
}
break;
}

在requestToString中添加

case RIL_REQUEST_SEND_AT: return "SEND_AT";

在responseToString中添加

case RIL_UNSOL_RESPONSE_TUNNEL_AT: return "RESPONSE_TUNNEL_AT";

在尾部添加

@Override
public void sendAtToModem(String at_string, Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_AT, result);

rr.mParcel.writeString(at_string);

if (RILJ_LOGD) riljLog(rr.serialString() +
"> sendAtToModem: " + requestToString(rr.mRequest)
+ " at_string: " + at_string);

send(rr);
}

packages\services\Telephony\src\com\android\phone\PhoneInterfaceManager.java

在尾部添加

/**
* Send AT command via unsync tunnel, it should return true or false when AT command has been send.
* @param cmd AT command
* return boolean
*/
public boolean AtCommandSendUnSync(String cmd){
Log.d(LOG_TAG, "AtCommandSendUnSync send at command" + cmd);
Phone phone = mPhone;
if (phone == null) return false;

final AtSendThread atSendThread = new AtSendThread("AtCommandSendUnSync", cmd, false);
atSendThread.start();
String result =  atSendThread.sendAt(phone);
sendResultBroadcast(result);
if (result != null && result.length() > 1 && result.contains("OK")) {
return true;
} else {
return false;
}
}

private void sendResultBroadcast(String result) {
Intent intent = new Intent("android.intent.action.AtCommand.result");
intent.putExtra("result", result);
mApp.getPhone().getContext().sendBroadcast(intent);
}

/**
* Send AT command via sync tunnel, it should return result until the command execute completely.
* @param cmd  AT command
* @param time max time for executing at command, unit is ms.
* return is result of AT.
*/
public String AtCommandSendSync(String cmd, int time){
Log.d(LOG_TAG, "AtCommandSendSync send at command" + cmd + " time = " + time);
Phone phone = mPhone;
if (phone == null) return null;

final AtSendThread atSendThread = new AtSendThread("AtCommandSendSync", cmd, true, time);
atSendThread.start();
return atSendThread.sendAt(phone);
}

private static class AtSendThread extends Thread {
private String mCmd;
private long mMaxTimeExcute;
private String mAtResult;
private boolean mIsSync;
private Handler mAtHandler;
private boolean mSuccess = false;

private static final int SEND_AT_VIA_TUNNEL = 1;

AtSendThread(String name, String cmd, boolean isSync) {
super(name);
mCmd = cmd;
mAtResult = null;
mMaxTimeExcute = 5;
mIsSync = false;
}

AtSendThread(String name, String cmd, boolean isSync, int max) {
super(name);
mCmd = cmd;
mMaxTimeExcute = (long)(max/100);
mAtResult = null;
mIsSync = isSync;
}

public void run() {
Looper.prepare();
synchronized (AtSendThread.this) {
mAtHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
AsyncResult ar = (AsyncResult) msg.obj;
switch (msg.what) {
case SEND_AT_VIA_TUNNEL:
Log.d("AtSyncThread", "SEND_AT_VIA_TUNNEL");
synchronized (AtSendThread.this) {
if (ar.exception == null && ar.result != null) {
mAtResult = ar.result.toString();
}else{
mAtResult = "Error AT response";
}
mSuccess = true;
AtSendThread.this.notifyAll();
}
break;
}
}
};
AtSendThread.this.notifyAll();
}
Looper.loop();
}

synchronized String sendAt(Phone phone) {
while (mAtHandler == null) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
Message callback = Message.obtain(mAtHandler, SEND_AT_VIA_TUNNEL);
Log.e(LOG_TAG, "mCmd = " + mCmd);
phone.sendAtToModem(mCmd, callback);
while (!mSuccess) {
try {
Log.d("AtSendThread", "wait for done");
mMaxTimeExcute--;
wait(100);
if (mMaxTimeExcute == 0) {
mAtResult = "Error AT TIME OUT";
return mAtResult;
}
} catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
Log.d("AtSendThread", "successfull! result = " + mAtResult);
return mAtResult;
}
}


hardware\ril\include\telephony\ril.hhardware\ril\reference-ril\ril.h

添加两条命令码

#define RIL_REQUEST_SEND_AT 114
...
#define RIL_UNSOL_RESPONSE_TUNNEL_AT 1038

注意要与上面的RILConstants.java添加的相同

hardware\ril\libril\ril_commands.h

在尾部添加

{RIL_REQUEST_SEND_AT, dispatchString, responseString},

hardware\ril\libril\ril_unsol_commands.h

在尾部添加

{RIL_UNSOL_RESPONSE_TUNNEL_AT, responseString, WAKE_PARTIAL},

hardware\ril\reference-ril\reference-ril.c

在onRequest中添加处理RILJ发送过来的AT命令

case RIL_REQUEST_SEND_AT:
requestSendAt(data, datalen, t);
break;


static void requestSendAt(void *data, size_t datalen, RIL_Token t)
{
int err;
char *cmd;
char *response;
ATResponse *p_response = NULL;

RLOGD("requestSendAt data = %s, datalen = %d", (char *)data, datalen);
assert (datalen != 1);

asprintf(&cmd, "%s", (char *)data+1);
response = (char *)data;
if(response[0] == '1'){
err = at_send_command(cmd, &p_response);
}else if(response[0] == '2'){
err = at_send_command_singleline(cmd, "", &p_response);
}else if(response[0] == '3'){
err = at_send_command_numeric(cmd, &p_response);
}else if(response[0] == '4'){
err = at_send_command_multiline(cmd, "", &p_response);
}else{
err = -1;
}

if (cmd != NULL) {
free(cmd);
cmd = NULL;
}

RLOGD("requestSendAt err = %d, p_response->success = %d", err, p_response->success);
if (p_response->p_intermediates == NULL) {
RLOGD("requestSendAt finalResponse = %s", p_response->finalResponse);
asprintf(&response, "%s\r\n", p_response->finalResponse);
} else {
RLOGD("requestSendAt finalResponse = %s, p_intermediates->line = %s", p_response->finalResponse, p_response->p_intermediates->line);
asprintf(&response, "%s, %s\r\n", p_response->p_intermediates->line, p_response->finalResponse);
}
if (err < 0 || p_response->success == 0)
/*Maybe the at command from user is invalid, we also send successful response to user, the result should handle it itself*/
goto error;

RLOGD("requestSendAt success, response = %s, len = ", response, strlen(response));
RIL_onRequestComplete(t, RIL_E_SUCCESS, response, strlen(response));
free(response);
return;

error:
RLOGE("ERROR: requestSendAt failed, response = %d", response);
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
free(response);
}

注意,你需要知道下发的命令要不要求返回数据,如果不要求一般用at_send_command即可,要求就用at_send_command_singleline。这个不能出错,否则RILJ和RILC之间的socket会断开。

在onUnsolicited中添加主动上发消息的处理

else{
  if(!s) {
   line = strdup(s);
   memset(atReadStorage, 0, 1024);
   
   strncpy(atReadStorage, line, strlen(line));
   p = atReadStorage + strlen(line);
   
   if(!sms_pdu) {
    strncpy(p, sms_pdu, strlen(sms_pdu));
   }
   
   RIL_onUnsolicitedResponse (
    RIL_UNSOL_RESPONSE_TUNNEL_AT,
    atReadStorage, strlen(atReadStorage));
   free(line);
  }
    }

注意,这个要放在已有的if-else语句的最后,目的是把过滤剩下的消息全部当成RIL_UNSOL_RESPONSE_TUNNEL_AT上发,其中atReadStorage为静态内存块。

static char atReadStorage[1024];

调试的时候可以用logcat -b radio命令查看信息。

一些常见的LOG TAG是:

 RIL: /hardware/ril/reference-ril/refereince-ril.c

 AT: /hardware/ril/reference-ril/atchannel.c

 RILD: /hardware/ril/rild/rild.c

 RILC: /hardware/ril/libril/ril.cpp

 RILB frameworks/base/telephony/java/com/android/internal/telephony/BaseCommands.java

 RILJ: /frameworks/base/telephony/java/com/android/internal/telephony/gsm/RIL.java

 GSM: /frameworks/base/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android frameworks RIL