stack

阅读 / 问答 / 标签

Maximum call stack size exceeded 问题出现原因是什么

Uncaught RangeError: Maximum call stack size exceeded 意思为:堆栈溢出 发生原因: 递归次数过多,没有正确的退出递归造成堆栈溢出 解决方法: 减少递归次数,使用其他方法解决问题 恰当的时机返回,避免由于返回条件不正确导致的堆栈溢出

Zstack中如何实现自己的任务 详细03

{ osal_pwrmgr_powerconserve(); // Put the processor/system into sleep } #endif } } //临界区资源管理 先看一个临界区代码保护的例子: HAL_ENTER_CRITICAL_SECTION(intState); events = activeTask->events; activeTask->events = 0; //清楚任务的事件 HAL_EXIT_CRITICAL_SECTION(intState); 其中:中断宏定义如下 #define HAL_ENABLE_INTERRUPTS() st( EA = 1; ) #define HAL_DISABLE_INTERRUPTS() st( EA = 0; ) #define HAL_INTERRUPTS_ARE_ENABLED() (EA) typedef unsigned char halIntState_t; #define HAL_ENTER_CRITICAL_SECTION(x) st( x = EA; HAL_DISABLE_INTERRUPTS(); ) #define HAL_EXIT_CRITICAL_SECTION(x) st( EA = x; ) #define HAL_CRITICAL_STATEMENT(x) st( halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); x; HAL_EXIT_CRITICAL_SECTION(s); ) 以及相关的st 宏: #define st(x) do { x } while (__LINE__ == -1) (1)cc2430 芯片中的中断使能的特殊功能寄存器(SFRs):IEN0,IEN1 和IEN2,(见 cc2430 datasheet: P49)。这三个寄存器的不同的位控制了不同的硬件的中断使能,比如IEN2 中的第五位WDTIE 控制着看门狗时钟的中断使能。这其中有一个比较特殊的位是IEN0 的第7 位,名称为EA,控制着所有中断的使能,为0 时 将没有中断相应,为1 时每一个中断源的使能受相应的位的控制。上面的宏即是用芯片的EA=0 来关中断实现临界资源的保护。 (2)set 宏定义如下,表示执行x 指令,注意x 是一个完整的语句,需要加分号。 #define st(x) do { x } while (__LINE__ == -1) 而整个宏的定义结束时没有分号,而是在最后的应用时加的分号,如: HAL_ENTER_CRITICAL_SECTION(intState); (3)HAL_ENABLE_INTERRUPTS()和HAL_DISABLE_INTERRUPTS()这两个宏分别实现了cc2430 的所有中断的开和关。HAL_ENTER_CRITICAL_SECTION(x)宏首先将 EA 的值保存在变量x 中,然后关闭所有中断,进行后面的临街资源处理。 HAL_EXIT_CRITICAL_SECTION(x)宏则是回复刚才保存在x 中的EA 的值。 HAL_CRITICAL_STATEMENT(x)宏的功能是将x 作为临界代码执行,首先声明了用于保存EA 值的变量,然后调用进入临界区宏,执行临界代码x,最后执行退出临界区的宏。 (4)注意HAL_CRITICAL_STATEMENT(x)这个宏,因为st 宏的实现中x 是一些可以执行的完整c 语句,更主要的是写在do{}while()中,它值一个子的程序片段,因此x 可以做很多事,比如声明变量等。否则你会奇怪,这样定义宏在宏展开的时候如果使用多个这个宏,会不会出现重复定义(HAL_CRITICAL_STATEMENT(x) 实现代码中的halIntState_t s;),会不会出现在程序的中间来定义变量(c语言要求要使用的变量需在最前面定义)等问题。其实这些问题是不会出现的,真是因为HAL_CRITICAL_STATEMENT(x)的x 的执行在do-while 中的do 子句中。 下面是一个类似的验证例子程序: #include #define st(x) do{x}while(__LINE__==-1) #define enable() st(EA = 1;) //使能所有中断 #define disable() st(EA = 0;) //关闭所有中断 #define enter(x) st(x = EA; disable();) //进入临界区 #define exit(x) st(EA = x;) //退出临界区 //简写临界代码的执行 #define critical(s) st(int temp; enter(temp); s; exit(temp);) //模拟控制所有中断的变量 int EA = 5; int main() { int a; enter(a); printf("EA=%d, a=%d ",EA,a); exit(a); //验证多次执行宏不会出现重复定义变量的问题 critical(printf("hello world-first ");); critical(printf("hello world-second ");); //上面的critical(printf("hello world-first "););展开后的等价代码 do { int temp; do{ temp = EA; do{ EA = 0; }while(__LINE__==-1); }while(__LINE__==-1); printf("hello world "); do{ EA =temp; }while(__LINE__==-1); }while(__LINE__==-1); //验证在子模块中可以再次声明变量 { int a = 12; printf("%d ",a); { int a = 89; printf("%d ",a); } } return 0; } 执行结果为: EA=0, a=5 hello world-first hello world-second hello world 12 89 PS: (1)c 程序中的各个宏定义的顺序任意。 (1)c 程序中要求变量需先定义所有要使用的变量,然后才使用,是对用一个层次模块来说,在子层次中可以遵循这个规则再次定义变量。一个花括号中的括起来的内容{...}可以看作一个子模块。 Zstack 设置发送功率(CC2530) 在mac_radio.c 中找到macRadioSetTxPower 函数,其具体内容复制如下: #ifndef HAL_MAC_USE_REGISTER_POWER_VALUES MAC_INTERNAL_API void macRadioSetTxPower(uint8 txPower) { halIntState_t s; #if defined MAC_RUNTIME_CC2591 || defined MAC_RUNTIME_CC2590 const uint8 CODE *pTable = macRadioDefsTxPwrTables[macRadioDefsRefTableId >> 4]; #elif defined HAL_PA_LNA || defined HAL_PA_LNA_CC2590 const uint8 CODE *pTable = macRadioDefsTxPwrTables[0]; #else const uint8 CODE *pTable = macRadioDefsTxPwrBare; //该table 中含有txPower 的设置值,将该table 的首地址赋给指针pTable, //macRadioDefsTxPwrBare[]定义在mac_radio_defs.c 中 #endif if ((int8)txPower > (int8)pTable[MAC_RADIO_DEFS_TBL_TXPWR_FIRST_ENTRY]) { txPower = pTable[MAC_RADIO_DEFS_TBL_TXPWR_FIRST_ENTRY];//发送功率上限值 } else if ((int8)txPower < (int8)pTable[MAC_RADIO_DEFS_TBL_TXPWR_LAST_ENTRY]) { txPower = pTable[MAC_RADIO_DEFS_TBL_TXPWR_LAST_ENTRY];//发送功率下限值 } HAL_ENTER_CRITICAL_SECTION(s); { uint8 index = pTable[MAC_RADIO_DEFS_TBL_TXPWR_FIRST_ENTRY] - txPower + MAC_RADIO_DEFS_TBL_TXPWR_ENTRIES; reqTxPower = pTable[index]; } //通过计算转换查表index,得到发送功率值,将其赋给reqTxPower, //函数macRadioUpdateTxPower 中用于更新发送功率 HAL_EXIT_CRITICAL_SECTION(s); macRadioUpdateTxPower(); } #else MAC_INTERNAL_API void macRadioSetTxPower(uint8 txPower) {//直接获得reqTxPower halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); reqTxPower = txPower; HAL_EXIT_CRITICAL_SECTION(s); macRadioUpdateTxPower(); } 下面了解一下macRadioUpdateTxPower 函数,其函数体如下: MAC_INTERNAL_API void macRadioUpdateTxPower(void) { halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s);//进入临界区 if (reqTxPower != macPhyTxPower)//macPhyTxPower 即为当前实际的发送功率 { if (!macRxOutgoingAckFlag && !MAC_TX_IS_PHYSICALLY_ACTIVE()) //当有发送任务正在进行时,不能改变发送功率。 //当前的发送任务完成后,将重新调用该函数进行发送功率设置。 { macPhyTxPower = reqTxPower; MAC_RADIO_SET_TX_POWER(macPhyTxPower);//设置寄存器TXPOWER 为 macPhyTxPower,即reqTxPower } } HAL_EXIT_CRITICAL_SECTION(s);//离开临界区 } 通过上面的函数,我们根据自己的需要,适当对发送功率进行设置。 关于ZStack-CC2530-2.3.0-1.4.0 中simpleApp 例子的组网(一) 所有的C 语言编写的程序,入口函数一定是main 函数,首先看一下ZMain.c 函数。 int main( void ) { osal_int_disable( INTS_ALL ); HAL_BOARD_INIT(); zmain_vdd_check(); InitBoard( OB_COLD ); HalDriverInit(); osal_nv_init( NULL ); ZMacInit(); zmain_ext_addr(); zgInit(); #ifndef NONWK afInit(); #endif osal_init_system(); osal_int_enable( INTS_ALL ); InitBoard( OB_READY ); zmain_dev_info(); #ifdef LCD_SUPPORTED zmain_lcd_init(); #endif #ifdef WDT_IN_PM1 WatchDogEnable( WDTIMX ); #endif osal_start_system(); return 0; } 主函数要做的事情非常简单,首先进行了一些初始化,包括各层的初始化,硬件初始化,以及任务的初始化等,然后就进入到操作系统当中,即 osal_start_system(); 就再也出不来了。操作系统的作用就是如果有事件发生,就把这个消息通知给处理该事件的事件处理函数去执行,然后一直的循环查找有没有事件发生。另外说一下,事件是定义在任务当中的,即一个任务可能有多个事件,每个任务对应一个事件处理函数。在这个程序中,一共有6 个任务,有兴趣的同学可以自己查看void osalInitTasks( void )函数的代码。 接下来看一下zigbee 协调器是怎么建立网络的 首先我们必须选择SimpleCollectorEB 版本,在APP 文件下看到sapi.c 源文件。找到SAPI_Init(byte task_id)函数,此函数是进行sapi 层的初始化,代码如下 void SAPI_Init( byte task_id ) { sapi_TaskID = task_id;//将操作系统初始化任务时定义的任务id 号传进来 sapi_bindInProgress = 0xffff;//设置不允许绑定 sapi_epDesc.task_id = &sapi_TaskID;//给端口描述符的任务ID 号赋值,感觉也就是端口收到的数据或者消息就交给ID 号指定的任务来处理。 sapi_epDesc.endPoint = 0;//端口描述符端口号初始化为0。 #if ( SAPI_CB_FUNC )//编译通过 sapi_epDesc.endPoint = zb_SimpleDesc.EndPoint;//端口号赋值 sapi_epDesc.task_id = &sapi_TaskID;//任务ID 赋值,与上面的任务ID 的值是相同的。 sapi_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&zb_SimpleDesc;//简单描述符赋值,是描述一个端口最基本的信息 sapi_epDesc.latencyReq = noLatencyReqs;//这是一个枚举类型的,不清楚具体含义,不过大家都设成noLatencyReqs,除此之外还有两个值。 afRegister( &sapi_epDesc );//将定义的端点在AF 层注册,一定要注册后端点才会生效 #endif afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);//设置描述符不能匹配 // Register callback evetns from the ZDApp ZDO_RegisterForZDOMsg( sapi_TaskID, NWK_addr_rsp );//在sapi 层注册网络地址事件,这个函数可以截取空中发来的消息,有兴趣的可以查查资料,第一个函数是截取的消息发到哪个任务中去,第二个参数,cluserID 是消息的类型。 ZDO_RegisterForZDOMsg( sapi_TaskID, Match_Desc_rsp );//同理,在sapi 层注册匹配描述符事件。 #if ( SAPI_CB_FUNC ) #if (defined HAL_KEY) && (HAL_KEY == TRUE) // Register for HAL events RegisterForKeys( sapi_TaskID );//注册按键响应事件 if ( HalKeyRead () == HAL_KEY_SW_5) { uint8 startOptions = ZCD_STARTOPT_CLEAR_STATE | ZCD_STARTOPT_CLEAR_CONFIG; zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions ); zb_SystemReset(); } #endif // HAL_KEY osal_set_event(task_id, ZB_ENTRY_EVENT);//在这里设置了一个进入事件,第一个参数是task_id 是任务的ID 号,因此我们可以在sapi 层的事件处理函数中找到这个进入事件是怎么处理的。 #endif } 在UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )函数中,找到 if ( events & ZB_ENTRY_EVENT ) { uint8 startOptions; // Give indication to application of device startup #if ( SAPI_CB_FUNC ) zb_HandleOsalEvent( ZB_ENTRY_EVENT ); #endif // LED off cancels HOLD_AUTO_START blink set in the stack HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);//为了方便观察实验现象,将第四个灯关闭。 zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions ); if ( startOptions & ZCD_STARTOPT_AUTO_START ) { zb_StartRequest(); } else { // blink leds and wait for external input to config and restart HalLedBlink(HAL_LED_2, 0, 50, 500); } return (events ^ ZB_ENTRY_EVENT ); } 这个时候,程序就停在这里,只能看到LED_2 在闪烁。这个时候我们可以按下按键1,然后去找一下,事件处理函数中如何对此事件进行相应。找到UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )函数中的关于按键的处理: case KEY_CHANGE: #if ( SAPI_CB_FUNC ) zb_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys ); #endif break; 进入到HandleKeys 函数中,找到 if ( keys & HAL_KEY_SW_1 ) { if ( myAppState == APP_INIT ) { zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );//读取flash 中的设备类型 if ( logicalType != ZG_DEVICETYPE_ENDDEVICE ) { logicalType = ZG_DEVICETYPE_COORDINATOR;//将设备类型改变为协调器类型 zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);//将设备类型写入到flash 中 } zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );//读取启动模式 startOptions = ZCD_STARTOPT_AUTO_START;//将启动模式赋值为自动启动模式 zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );//将启动模式存入到flash 中 zb_SystemReset();//系统重启设置。这时候flash 中,启动模式就变成了ZCD_STARTOPT_AUTO_START,系统重启以后,系统继续刚才讲过的过程,不同的是在进行到进入事件处理函数时,if ( startOptions & ZCD_STARTOPT_AUTO_START )的值成立,调用if 语句里面的zb_StartRequest() 函数;即执行开始请求函数。 } 接下来进入到zb_StartRequest 函数中看一看,原代码如下: void zb_StartRequest() { uint8 logicalType; zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );//从flash 中读出设备类型。 // Check for bad combinations of compile flag definitions and device type setting. if ((logicalType > ZG_DEVICETYPE_ENDDEVICE) || //可以判断if 里面语句为0,执行else #if !ZG_BUILD_ENDDEVICE_TYPE // Only RTR or Coord possible. (logicalType == ZG_DEVICETYPE_ENDDEVICE) || #endif #if !ZG_BUILD_RTR_TYPE // Only End Device possible. (logicalType == ZG_DEVICETYPE_ROUTER) || (logicalType == ZG_DEVICETYPE_COORDINATOR) || #elif ZG_BUILD_RTRONLY_TYPE // Only RTR possible. (logicalType == ZG_DEVICETYPE_COORDINATOR) || #elif !ZG_BUILD_JOINING_TYPE // Only Coord possible. (logicalType == ZG_DEVICETYPE_ROUTER) || #endif (0)) { logicalType = ZB_INVALID_PARAMETER; SAPI_SendCback(SAPICB_START_CNF, logicalType, 0); } else { logicalType = ZB_SUCCESS; //将设备类型改为ZB_SUCCESS ZDOInitDevice(zgStartDelay); // 执行初始化设备函数。 } return; } 那么接下来去初始化设备函数中看一下,右键,go to definition uint8 ZDOInitDevice( uint16 startDelay ) { uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; //首先更改了网络状态为初始化新网络状态 uint16 extendedDelay = 0; if ( devState == DEV_HOLD ) { zgInitItems( FALSE ); } ZDConfig_InitDescriptors(); _NIB.CapabilityInfo = ZDO_Config_Node_Descriptor.CapabilityFlags; devState = DEV_INIT; // 设备状态改为初始化 ZDApp_LeaveCtrlInit(); //离开控制初始化 ZDApp_LeaveCtrlStartup( &devState, &startDelay );//检查离开控制时的一些设置 if ( devState == DEV_HOLD ) { zgWriteStartupOptions( ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE ); osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); return ( ZDO_INITDEV_LEAVE_NOT_STARTED ); } #if defined ( NV_RESTORE ) //NV_RESTORE 编译不通过,NV_RESTORE 主要是设置掉电再重新上电,参数是否保留 if ( HalKeyRead() == SW_BYPASS_NV ) networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; else { networkStateNV = ZDApp_ReadNetworkRestoreState(); } if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE ) { networkStateNV = ZDApp_RestoreNetworkState(); } else { NLME_InitNV(); NLME_SetDefaultNV(); } #endif if ( networkStateNV == ZDO_INITDEV_NEW_NETWORK_STATE ) { ZDAppDetermineDeviceType(); //确定设备类型 extendedDelay = (uint16)((NWK_START_DELAY + startDelay) + (osal_rand() & EXTENDED_JOINING_RANDOM_MASK)); } ZDApp_SecInit( networkStateNV );// 初始化设备对象的安全操作 ZDApp_NetworkInit( extendedDelay ); //进行网络的初始化 NLME_SetBroadcastFilter( ZDO_Config_Node_Descriptor.CapabilityFlags ); //网络层函数,代码看不到,看函数名字是设置广播地址掩码来支持广播过滤。不太明白这个。。。

如何在Zstack 中使用串口

网上和论坛里面很多帖子都把精力集中到分析协议栈的串口工作机制上,比如分析DMA工作原理,中断工作原理,然后分析输入和输出Buffer的处理等内容,学习者跟着协议栈的串口底层一直到顶层转圈、转圈、再转圈,蒙圈了。实际上,从应用角度讲,我们根本就没有必要去深入的追究Zstack中串口的工作机制,也没有必要去搞清楚到底是怎么DMA和Interrupt的,我们只要调用几个简单函数就可以正常使用串口了。其实协议栈已经把使用串口的条件准备好了,我们何必再纠结硬件底层实现呢?应用者应该把协议栈看作一个平台,平台之上的应用才是我们的目标。下面我就讲一下如何利用协议栈现有平台来实现自己的串口应用。这里我所提及的现有平台即是Zstack自带的MT包,其实Zstack中的这个MT包功能相当强大,通过TI提供的ZTOOL工具可以用串口的方式同整个协议栈进行交互,在我们编写Zigbee应用程序的过程中,很多不知道该如何调用的函数都能在MT中找到参考!这个不多说了,有兴趣的同学可以去专门研究一下MT包。二、使用方法在MT包中,已经有了串口初始化即串口数据处理函数可用,关键的几个函数出现在MT_Uart.c文件中。我们拿出来几个关键函数说明一下(我捡重要语句注释):第一个函数void MT_UartInit (){ // 这个是MT中的一个串口初始化函数,主要作用是初始化串口工作的一些规矩halUARTCfg_t uartConfig;App_TaskID = 0; //处理串口数据的任务ID,可以先不管uartConfig.configured = TRUE;uartConfig.baudRate = MT_UART_DEFAULT_BAUDRATE;//默认38400波特率;可以更改,但是可能有新问题,具体解释内容比较多,我不说;uartConfig.flowControl = FALSE;//MT_UART_DEFAULT_OVERFLOW;//禁止硬件流控,如果你的串口只有RXD,TXD和GND三条线,必须这么做;uartConfig.flowControlThreshold= MT_UART_DEFAULT_THRESHOLD;uartConfig.rx.maxBufSize = MT_UART_DEFAULT_MAX_RX_BUFF;uartConfig.tx.maxBufSize = MT_UART_DEFAULT_MAX_TX_BUFF;uartConfig.idleTimeout = MT_UART_DEFAULT_IDLE_TIMEOUT;uartConfig.intEnable = TRUE;#if defined (ZTOOL_P1) || defined (ZTOOL_P2)uartConfig.callBackFunc = MT_UartProcessZToolData;//如果编译的时候选择使用ZTOOL,那么MT_UartProcessZtoolData将会处理串口接到的数//据串#elif defined (ZAPP_P1) || defined (ZAPP_P2)uartConfig.callBackFunc = MT_UartProcessZAppData;//如果编译的时候没有选择ZTOOL,而是选择使用了ZAPP,则由MT_UartProcessZAppData//函数来处理串口数据串(*如果是用CC2530的P0口那两根串口引脚,你就要define ZTOOL_P1,如果是P1口的那两根串口引脚,你就要define ZTOOL_P2,对于ZAPP_P1和ZAPP_P2也是一个情况*)#elseuartConfig.callBackFunc = NULL;//这个地方,如果你有兴趣自己写一个串口处理函数,那么你实现一个My_UartProcessData//函数,然后填到这里,替换NULL。#endif#if defined (MT_UART_DEFAULT_PORT)HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);//如果定义了默认串口,(0或者1),打开串口,这个HalUartOpen函数会做一大堆工作,具//体说来就是初始化呗。。。,我没有必要展开。需要注意的是这个函数把前面哪一堆初始化//的uartConfig做为参数传进去了噢!#else(void)uartConfig;#endif#if defined (ZAPP_P1) || defined (ZAPP_P2)MT_UartMaxZAppBufLen = 1;MT_UartZAppRxStatus = MT_UART_ZAPP_RX_READY;//这两句,如果是不想使用MT_UartProcessZToolData来处理串口数据,就。。。。//再说就要深入串口机制了,网上讲解文章太多了,自己看吧,我一会儿使用//MT_UartProcessZToolData。#endif}第二个函数void MT_UartRegisterTaskID( byte taskID ){App_TaskID = taskID;}第三个函数void MT_UartProcessZToolData ( uint8 port, uint8 event )osal_msg_deallocate ( (uint8 *)pMsg );}我们往上看看这个Message是什么?MT_UartProcessZToolData函数开始不远的地方有以下程序段:if (pMsg){pMsg->hdr.event = CMD_SERIAL_MSG;pMsg->msg = (uint8*)(pMsg+1);pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;state = CMD_STATE1;}从这里看到,这个函数建立了一个消息头,用CMD_SERIAL_MSG做为消息,那么osal_msg_send给任务的那个消息将会以CMD_SERIAL_MSG出现。。。。。。。好了,以上三个函数看完,我们试着使用一下:以GenericApp例子为例:void GenericApp_Init( byte task_id ){XXXXXXXXXXXXXXXXXXXXXXXXXX(这个函数的最后,其实放在这个函数的哪里都行)MT_UartInit(); //added by kennanMT_UartRegisterTaskID(GenericApp_TaskID);}再看一下MT_UartRegisterTaskID(GenericApp_TaskID):void MT_UartRegisterTaskID( byte taskID ){App_TaskID = taskID;}好了,这样,我们顺利地把串口发来的数据用MT_UartProcessZToolData来处理,并且把处理后的数据打包发给了任务GenericApp_TaskID。接下来,我们看一下在GenericApp_TaskID中如何处理吧。在GenericApp的主处理函数中:UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events ){if ( events & SYS_EVENT_MSG ){MSGpkt = (afIncomingMSGPacket_t*)osal_msg_receive( GenericApp_TaskID );while ( MSGpkt ){switch ( MSGpkt->hdr.event ){case ZDO_CB_MSG:GenericApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );break;case KEY_CHANGE:GenericApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t*)MSGpkt)->keys );break;//增加Case CMD_SERIAL_MSG:ProcessUartData((mtOSALSerialData_t *)MSGpkt); //这个函数你自己实现吧,想做啥呢?想做啥就做啥。如果想把接//到的数据发回串口,调用HalUARTWrite就行了。}如果你不知道如何提取串口消息并处理,我就好人做到底,帮你实现一个ProcessUartData()函数吧。这个函数的作用是把接收到的数据从CM0开始一直到payload的最后一个字节发送给串口回显,不包括校验字节噢。ProcessUartCommand((mtOSALSerialData_t *)MSGpkt){ //为了正确地进行下面工作,用mtOSALSerialData_t类型来指向整个zigbee数据包(不是串//口数据包)uint8 *pMsg;pMsg = MSGpkt->msg;//定义一个指针,指向真正的串口接收数据存放位置,MSGptk里面还有一些别的Header噢。switch ( MSGpkt->hdr.event ){case CMD_SERIAL_MSG://如果是串口消息。。。。HalLedSet( HAL_LED_RED, HAL_LED_MODE_FLASH );//用LED灯指示一下收到数据啦uint8 *pBuffer;uint8 datalength;uint8 i;//定义几个变量,为从接收到的串口包里面提取数据以及写回串口做准备datalength = *pMsg++;//串口包中第一个字节是数据长度噢pBuffer = osal_mem_alloc(datalength);//分配一块内存准备把串口消息数据拿出来if(pBuffer != NULL){for(i = 0;i < datalength; i++)*pBuffer++ = *pMsg++;//把消息中的串口数据按照datalength数量挨个捞出来放血(放血啥意思?把池子//里面那东西捞出来放血,明白不?HalUARTWrite(0,pBuffer,datalength);//捞出来放血的串口数据再写回串口,也就是送到串口助手显示Osal_memfree(pBuffer);//动态申请的内存记得用完了free一下噢}break;default:break;}}说明:因为ZTOOL发过来的数据是有格式的,所以如果你用串口助手来测试,那么发的数据要按照格式来,如果你不想按那个格式,你可以自己去修改MT_UartProcessZToolData里面的相关程序。这种方法对于想要通过PC来控制zigbee的应用场合非常实用,因为你PC发过来的一般也会有命令和数据,如果不用MT的格式,你自己也要规范一个格式,既然MT已经有了,我们就借用就好。对于MT_UartProcessZAppData这个处理方法,也就是你define了ZAPP_P1或ZAPP_P2的情况,其机制也是类似的,只不过没有规定格式,你更自由,这里我就不多说了。再有,如果你真的在测试的时候不知道那么一长串数据的xor 结果是多少,也可以去MT_UartProcessZToolData函数中,找到://if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ +LEN_Token) == FSC_Token)){osal_msg_send( App_TaskID, (byte *)pMsg );}else//{//osal_msg_deallocate ( (uint8 *)pMsg );//}把我标红的几个位置注释掉,就不会校验了,你也不用算xor结果了,不过发数据的时候这个位置还是要的,你随便填个0好了。

Call Stack窗口是怎么显示出来的

首先要进入调试状态(F5),VC6.0 在菜单栏或工具栏右键便可以看到调试窗口( watch Window、call stack Window、...)。如果是VC8.0或者VC9.0在菜单debug=〉windows下面可以找到。

maximum call stack size exceeded怎么解决

可以对WINDOW窗体的onerror事件做出操作,具体请参考以下代码:window.onerror=function (){return true;}注:此代码一定要放在所有JS脚本代码前,否则是不会起作用的。

汇编中未定义stack段 call命令执行后 cs ip放哪里

放在默认栈中。这个栈是不安全的,因为你实际不能操作它。

我下了一个国王的恩赐:北方勇士-冰与火中文版 打不开,错误提示 ”Call stack functions:"

我觉得很有可能使visual C++ 的问题,运行环境装全了吗?DirectX9.0及以上visual C++ 2008net.framework 3.5及以上这三个是大多数游戏的运行环境

如何关闭 PHP 报错的 Call Stack

在php.ini上修改 display_errors的值为OFF就可以了然后重启web环境~

为什么用void InitStack(LiStack *&s)那个是引用还是什么,有什么用啊

LiStack*&s那个s是指针的引用因为在函数中会改变指针的指向为了防止返回后main函数中*s的指针在调用函数中被改变指向以至于丢失地址的情况所以使用了指向同一指针别名你也可以使用指针的指针

Delphi中 j:=i to high(frmstack) 怎么理解

请描述详细些

wpf做一个居中的stackpannel

怎么不支持居中呢,设置stackpanel的VerticalAlignment="Center"不就可以了么

华为拥抱OpenStack、力推企业云

华为要做公有云?2015年4~5月间,华为要做公有云的传闻令国内的云厂商颇为惊讶,消息一度令媒体兴奋了好一阵时间。7月30日,华为在北京正式对外宣布其云服务战略,只不过“公有云”的名字再没有被提及。这是自2010年华为首次发布 云计算 战略以来的另一个重要节点。 在7月30日的发布会上,华为轮值CEO徐直军表示:“云服务正在成为企业IT的新模式,这已经成为产业界的共识。为了满足企业市场客户与合作伙伴在网络时代的新需求,华为决定推出企业云服务,这是华为ICT产品和解决方案的自然延伸。”目前华为在全球已部署了255个云数据中心,云计算虚拟机超过70万个。此外,华为在全球拥有5个云计算研发中心,相关的研发人员超10000人。 9月18日,一年一度的华为云计算大会(HCC2015)在上海世博中心开幕。美国《连线》杂志的Kevin Kelly在主题演讲中表示,云就是未来。他预言,2020年,将有60%的应用运营在云上,全球现有的9000多家云计算公司已经为人类提供了各种各样的产品和服务。 徐直军指出,企业的IT 架构 要云化不是一件容易的事情,需要全生态链的共同努力。公有云显然并不是华为的优先选择,与运营商合作才是最好的方式。华为IT产品线总裁郑叶来则进一步阐述了华为云计算的概念,即虚拟化纪元是Cloud 1.0的特征,以资源为核心则是Cloud 2.0的表现,以及以应用为核心的Cloud 3.0将是未来云计算的趋势。 全面拥抱 OpenStack 在本年度的华为云计算大会(HCC2015)上,华为发布了基于OpenStack的云 操作系统 FusionSphere 6.0,任何基于社区版本的第三方应用无需改动都能运行在FusionSphere上。在笔者看来,FusionSphere 6.0在网络部分对 SDN 技术的集成管理是值得关注的部分。此外,基于OpenStack的跨数据中心云灾备解决方案也一并推出。 华为云计算首席架构师顾炯炯在接受InfoQ采访时表示,目前全球有300多家厂商参与OpenStack贡献,华为从G版本开始参与社区,在最新L版本(受访时)中的综合贡献排名第六,而三年前华为的排名只不过是第二十名。FusionSphere坚持开放原则,即拥抱开源、高于开源、回馈开源。在19日的开源与云应用主题论坛上,顾炯炯详细介绍了华为的公有云架构设计,听众云集以至于笔者未能挤进会场只好站在门外听完顾大师的演讲。顾炯炯在演讲中透露,除了全面拥抱OpenStack,华为FusionSphere还基于开源的Cloud Foundry集成了DevOps技术支持。作为华为三大软件之一,FusionSphere实现了与华为硬件的解耦,并通过了全球300多家主流硬件厂商的兼容验证。 在开源社区版本的基础上,华为FusionSphere系统做了如下产品化增强: HA framework:解决OpenStack管理进程存在单实例单点故障的问题。支持OpenStack的服务多实例负荷分担方式部署,单个物理服务故障的时候不影响OpenStack功能的使用。 Auto Deployment:数据中心内的所有物理服务器都可以被自动化的安装并纳入云资源池管理。安装服务通过PXE方式将Hypervisor、OpenStack等必须的云平台软件包按照配置部署到对应的物理服务器中。实现整个云平台的快速安装和快速扩容。 Smooth upgrade:提供采用UI界面的升级工具实现全系统的平滑升级。升级过程中通过将虚拟机从被升级节点迁移到其它节点的方式保证虚拟机业务不中断。 Log & Monitor:提供全系统的操作日志记录与性能监控功能。监控全系统的物理服务器性能数据和虚拟机的性能数据。 API proxy:通过API proxy实现OpenStack内部管理网络与外部网络的隔离,提升openStack服务的网络安全性。 Backup:提供全系统的管理数据备份功能。包括OpenStack的所有管理数据的备份和FusionMananger管理数据的备份功能。 除了在OpenStac外围做了产品化增强,华为还在OpenStack和KVM里面针对NFV做了功能增强,如资源调度功能、性能优化、高可用HA。 网络、存储以及容器 网络与存储目前仍然是云计算最赚钱的业务,2015年6月,IDC报告显示华为存储全球收入增长率连续七个季度第一。在今年的华为云计算大会(HCC2015)上,华为联合QLogic基于25Gb以太网技术联合发布了横向扩展文件存储系统。通过收购博通的NS2技术,QLogic在以太网市场的占有率达到了26%之多。华为存储产品线副总裁肖苡在接受媒体采访时认为,未来高端存储介质将走向SSD,海量数据必然会影响企业数据存储的架构,数据中心横向扩展将面临更大的挑战。数据中心建设对以太网技术的要求也从10Gb这个量级提高到100Gb的量级。QLogic亚太区资深首席产品经理陈介颂在演讲中表示,25Gb技术将使带宽和性能提升2.5倍,同时端口成本降低50%,通过线性扩展系统整体带宽可达400GB/s,这对高负载I/O的用户来说是一个令人眼前一亮的提升。此外,采用RoCE协议也大大降低了CPU负载和网络延时。当然,这些高性能需要华为硬件设备的支撑。 华为企业核心网解决方案总经理杨军在接受媒体采访时表示,企业云通信在快速增长,占比将从2015年的20%增长到2019年的50%,市场规模超过200亿元。华为企业云通信支持SaaS和PaaS两个层面的服务,企业可以在公有云或者自己的私有云上部署。作为较早支持NFV的厂商,华为凭借长期以来运营商市场的经验,可以通过定制化解决系统对接、集成和升级等等问题。华为企业BG UC&C MKT与解决方案销售部部长林明则指出,随着互联网服务的边界越来越模糊,未来云通信的发展将基于统一的基础,通信的可靠性、稳定性需求会越来越高,针对横向扩展的问题,目前的SDK是一个过渡方案。华为做的事情总结起来有两点,即向上开放API,向下开放SDK。 当笔者问到对容器技术的支持时,华为云计算首席架构师顾炯炯表示,随着IT业务越来越互联网化,应用弹性问题其实并没有非常好的被解决。华为会考虑将 Docker 与OpenStack相结合,华为有一个开源项目作为Docker调度与编排的引擎,可以实现在基础设施层面对容器管理的自动化。这跟OpenStack基础设施云服务形成一个优势互补整体解决方案。因此,容器与 微服务 将在未来一段时间呈现并存的关系。当笔者追问华为容器云服务的进展时,顾大师表示今年年底华为将发布一个在线 测试 版的容器服务。

Win7系统安装bluestacks模拟器及修改教学

都是:注册表打开方式:win+r(或者点击-开始-运行),然後输入regedit回车找到{HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersion}分支,并在右侧区域找到名为“ProgramFilesDir”和“ProgramFilesPath”的键值比如可以改成D:ProgramFiles~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~以上对WIN-XP有用~用在WIN7上面会死很惨!因为你安装bluestacks时...他确实会依你修改安装路径来安装...但问题来了!WIN7太聪明也是一大遗憾-.-因为你把系统内定安装路径改D:ProgramFiles...等重新开机後...只剩bluestacks能用~其它之前安装的软体全不能用了!因为WIN7自动把之前安装的软体~安装路径原本C:ProgramFiles...全改成路径改D:ProgramFiles...我试过C:+D:都放bluestacks~把系统内定安装路径改回C:ProgramFiles...利用注册表把bluestacks相关的都改为D:ProgramFiles...此时开启bluestacks...原本只要几分钟内能开启...现在变等最久2小时了!还在开启中的画面-.-移除...修改...安装...以上动作算一回合...至少做快10次以上才搞清楚...那些修改对WIN7有用~那些是无效且更惨的!安装好RevoUninstaller~开启RevoUninstaller~选好bluestacks...点解除安装...他会跳出选项...点最下面=>进阶!其它就交给他噜~等他跑完...连重开机都不用!可直接重新安装bluestacks~~~~~~~~~~~~~~~~~~~~~~~~~~还现在正式进如主题!WIN7其实是通过DOS命令修改~(WIN+R或者点击开始-运行-输入CMD)看你哪个碟空间最大~依我...只剩E碟-.-(没几人硬碟比我吃紧吧-.-)所以先建立E:BlueStacks的资料夹~命令提示符中输入(WIN+R或者点击开始-运行-输入CMD)出现久违的DOS画面...将以下复制=>贴上=>执行~mklink/j"C:ProgramDataBlueStacks""E:BlueStacks"(“E”是希望安装的硬碟名称)如正确DOS画面会出现:以建立C:ProgramDataBlueStacks的连接<<===>>E:BlueStacks此时你的C:ProgramData底下会出现一个像捷径的BlueStacks资料夹~这时可以开始安装最新版:BlueStacks_HD_AppPlayerPro_setup_0.7.14.901_REL(www.bluestacks.net.cn)等安装好...BlueStacks确定能进入且操作没问题...先把BlueStacks关闭...开始进修改阶段~预防万一...先同时按Ctrl+Ait+Delete这3个键~或是滑鼠点桌面最下工作列点右键~点选=>启动工作管理员~点选=>第2项=>处理程序~把BlueStacks相关得都点选=>结束处理程序~现在来修改其它占空间的东西~修改Data.sparsefs,SDCard.sparsefs文件存放位置~依我为例:一样是通过注册表打开找到:注册表打开方式:win+r(或者点击-开始-执行),然後输入regedit回车找到这2个:{HKEY_LOCAL_MACHINESOFTWAREBlueStacksGuestsAndroidBlockDevice}把里面的1跟2的path值...把原本的path...C:ProgramDataBlueStacksAndroidData.sparsefs改为E:BlueStacksAndroidData.sparsefs然後回去上面第2层~{HKEY_LOCAL_MACHINESOFTWAREBlueStacksGuestsAndroid}点两下右边视窗中的『Memory』选择十进位~把原本的768改为您想使用的记忆体容量~※注意:需考量您系统记忆体加上BlueStacks是否够用!(我记忆体只有3G.所以我设1024)关闭注册表~开启BlueStacks....成功~可以收工噜^^PS:怕此篇教学无法另存下来的~我有另外做网页档工你们抓下来收藏~

如何更换 OpenStack 默认的 Hypervisor

OpenStack 几乎支持现在所有主流的虚拟技术和 Hypervisor,如 KVM, Hyper-V, LXC, QEMU, UML, VMWare ESX/ESXi, Xen/XenServer 等,未来还会支持 OpenVZ 和 VirtualBox. 不过 OpenStack 首选的 Hypervisor 是 KVM,OpenStack 安装后默认使用的是 KVM (–libvirt_type=kvm),不需要特别配置。如果由于某种原因,比如服务器 CPU 不支持 Intel VT-x/AMD-V 不能使用 KVM 或者想简单尝试一下另外一种 Hypervisor 怎么办呢?方法很容易,1、更改 OpenStack Nova 的配置文件(–libvirt_type);2、给所有的 Compute 结点装上相应的 Hypervisor 就可以了。以下以 LXC 为例来说明如何更换 OpenStack Nova 的 Hypervisor,LXC 使用的是与 Xen 和 KVM 完全不同的虚拟技术,和 OpenVZ 的容器技术有点类似。  首先在所有 openstack nova compute 结点上替换现有的 nova-compute-kvm 到 nova-compute-lxc:  $ sudo apt-get install nova-compute-lxc  LXC 使用 cgroup 文件系统来限制资源和进程,libvirt 需要 cgroup 文件系统来运行 LXC,我们只要在 nova compute 上创建一个 ctroups 目录并且在 /etc/fstab 最后加上 none /cgroups cgroup cpuacct,memory,devices,cpu,freezer,blkio 0 0 这行就可以了,别忘了重启系统:  $ sudo mkdir /cgroups$ vi /etc/fstabnone /cgroups cgroup cpuacct,memory,devices,cpu,freezer,blkio 0 0$ sudo reboot  重启后可以看到 /cgroups 下面多了很多东西:  $ ls /cgroup/blkio.io_merged cpu.sharesblkio.io_queued devices.allowblkio.io_service_bytes devices.denyblkio.io_serviced devices.listblkio.io_service_time libvirtblkio.io_wait_time memory.failcntblkio.reset_stats memory.force_emptyblkio.sectors memory.limit_in_bytesblkio.throttle.io_service_bytes memory.max_usage_in_bytesblkio.throttle.io_serviced memory.memsw.failcntblkio.throttle.read_bps_device memory.memsw.limit_in_bytesblkio.throttle.read_iops_device memory.memsw.max_usage_in_bytesblkio.throttle.write_bps_device memory.memsw.usage_in_bytesblkio.throttle.write_iops_device memory.move_charge_at_immigrateblkio.time memory.numa_statblkio.weight memory.oom_controlblkio.weight_device memory.soft_limit_in_bytescgroup.clone_children memory.statcgroup.event_control memory.swappinesscgroup.procs memory.usage_in_bytescpuacct.stat memory.use_hierarchycpuacct.usage notify_on_releasecpuacct.usage_percpu release_agentcpu.rt_period_us taskscpu.rt_runtime_us  修改 OpenStack Nova 配置,将 nova-compute.conf 里面的 –libvirt_type=kvm 改成 lxc:  $ sudo vi /etc/nova/nova-compute.conf--libvirt_type=lxc$ sudo restart nova-compute  重启所有 nova compute 结点上的 nova-compute 服务,有必要的话重启所有 nova compute 结点。  那镜像怎么办呢?以前为 KVM 上传的镜像也可以用在 LXC 上吗?嗯,可以。下载 oneiric-server-cloudimg-amd64.tar.gz 解压并镜像到 OpenStack:  $ wget http://uec-images.ubuntu.com/oneiric/current/oneiric-server-cloudimg-amd64.tar.gz$ tar zxvf oneiric-server-cloudimg-amd64.tar.gz$ euca-bundle-image -i oneiric-server-cloudimg-amd64.img $ euca-upload-bundle -b oneiric -m /tmp/oneiric-server-cloudimg-amd64.img.manifest.xml $ euca-register oneiric/oneiric-server-cloudimg-amd64.img.manifest.xml$ euca-describe-images IMAGE ami-00000001 oneiric/oneiric-server-cloudimg-amd64.img.manifest.xml available private x86_64 machine instance-store$ euca-run-instances -k vpsee -t m1.tiny ami-00000001$ euca-describe-instances RESERVATION r-4bbu7bd7 sanbi defaultINSTANCE i-00000001 ami-00000001 172.16.39.6 172.16.39.6 running vpsee (vpseecloud, node00) 0 m1.tiny 2012-01-20T08:04:05Z nova ami-00000000 ami-00000000  需要注意的是,OpenStack 目前不支持混合 Hypervisor,也就是说所有 nova compute 结点上必须使用同一种 Hypervisor,不过支持混合 Hypervisor 的 OpenStack 正在计划开发中。

JAVA中code segment,data segment,heap,stack分别存放什么内容?

纠正两点错误:1、"对象引用都是在栈里的",不能这么说,static Integer i=new Integer(5);这里的引用变量在datasegment里2、 “data segment那个不太清楚,只知道存放常量和静态的”,不是放常量,是字符串常量
 首页 上一页  1 2 3 4