The CAMediaTiming protocol models a hierarchical timing system, with each object describing the mapping of time values from the object's parent to local time.
不是很明白,这句话的含义,等理解透彻了再来解释。对于手上拥有一个2530开发板的Zstack初学者来说,最经常做的事情也许就是按下开发板上的某个按键,进行绑定或者远程控制另一个开发板上的LED的亮灭。自然而然地,大家都想知道这个过程是如何实现的,协议栈的按键处理函数在哪里,如果想自己设计开发板,假如按键接口和2530标准开发板不一样的话,又应当修改哪些参数才能保证按键能够起作用,这里我就来详细地解释一下。
按键的配置是在hal_key.c里实现的,在文件的顶端,我们能够找到如下的预编译内容:
/* SW_6 is at P0.1 */
#define HAL_KEY_SW_6_PORT P0
#define HAL_KEY_SW_6_BIT BV(1)
#define HAL_KEY_SW_6_SEL P0SEL
#define HAL_KEY_SW_6_DIR P0DIR
/* edge interrupt */
#define HAL_KEY_SW_6_EDGEBIT BV(0)
#define HAL_KEY_SW_6_EDGE HAL_KEY_FALLING_EDGE
/* SW_6 interrupts */
#define HAL_KEY_SW_6_IEN IEN1 /* CPU interrupt mask register */
#define HAL_KEY_SW_6_IENBIT BV(5) /* Mask bit for all of Port_0 */
#define HAL_KEY_SW_6_ICTL P0IEN /* Port Interrupt Control register */
#define HAL_KEY_SW_6_ICTLBIT BV(1) /* P0IEN - P0.1 enable/disable bit */
#define HAL_KEY_SW_6_PXIFG P0IFG /* Interrupt flag at source */
对于具备大学英语水平的同学们来说,这些语句的含义并不难理解。这里是说Zstack协议栈的SW6按键被分配到了P0.1端口,下面所有的这些预编译内容都是为了保证按键被按下时,程序能够检测到并进行正确处理。我们看到这里的预编译内容涉及到了大量的寄存器,大家要适应Zstack的这一编码方式,习惯冗长的预编译命名(对于经常编写VC等高级语言代码的同学来说这也许并不算什么)。
好的,心急的同学也许已经迫不及待地想要开始修改了,我这里就列出我自己修改的将SW6分配到P0.7的配置代码:
/* SW_6 is at P0.7 */
#define HAL_KEY_SW_6_PORT P0
#define HAL_KEY_SW_6_BIT BV(7)
#define HAL_KEY_SW_6_SEL P0SEL
#define HAL_KEY_SW_6_DIR P0DIR
/* edge interrupt */
#define HAL_KEY_SW_6_EDGEBIT BV(0)
#define HAL_KEY_SW_6_EDGE HAL_KEY_FALLING_EDGE
/* SW_2 interrupts */
#define HAL_KEY_SW_6_IEN IEN1 /* CPU interrupt mask register */
#define HAL_KEY_SW_6_IENBIT BV(5) /* Mask bit for all of Port_0 */
#define HAL_KEY_SW_6_ICTL P0IEN /* Port Interrupt Control register */
#define HAL_KEY_SW_6_ICTLBIT BV(7) /* P0IEN - P0.6 enable/disable bit */
#define HAL_KEY_SW_6_PXIFG P0IFG /* Interrupt flag at source */
如果对于以上配置有什么不很理解的地方我建议大家多去看看CC2530的说明文档,仔细理解每一个寄存器所起到的作用。对于嵌入式软件工程师来说,说明文档永远是最得力的帮手。
OK,在完成了以上配置之后,下面要关注的应该就是按键处理函数了,那么这个函数在哪呢?这里我们以Zstack协议栈的SampleSwitch工程为例,有一个文件我们要特别注意,这就是zcl_samplesw.c。这是应用层的源文件,对于广大Zstack协议栈开发者来说,以后对协议栈的修改很大一部分都是在这个文件中进行的。在这个文件中,找到这个函数:
static void zclSampleSw_HandleKeys( byte shift, byte keys )
{
zAddrType_t dstAddr;
(void)shift; // Intentionally unreferenced parameter
if ( keys & HAL_KEY_SW_1 )
{
// Using this as the "Light Switch"
#ifdef ZCL_ON_OFF
zclGeneral_SendOnOff_CmdToggle( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, false, 0 );
#endif
}
if ( keys & HAL_KEY_SW_2 )
{
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate an End Device Bind Request, this bind request will
// only use a cluster list that is important to binding.
dstAddr.addrMode = afAddr16Bit;
dstAddr.addr.shortAddr = 0; // Coordinator makes the match
ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),
SAMPLESW_ENDPOINT,
ZCL_HA_PROFILE_ID,
0, NULL, // No incoming clusters to bind
ZCLSAMPLESW_BINDINGLIST, bindingOutClusters,
TRUE );
}
if ( keys & HAL_KEY_SW_3 )
{
}
if ( keys & HAL_KEY_SW_4 )
{
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate a Match Description Request (Service Discovery)
dstAddr.addrMode = AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,
ZCL_HA_PROFILE_ID,
ZCLSAMPLESW_BINDINGLIST, bindingOutClusters,
0, NULL, // No incoming clusters to bind
FALSE );
}
}
聪明的同学一看就明白了,哦,原来如此简单啊,那我是不是只要这么添加就成了:
if ( keys & HAL_KEY_SW_6 )
{
处理函数…
}
没有错,杀人越货居家旅行必备的天下第一奇毒秘密配方已尽收你眼底了,哈哈。OK,修改之后编译下载,大功告成,按下按键,等待见证奇迹的时刻。咦,咋什么反应都没???
呵呵,是不是有种想要砸电脑的感觉,Zstack协议栈确实相当令人各种厌烦,除了以上的配置,还有两个要注意的地方。在hal_board_cfg.h文件中,有下面两句预编译语句:
/* S1 */
#define PUSH1_BV BV(1)
#define PUSH1_SBIT P0_1
这时你心想,这不是S1么,跟S6有毛的关系啊!咦,不对啊,Zstack默认的的SW6不是对应着P0.1么,怎么这里的S1也关联到P0.1去了。呵呵,这个其实是TI的不对了,确实这里的S1和刚才的SW6是一回事,就让我们尽情地对着TI的协议栈送上各种“美好的”问候词吧。在hal_key.c中,也可以看到:
if (HAL_PUSH_BUTTON1())
{
keys |= HAL_KEY_SW_6;
}
是不是憋不住想骂人了,淡定淡定。我们把hal_board_cfg.h中的那两个预编译代码进行相应的修改:
/* S1 */
#define PUSH1_BV BV(7)
#define PUSH1_SBIT P0_7
编译下载,按下按键,此刻,屏幕缓缓变黑,最后留下一行颇有深意的文字:To be continued…
影迷们请尽情期待13年悬疑大剧的下一集。
这只是时长三个月左右的Android培训, 所以学到的都是应用层面的东东(自己以为), 不可能对整个Android进行系统深入的讲解.
------------------------
各种来电防火墙之类的功能都可以过滤掉黑名单中的来电, 原理是响铃是判断来电号码是否存在于黑名单中, 如果存在则将其挂断. 而一些软件可以选择被挂断的家伙听到的提示音是"正在通话中"还是"欠费停机"之类的, 则是通过判断之后用运营商的"呼叫转移"功能将号码转接给一个已经停机的号码来实现的.
挂断一个电话在API-10和之前版本中直接调用TelephonyManager对象的endCall方法即可, 但是之后的版本中这个API不再被公开(升级后的Android系统中还存在, 但是在Android SDK中不再提供给开发者* ).
还想忤逆股沟的意思来调用它的话, 大概有两中方式:
第一种: 自己定制android.jar文件. 这种方法不用每次用到"非公开"的API都在代码中费一番功夫. 这里http://mogoweb.net/archives/87 有非常详细的说明.
第二种: 用反射. (有两种方法):
package com.example.hanguptest; import java.lang.reflect.Method; import android.app.Activity; import android.os.Bundle; import android.os.IBinder; import android.telephony.TelephonyManager; import android.view.View; import android.widget.Toast; import com.android.internal.telephony.ITelephony; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void hangUp1(View v) throws Exception{ Toast.makeText(getApplicationContext(), "hangUp1", 0).show(); TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); Class tmClazz = tm.getClass(); Method getITelephonyMethod = tmClazz.getDeclaredMethod("getITelephony", null); getITelephonyMethod.setAccessible(true); ITelephony iTelephony = (ITelephony) getITelephonyMethod.invoke(tm, null); iTelephony.endCall(); } /** * @param v * @throws Exception */ public void hangUp2(View v) throws Exception{ Toast.makeText(getApplicationContext(), "hangUp1", 0).show(); Class clazz = Class.forName("android.os.ServiceManager"); Method getServiceMethod = clazz.getMethod("getService", String.class); IBinder iBinder = (IBinder) getServiceMethod.invoke(null, TELEPHONY_SERVICE); ITelephony iTelephony = ITelephony.Stub.asInterface(iBinder); iTelephony.endCall(); } }
-----------------------
注: * 在模拟器和手机上的system/framework/framework.jar中存在, 但是在SDK的sdk\platforms\android-X\android.jar中被移除了.
----
看了这两篇文章, 收获也很大.
http://blog.csdn.net/louiswangbing/article/details/6607418
http://www.linuxidc.com/Linux/2011-11/46416.htm