android命令執行at
⑴ android 怎麼通過藍牙向一個硬體發送AT指令
將16進制的字元串轉換成bytes,通過hexstring2bytes轉換,從而發送指令。
⑵ Android平台到底能不能通過串口發送AT指令呢,急!!!
AT命令(Attention)在手機中,用於對modem(也就是移動模塊)通過串口命令進行操作,處理與語音電話、簡訊和數據。
關於AT命令:
Android系統與AT命令
對於智能手機,AP和BP分離的情況,在AP上的系統通過串口和BP通信是個不錯方式。在Android的源碼中有一個內部包com.android.internal.telephony中有對AT命令的封裝和解析,但這種internal的包開發者不能調用的SDK部分,可以用來封裝ROM。這說明Android對AT command的方式是支持的。
對於Android如何調用AT command
用root登錄命令行,直接對串口進行操作,如echo -e "AT " > /dev/smd0
具體的串口,不同設備會有不同,甚至不一定會提供。這種方式,開發者是可以調用的,通過Runtime.exec直接執行命令行命令,但要求是root,例如echo -e "ATD123456789; " > /dev/smd0,撥打123456789的號碼。
目前最新的AT命令標准發布與2014.6.27,似乎還活得挺滋潤的。但是給出的keywords是UMTS, GSM, command, terminal, LTE這說明CDMA確實很可能不是採用AT命令的方式。
⑶ 如何修改android模擬器上的IMEI,IMSI,SIM card serial number
手機使用IMEI和IMSI登錄到GSM網路的,由GSM網路側負責將IMSI和映射成手機號(MSISDN),以及執行相反方向的映射。
(一)、SIM card 號的修改:
SIM card號就是印製在SIM上的一串數字。
讀SIM card號的AT命令為:AT+CRSM=176,12258,0,0,10
因此在andorid模擬其源碼中找到該AT命令——在sim_card.c中:
const char*
asimcard_io( ASimCard sim, const char* cmd )
{
int nn;
#if ENABLE_DYNAMIC_RECORDS
int command, id, p1, p2, p3;
#endif
static const struct { const char* cmd; const char* answer; } answers[] =
{
{ "+CRSM=192,28436,0,0,15", "+CRSM: 144,0," },
{ "+CRSM=176,28436,0,0,20", "+CRSM: 144,0," },
{ "+CRSM=192,28433,0,0,15", "+CRSM: 144,0," },
{ "+CRSM=176,28433,0,0,1", "+CRSM: 144,0,55" },
{ "+CRSM=192,12258,0,0,15", "+CRSM: 144,0," },
{ "+CRSM=176,12258,0,0,10", "+CRSM: 144,0,98101430121181157002" },
...
...
因此用UE二進制方式打開emulator-arm.exe 或 emulator-x86.exe,並搜索字元串「98101430121181157002」,然後將其修改成需要的SIM card號。
比如:
00209a00h: 31 30 00 00 2B 43 52 53 4D 3A 20 31 34 34 2C 30 ; 10..+CRSM: 144,0
00209a10h: 2C 39 38 31 30 31 34 33 30 31 32 31 31 38 31 31 ; ,981014301211811
00209a20h: 35 37 30 30 32 00 2B 43 52 53 4D 3D 31 39 32 2C ; 57002.+CRSM=192,
(二)、IMEI、IMSI號的修改:
java代碼中獲取手機的IMEI號與ISMI號途徑為:
TelephonyManager manager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String imei = manager.getDeviceId();
String imsi = manager.getSubscriberId();
在android的源碼樹中找到類TelephonyManager的實現:
成員函數getDeviceId:
/**
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
* or ESN for CDMA phones. Return null if device ID is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getDeviceId() {
try {
return getSubscriberInfo().getDeviceId();
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
}
成員函數getSubscriberId:
/**
* Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
* Return null if it is unavailable.
* <p>
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getSubscriberId() {
try {
return getSubscriberInfo().getSubscriberId();
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
// This could happen before phone restarts e to crashing
return null;
}
}
上面兩個成員函數最終調用共同的一個私有成員函數getSubscriberInfo():
private IPhoneSubInfo getSubscriberInfo() {
// get it each time because that process crashes a lot
return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
}
而上面私有函數getSubscriberInfo獲取的手機IMSI和IMEI號被硬編碼在文件android_modem.c中:
/* the Android GSM stack checks that the operator's name has changed
* when roaming is on. If not, it will not update the Roaming status icon
*
* this means that we need to emulate two distinct operators:
* - the first one for the 'home' registration state, must also correspond
* to the emulated user's IMEI
*
* - the second one for the 'roaming' registration state, must have a
* different name and MCC/MNC
*/
#define OPERATOR_HOME_INDEX 0
#define OPERATOR_HOME_MCC 310
#define OPERATOR_HOME_MNC 260
#define OPERATOR_HOME_NAME "Android"
#define OPERATOR_HOME_MCCMNC STRINGIFY(OPERATOR_HOME_MCC) \
STRINGIFY(OPERATOR_HOME_MNC)
#define OPERATOR_ROAMING_INDEX 1
#define OPERATOR_ROAMING_MCC 310
#define OPERATOR_ROAMING_MNC 295
#define OPERATOR_ROAMING_NAME "TelKila"
#define OPERATOR_ROAMING_MCCMNC STRINGIFY(OPERATOR_ROAMING_MCC) \
STRINGIFY(OPERATOR_ROAMING_MNC)
/* a function used to deal with a non-trivial request */
typedef const char* (*ResponseHandler)(const char* cmd, AModem modem);
static const struct {
const char* cmd; /* command coming from libreference-ril.so, if first
character is '!', then the rest is a prefix only */
const char* answer; /* default answer, NULL if needs specific handling or
if OK is good enough */
ResponseHandler handler; /* specific handler, ignored if 'answer' is not NULL,
NULL if OK is good enough */
} sDefaultResponses[] =
{
/* see onRadioPowerOn() */
{ "%CPHS=1", NULL, NULL },
{ "%CTZV=1", NULL, NULL },
...
{ "!+VTS=", NULL, handleSetDialTone },
{ "+CIMI", OPERATOR_HOME_MCCMNC "000000000", NULL }, /* request internation subscriber identification number */
{ "+CGSN", "000000000000000", NULL }, /* request model version */
{ "+CUSD=2",NULL, NULL }, /* Cancel USSD */
...
/* end of list */
{NULL, NULL, NULL}
};
因此用UE二進制方式打開emulator-arm.exe 或 emulator-x86.exe,並搜索字元串"+CGSN"修改為需要的IMEI號;搜索"+CIMI"修改為需要的IMSI號。需要注意的是 IMSI 號的頭六個數字"310260"不能修改,否則模擬器無法與網路連接。
例如:
001fc700h: 33 00 41 00 48 00 21 2B 56 54 53 3D 00 2B 43 49 ; 3.A.H.!+VTS=.+CI
001fc710h: 4D 49 00 33 31 30 32 36 30 30 30 30 30 30 30 30 ; MI.3102600000000
001fc720h: 30 30 00 2B 43 47 53 4E 00 30 30 30 30 30 30 30 ; 00.+CGSN.0000000
001fc730h: 30 30 30 30 30 30 30 30 00 2B 43 55 53 44 3D 32 ; 00000000.+CUSD=2
⑷ android添加藍牙電量
1. HFP 命令AT+IPHONEACCEV
描述:報告耳機的狀態變更
發起者:耳機
格式:AT+IPHONEACCEV=[Number of key/value pairs ],[key1 ],[val1 ],[key2
],[val2 ],…
參數:
Number of key/value pairs :接下來參數的數量
key:被報告狀態變化的類型
1 =電量等級
2 =暫停狀態
val:更改的值
Battery events:0-9之間數字的字元串 A
string value between 『0』 and 『9』.
Dock state: 0 = undocked, 1 = docked.
Example:AT+IPHONEACCEV=1,1,3
2.android framework 修改點
packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
BluetoothAssignedNumbers.APPLE可以隨便用哪個公司的,但注冊廣播時要一致就行。
static {
classInitNative();
型亂磨 VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID = new HashMap();
VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put("+XEVENT",BluetoothAssignedNumbers.PLANTRONICS);
VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put("+ANDROID",BluetoothAssignedNumbers.GOOGLE); 陪絕 +VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put("+XAPL",BluetoothAssignedNumbers.APPLE);
+VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put("+IPHONEACCEV",BluetoothAssignedNumbers.APPLE);
}
獲取藍牙電量需要向藍牙發送回復的at命令:
private (String atString) {
log("processVendorSpecificAt - atString = " + atString);
// Currently we accept only SET type commands.
int indexOfEqual = atString.indexOf("=");
if (indexOfEqual == -1) {
Log.e(TAG, "processVendorSpecificAt: command type error in " +atString);
return false;
}
String command = atString.substring(0, indexOfEqual);
Integer companyId = VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.get(command);
if (companyId == null) {
Log.e(TAG, "processVendorSpecificAt: unsupported command: " +atString);
卜斗 return false;
}
String arg = atString.substring(indexOfEqual + 1);
if (arg.startsWith("?")) {
Log.e(TAG, "processVendorSpecificAt: command type error in " +atString);
return false;
}
Object[] args = generateArgs(arg);
+ if ("+XAPL".equals(command)) {
+ processAtXapl(args);
+ }
(command,
companyId,
BluetoothHeadset.AT_CMD_TYPE_SET,
args,
mCurrentDevice);
atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_OK, 0);
return true;
}
/**
* Process AT+XAPL AT command
* @param args command arguments after theequal sign
* @param device Remote device that hassent this command
*/
private void processAtXapl(Object[] args){
if (args.length != 2) {
Log.w(TAG, "processAtXapl()args length must be 2: " + String.valueOf(args.length));
return;
}
if (!(args[0] instanceof String) ||!(args[1] instanceof Integer)) {
Log.w(TAG, "processAtXapl()argument types not match");
return;
}
// feature = 2 indicates that wesupport battery level reporting only
Log.d("tsq77","+XAPL=iPhone,");
atResponseStringNative("+XAPL=iPhone," + String.valueOf(2));
}
2.上層app監聽廣播獲取電量
packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothSettings.java
在settings中的藍牙界面中注冊廣播,然後把電量顯示出來。
//aaron
IntentFilter filter=new IntentFilter();
filter.addAction(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
//filter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY+"."+BluetoothAssignedNumbers.
APPLE);
filter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY+"."+BluetoothAssignedNumbers.
APPLE);
getActivity().registerReceiver(mIntentReceiver,filter);
Log.i("a", "registerReceiver ");
//end
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(action.equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) {
Log.i("a","intent "+intent);
String command=intent.getStringExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD);
if("+IPHONEACCEV".equals(command)) {
Object[] args = (Object[])intent.getSerializableExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS);
if (args.length >= 3&& args[0] instanceof Integer &&((Integer)args[0])*2+1<=args.length) {
for (inti=0;i<((Integer)args[0]);i++) {
if(!(args[i*2+1] instanceof Integer) || !(args[i*2+2] instanceof Integer)) {
continue;
}
if(args[i*2+1].equals(1)) {
floatlevel=(((Integer)args[i*2+2])+1)/10.0f;//獲取的電量百分比
break;
}
}
}
}
}
}
};
⑸ android 中什麼是上下層交互介面,命令
Android的無線介面層(RIL)充當了Android電話服務與無線電硬體之間的抽象層,它與具體的通信方式無關,主要提供GSM網路支持。在Android電話系統的架構圖中,RIL被置於一個實線框內,代表其屬於Android系統的一部分,而合作夥伴專用的部分則由虛線框表示。
RIL由兩個基本部分組成:RIL守護進程(RIL Daemon)和Vendor RIL。RIL守護進程負責初始化Vendor RIL,管理所有來自Android通訊服務的請求命令,將這些命令調度給Vendor RIL;而Vendor RIL則負責與無線電硬體進行通信,並通過未被請求的命令(即被動請求命令)將其分發給RIL守護進程。在Android啟動時,RIL守護進程會讀取rild.lib路徑和rild.libargs系統參數,以確定應該使用的Vendor RIL庫及向Vendor RIL提供的初始化參數。隨後,RIL守護進程會載入Vendor RIL庫,執行RIL_Init以初始化RIL並獲取RIL函數所需參數,最後調用Android通訊棧中的RIL_register,為Vendor RIL函數提供參考。
RIL句柄提供了兩種交互方式:主動請求命令和被動請求命令。主動請求命令來自RIL lib,包括DIAL和HANGUP等;被動請求命令則來自基帶,如CALL_STATE_CHANGED 和 NEW_SMS。主動請求命令的代碼片段包括OnRequest和OnRequestComplete函數,其中主動請求命令有超過60種,涵蓋SIM PIN、電話狀態、網路狀態查詢、網路設置、簡訊、PDP連接、電源和復位以及供應商定義及其支持等類別。
被動請求命令的代碼片段為OnUnsolicitedResponse函數,它有超過10條被動請求命令,包括網路狀態改變、新簡訊通知、新USSD通知以及信號強度和時間改變等。為了實現一個專用的通訊RIL,需要定義一系列函數以創建一個共享庫,這些函數被定義在RIL頭部文件(/include/telephony/ril.h)中。RIL參考源碼位於/commands/reference-ril/,提供了一個使用賀式(Hayes)AT命令設備的參考Vendor RIL,適用於快速入門和通訊測試。
特定的Vendor RIL必須定義一個初始化函數,提供一系列句柄函數以處理每一個通訊請求。Android RIL守護進程會在啟動時調用RIL_Init以初始化RIL。RIL_RadioFunctions結構體包含了無線電函數指針,如RIL_version、RIL_RequestFunc、RIL_RadioStateRequest、RIL_Supports、RIL_Cancel和RIL_GetVersion等。Vendor RIL必須提供RIL_RequestFunc函數來發送主動命令,RIL主動命令請求類型定義在ril.h的RIL_REQUEST_prefix中。RIL_RequestFunc函數需要處理各種RIL主動請求,並調用RIL_onRequestComplete函數完成通訊。
此外,RIL_Cancel函數用於指示取消一個待處理請求,一旦取消,被調用者應當盡量放棄請求並調用RIL_onRequestComplete函數的RIL_Errno CANCELLED。響應請求後調用RIL_onRequestComplete並產生其他結果是可以接受的,但會被忽略。RIL_Cancel函數應立刻返回,無需等待取消。RIL_GetVersion函數返回你的Vendor RIL的版本字元串。