Beispiel #1
0
/*********************************************************** 
函数功能:按键唤醒初始化
入口参数:
出口参数:
备注说明:1 按键唤醒后调用
          2 初始化唤醒下的任务
          
***********************************************************/
void PowerSleepWakeInit(void)
{	
	//按键唤醒后跑高速RC//后面有必要再调
	SwitchToHighCR(CLOCK_MAINPLL_OFF, CLOCK_MAIN_OSC_OFF, CLOCK_SUB_OSC_ON, BaseSysetmClockDIV8);
	//初始化主任务
	TaskInit(SYS_TICK_LOW, 0);

	//硬件设置为低功耗模式
	KeyPowerDownInit();
	DRV_LCD_Init(1);	//7天后需要重新打开LCD
	KeyPowerDownInit();
    DRV_RTC_FlashTask();
	//Clock_CheckDST();
	//存储器相关
	IIcPowerDownInit(); 
	//MX25L3206_IOPowerDownInt();//!
    
	//2 应用模块掉电初始化,保存数据等
	//==============================================================
	Init_DispPowerDown();
	//KeyScrTaskAdd(PowerWakeTierRst);
	PowerWakeTierRst();
	//==============================================================
	SleepDispTimerRst();   //按键重新开启7天
	TaskStart();
}
Beispiel #2
0
int KernelMain(void) {
    printf("\n\n\nStart NOOS RTOS kernel...............\n");

#ifdef _SHOW_EXCEPTION_HANDLER_
    __asm__ __volatile__ (
            "SWI 0x121212\n"
            );
    return 0;
#endif // _SHOW_EXCEPTION_HANDLER_

    InitScheduler();
    InitTask();
    InitInterrupt();
    InitTick();
    InitTimer();

    TaskInit(&initTask, InitTaskMain, 0, CONFIG_MAX_PRIORITY - 1, 20, initStack, sizeof(initStack));

    while (1) {
        /* task idle */
        continue;
    }

    return 0;
}
Beispiel #3
0
/*
 ***************************************************************
 * 名称: start_task 
 * 功能: 启动任务
 * 输入: 1. *pdata:任务参数
 * 输出: NULL 
 * 返回: NULL 
 * 描述: 无 
 ***************************************************************
 */
void start_task(void *pdata)
{
    OS_CPU_SR cpu_sr = 0;
	
	pdata = pdata; 		  
	
	TaskInit();
	
	OSStatInit();					// 初始化统计任务.这里会延时1秒钟左右	
 	
	OS_ENTER_CRITICAL();			// 进入临界区(无法被中断打断)    
 	
	OSTaskCreate(uart3_task, 
				(void *)0, 
				(OS_STK*)&UART3_TASK_STK[UART3_STK_SIZE-1], 
				UART3_TASK_PRIO);
	
	OSTaskCreate(can1_task, 
				(void *)0, 
				(OS_STK*)&CAN1_TASK_STK[CAN1_STK_SIZE-1], 
				CAN1_TASK_PRIO);	
 
	OSTaskCreate(beep_task, 
				(void *)0, 
				(OS_STK*)&BEEP_TASK_STK[BEEP_STK_SIZE-1], 
				BEEP_TASK_PRIO);
 	
	OSTaskSuspend(START_TASK_PRIO);	// 挂起起始任务.
	
	OS_EXIT_CRITICAL();				// 退出临界区(可以被中断打断)
}	  
Beispiel #4
0
/*
--------------------------------------------------------------------------------
  Function name : void OSStart(WIN *pWin, THREAD *pThread)
  Author        : ZHengYongzhi
  Description   : 
                  
  Input         : ID
  Return        : 

  History:     <author>         <time>         <version>       
             ZhengYongzhi     2008/07/21         Ver1.0
  desc:         ORG
--------------------------------------------------------------------------------
*/
_ATTR_OS_CODE_
void OSStart(WIN **pWin, THREAD **pThread)
{
    void *pWinArg;
#if PRINTF_CPU_USE
    int idletime=0,sec_prev=0,sec_cur=0;
    float cpubusy=0.0;
#endif
    while(1) 
    {
        *pWin = TaskInit(&pWinArg);//task adjust,call new task code,rturn main window pointer.
        WinCreat((WIN *)NULL, *pWin, pWinArg); 
	 ConnectNumber = 0;
	 printf("wifi init start!\n");
        
        while(1) 
        { 
        #if 1
            if (SysService() != RETURN_OK)
            {
                break;
            }
            
            if (ThreadProcess(*pThread) != TRUE)
            {
                break;
            }
            
            if (WinServiceProc(*pWin) != RETURN_OK)
            {
                break;
            }
                
            if (WinKeyProc(*pWin) != RETURN_OK) 
            {
                break;
            }
           	
            WinPaintProc(*pWin);
	 #endif	

	 #if PRINTF_CPU_USE
            idletime ++;
	     sec_cur = GetSysTick()>>9;// 2^7=1.28S
	     if(sec_cur != sec_prev){
		   sec_prev = sec_cur;
		   cpubusy = 7168.0 / idletime;	// 本公式按照主程序1400转/秒为满负荷,通过指令数比得出
		   printf("CPU usage: %f %\n",cpubusy);   
		   idletime = 0;
	     }
	 #endif
		
        }
        //end the main window.
        WinDestroy(*pWin);
    }
    
}
Beispiel #5
0
/*********************************************************** 
函数功能:掉电模式初始化
入口参数:
出口参数:
备注说明:1 硬件设置为低功耗模式
          2 应用模块掉电初始化,保存数据等
          3 数据保存完后,关闭存储器
          3 设置唤醒源,进入休眠
***********************************************************/
void PowerDownInit(void)
{	
	__disable_irq();		//关闭总中断,停电处理期间不再响应中断,避免占用停电处理时间
	//初始化主任务
	TaskInit(0, 0);
	RF1MSPowerDownInit();
	//关闭RF外部中断
    Disable_ExtInt();	
	//硬件设置为低功耗模式
	LvdClose();				//关闭LVD
    MFT_FRTStop(MFT_UNIT0, FRT_CH2);
	DRV_IO_PowerDownInit();
	KeyPowerDownInit();
	DRV_ADC_Init(0);
    DRV_ADC_Off();
//	DRV_RTC_CalcSecDeviation();
    DRV_RTC_InitPowerDown();  //rtc中断初始化
    DRV_RTCSecPulsePowerDownInit();  //rtc秒脉冲初始化
    PowerDownClockCopy();
    DRV_RTC_CalcSecDeviation();
    PowerDownInitCail(); //停电下 不补偿 
	DRV_EMU_PowerDownInit();//used for EMU
	DRV_LCD_Init(1);	
	LEDPowerDownInit();
	ProtocolManagePowerDownInit();//串口
	//SPI_POWER_DOWN_Init();
	RFIOPowerDownInit();
    DRV_Calibrate_PRO_SWI_POWER_DOWN_INIT();
	//应用模块掉电初始化,保存数据等
	EnergyPowerOffProcess();
	Init_DispPowerDown();
	SleepDispTimerRst();
	//BillingPowerDownProcess();
	//EventPowerdownInit();
	MeterInfoPowerDownInit();
	
	//存储器相关
	IIcPowerDownInit(); 
	//MX25L3206_IOPowerDownInt();//!


	//设置唤醒源,进入休眠
	ScrExtInt_Init();		//轮显按键中断
    PowerExtInt_Init();
    LCD_ConfigInputIOMode(LCD_INPUT_IO_CUTOFF);
	__enable_irq();
	SwitchToLowCR(CLOCK_MAINPLL_OFF,CLOCK_MAIN_OSC_OFF,CLOCK_SUB_OSC_ON, BaseSysetmClockDIV1);
	LowPwrCon_GoToStandByMode(STB_TimerMode,STB_IO_KEEP);	//休眠
  
}
Beispiel #6
0
void main() {
  clearRAM(); //clear all ram
  DDR_init(); //intialize DDR copy registers
  //initialize and install VP's
  vpInit(); //must be called prior to other vp functions
  tx = vpInstall(TX1); //install virtual peripheral TX1
  rx = vpInstall(RX1); //install virtual peripheral RX1
  //setup tasks
  TaskInit(); //must be called prior to other task functions
  TaskSet(0,TXDEQUEUE+TASKSTART,2); // task slot 0, run "TxDequeue", every 2 taskticks
  TaskSet(1,RXENQUEUE+TASKSTART,2); // task slot 1, run "RxEnqueue", every 2 taskticks
  TaskEnable(); //master task enable (eg. enable task interrupts)
  //at this point, the interrupt should be enabled
  OPTION = RTCC_ON + RTCC_PS_OFF;
  sendString(WELCOME);
  while (1) {
    wresult = dequeue(); // get received byte (from receiver queue)
    if (wresult.high8 == 0) { //queue not empty, so result valid
      sendChar(wresult.low8); //echo received byte
    }
  }
}
Beispiel #7
0
/*********************************************************** 
函数功能:按键唤醒初始化
入口参数:
出口参数:
备注说明:1 按键唤醒后调用
          2 初始化唤醒下的任务
          
***********************************************************/
void PowerWakeSleepInit(void)
{	
	//初始化主任务
	TaskInit(0, 0);

	//硬件设置为低功耗模式
	//停电停显定时			
	if(!SleepDispTimer)
	{
		DRV_LCD_Uninit(); //关闭LCD
	}
	//存储器相关
	//MX25L3206_IOPowerDownInt();
	//2 应用模块掉电初始化,保存数据等
	Init_DispPowerDown();

	//设置唤醒源,进入休眠
	ScrExtInt_Init();		//轮显按键中断
    PowerExtInt_Init();
	//按键模式采用高速RC需要回到低速
	LCD_ConfigInputIOMode(LCD_INPUT_IO_CUTOFF);
	SwitchToLowCR(CLOCK_MAINPLL_OFF,CLOCK_MAIN_OSC_OFF,CLOCK_SUB_OSC_ON, BaseSysetmClockDIV1);
}
Beispiel #8
0
void TaskStart(void)
{
    TaskInit();

    TaskScheduler();
}
Beispiel #9
0
/*********************************************************** 
函数功能:电池上电模式初始化
入口参数:
出口参数:
备注说明:1 电池上电时调用
          2 调用每个模块初始化函数,初始化函数包括所有的硬件初始化、数据初始化、任务初始化
***********************************************************/
void PowerUpBattInit(void)
{
	//电池上电跑高速RC分频//后面有必要再调
	SwitchToHighCR(CLOCK_MAINPLL_OFF, CLOCK_MAIN_OSC_OFF, CLOCK_SUB_OSC_ON, BaseSysetmClockDIV8);
	//初始化主任务
	TaskInit(0, 0);
	RF1MSPowerDownInit();
	//关闭RF外部中断
	Disable_ExtInt();
	//硬件设置为低功耗模式
    LvdClose();				//关闭LVD
	DRV_IO_PowerDownInit();
	//存储器相关打开
	IIcPowerDownInit();	
	//MX25L3206_IOPowerDownInt();//!
	KeyPowerDownInit();
	DRV_ADC_Init(1);	//先开一下ADC
//	DRV_RTC_CalcSecDeviation();
    DRV_RTC_InitUpBatt();  //rtc中断初始化
    InitCaliVal();      //RTC温补
    PowerDownInitCail(); //停电下 不补偿
//  DRV_RTC_CalcSecDeviation();
    DRV_RTCSecPulsePowerDownInit();  //rtc秒脉冲初始化
    ClockBatteryUpInit();
    DRV_EMU_PowerDownInit();//used for EMU
    DRV_LCD_Init(1);    
	DRV_LCD_FillAll();
	LEDPowerDownInit();
	ProtocolManagePowerDownInit();//串口
    //SPI_POWER_DOWN_Init();
    RFIOPowerDownInit();
    DRV_Calibrate_PRO_SWI_POWER_DOWN_INIT();
    Feed_watchdog();
    //IIcInit();
	//存储器相关打开
	//IIcPowerDownInit();	
	//MX25L3206_IOPowerDownInt();//!
	//应用模块掉电初始化,保存数据等
   	EnergyDataInitBattery();
	//EventPowerBatteryInit();
	Init_DispPowerUpBatt();
	SleepDispTimerRst();


	//---------RTC校准处理
	DRV_ADC_StartTask();
    while(RESET != ADC12_GetScanStatusFlag(ADC12_UNIT0));
    DRV_ADC_StartTask();
    while(RESET != ADC12_GetScanStatusFlag(ADC12_UNIT0));
    DRV_ADC_StartTask();
    while(RESET != ADC12_GetScanStatusFlag(ADC12_UNIT0));
    DRV_ADC_StartTask();
    while(RESET != ADC12_GetScanStatusFlag(ADC12_UNIT0));
    DRV_ADC_StartTask();
    while(RESET != ADC12_GetScanStatusFlag(ADC12_UNIT0));
    CaliProcessTaskPowerDown();
	DRV_RTC_CalcSecDeviation();
	DRV_ADC_Init(0);	//关闭ADC
	//存储器相关关闭
	//设置唤醒源,进入休眠
    LCD_ConfigInputIOMode(LCD_INPUT_IO_CUTOFF);
    ScrExtInt_Init();		//轮显按键中断
    PowerExtInt_Init();
    
	//电池上电采用高速RC需要回到低速
	SwitchToLowCR(CLOCK_MAINPLL_OFF,CLOCK_MAIN_OSC_OFF,CLOCK_SUB_OSC_ON, BaseSysetmClockDIV1);
	LowPwrCon_GoToStandByMode(STB_TimerMode,STB_IO_KEEP);	//休眠
}
Beispiel #10
0
/*********************************************************** 
函数功能:上电模式初始化
入口参数:
出口参数:
备注说明:1 市电上电时调用
          2 调用每个模块初始化函数,初始化函数包括所有的硬件初始化、数据初始化、任务初始化
***********************************************************/
uint16 PowerUpInit(void)
{
	DRV_WD_FeedDog();		//喂狗
	//切换到高速时钟
    SwitchToMainPLL(CLOCK_SUB_OSC_ON,BaseSysetmClockDIV1,PLLMultiplier2);
    DRV_RTC_CalcSecDeviation();           //上电马上进行补偿
	/*设置中断优先级*/
	Config_SystemClock_Priority();
    LvdOpen();		//打开LVD
    EXTI_DisableInt(EXTI_CH1);
	if(PowerDownDetect() != 0)
	{
		return 0;
	}
	/*初始化主任务*/
	TaskInit(SYS_TICK_LOW, SYS_TICK_HIGH);	//只初始化,不启动		
	/*初始化驱动模块*/
	DRV_IO_Init();
	Drv_Calibrate_Init();
	DRV_Calibrate_PRO_SWI_INIT();			//used for calibrate
	IIcInit();	
	//MX25L3206_IOInt();
	KeyInit();
	DRV_ADC_Init(1);
    DRV_ADC_On();
//	DRV_RTC_CalcSecDeviation();
    DRV_RTC_Init();  		//rtc初始化
    InitCaliVal();      	//RTC温补
    DRV_RTCSecPulseInit();  //rtc秒脉冲初始化
	DRV_LCD_Init(0);
	DRV_LCD_FillAll();
	LEDInit();
	ProtocolManageInit();	//通讯串口打开
	//RF 初始化
	RFModeChangeInit();     //RF切换模块
	RFIOPowerUpInit();
    
	if(0 == DRV_EMU_PowerUpInit())//used for EMU,load cailibrate data
	{
		return POWER_UP_INIT_FAIL;
	}
	//初始化应用模块
	ClockPowerUpInit();
//	if(POWER_UP_INIT_FAIL == TariffInit())
//	{
//		return POWER_UP_INIT_FAIL;
//	}
	//DRV_WD_FeedDog();		//?11·
	//DemandDataClear();
	//DemandInit();
	if(POWER_UP_INIT_FAIL == EnergyDataInit())
	{
		return POWER_UP_INIT_FAIL;
	}
	DRV_WD_FeedDog();		//?11·
	if(POWER_UP_INIT_FAIL == BillingPowerUpInit())
	{
		return POWER_UP_INIT_FAIL;
	}
	DRV_WD_FeedDog();		//?11·
//	if(POWER_UP_INIT_FAIL == LoadProfilePowerUpInit())
//	{
//		return POWER_UP_INIT_FAIL;
//	}
	if(POWER_UP_INIT_FAIL == FreezeInit())
	{
		return POWER_UP_INIT_FAIL;
	}
	DRV_WD_FeedDog();		//?11·
	if(POWER_UP_INIT_FAIL == EventPowerUpInit())
	{
		return POWER_UP_INIT_FAIL;
	}
	MeterInfoPowerUpInit();
	//DLMS_AA_Init();
	//------end----------
   //==============================================================
	Init_Disp();
   //==============================================================
    MeterPowerUPClearAll();         //全清,生产用
	//任务起动
   	MFT_FRTStart(MFT_UNIT0, FRT_CH2);
	TaskStart();
	//RF1MSStart();
	return POWER_UP_INIT_SUCESS;
}
Beispiel #11
0
int main(int argc, char *argv[])
{
	u2_t *up;
	int i;
	char s[32];
	
	// enable generation of core file in /tmp
	scall("core_pattern", system("echo /tmp/core-%e-%s-%u-%g-%p-%t > /proc/sys/kernel/core_pattern"));
	const struct rlimit unlim = { RLIM_INFINITY, RLIM_INFINITY };
	scall("setrlimit", setrlimit(RLIMIT_CORE, &unlim));
	
	for (i=1; i<argc; ) {
		if (strcmp(argv[i], "-bg")==0) { background_mode = TRUE; bg=1; }
		if (strcmp(argv[i], "-off")==0) do_off = 1;
		if (strcmp(argv[i], "-down")==0) down = 1;
		if (strcmp(argv[i], "+gps")==0) do_gps = 1;
		if (strcmp(argv[i], "-gps")==0) do_gps = 0;
		if (strcmp(argv[i], "+sdr")==0) do_sdr = 1;
		if (strcmp(argv[i], "-sdr")==0) do_sdr = 0;
		if (strcmp(argv[i], "+fft")==0) do_fft = 1;

		if (strcmp(argv[i], "-stats")==0 || strcmp(argv[i], "+stats")==0) {
			if (i+1 < argc && isdigit(argv[i+1][0])) {
				i++; print_stats = strtol(argv[i], 0, 0);
			} else {
				print_stats = 1;
			}
		}
		
		if (strcmp(argv[i], "-eeprom")==0) create_eeprom = true;
		if (strcmp(argv[i], "-cmap")==0) color_map = 1;
		if (strcmp(argv[i], "-sim")==0) wf_sim = 1;
		if (strcmp(argv[i], "-real")==0) wf_real = 1;
		if (strcmp(argv[i], "-time")==0) wf_time = 1;
		if (strcmp(argv[i], "-port")==0) { i++; alt_port = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-p")==0) { alt_port = 8074; }
		if (strcmp(argv[i], "-dump")==0 || strcmp(argv[i], "+dump")==0) { i++; ev_dump = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-flip")==0) wf_flip = 1;
		if (strcmp(argv[i], "-start")==0) wf_start = 1;
		if (strcmp(argv[i], "-mult")==0) wf_mult = 1;
		if (strcmp(argv[i], "-multgen")==0) wf_mult_gen = 1;
		if (strcmp(argv[i], "-wmax")==0) wf_max = 1;
		if (strcmp(argv[i], "-olap")==0) wf_olap = 1;
		if (strcmp(argv[i], "-meas")==0) meas = 1;
		
		// do_fft
		if (strcmp(argv[i], "-none")==0) unwrap = 0;
		if (strcmp(argv[i], "-norm")==0) unwrap = 1;
		if (strcmp(argv[i], "-rev")==0) unwrap = 2;
		if (strcmp(argv[i], "-qi")==0) rev_iq = 1;
		if (strcmp(argv[i], "-ineg")==0) ineg = 1;
		if (strcmp(argv[i], "-qneg")==0) qneg = 1;
		if (strcmp(argv[i], "-file")==0) fft_file = 1;
		if (strcmp(argv[i], "-fftsize")==0) { i++; fftsize = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-fftuse")==0) { i++; fftuse = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-np")==0) { i++; noisePwr = strtol(argv[i], 0, 0); }

		if (strcmp(argv[i], "-rcordic")==0) rx_cordic = 1;
		if (strcmp(argv[i], "-rcic")==0) rx_cic = 1;
		if (strcmp(argv[i], "-rcic2")==0) rx_cic2 = 1;
		if (strcmp(argv[i], "-rdump")==0) rx_dump = 1;
		if (strcmp(argv[i], "-wcordic")==0) wf_cordic = 1;
		if (strcmp(argv[i], "-wcic")==0) wf_cic = 1;
		if (strcmp(argv[i], "-clkg")==0) spi_clkg = 1;
		
		if (strcmp(argv[i], "-wspr")==0) { i++; wspr = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-avg")==0) { i++; navg = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-tone")==0) { i++; tone = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-slc")==0) { i++; do_slice = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-rx")==0) { i++; rx_num = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-wf")==0) { i++; wf_num = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-spispeed")==0) { i++; spi_speed = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-spi")==0) { i++; spi_delay = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-ch")==0) { i++; gps_chans = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-y")==0) { i++; rx_yield = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-p0")==0) { i++; p0 = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-p1")==0) { i++; p1 = strtol(argv[i], 0, 0); }
		if (strcmp(argv[i], "-p2")==0) { i++; p2 = strtol(argv[i], 0, 0); }
		
		i++;
		while (i<argc && ((argv[i][0] != '+') && (argv[i][0] != '-'))) {
			i++;
		}
	}
	
	lprintf("KiwiSDR v%d.%d\n", VERSION_MAJ, VERSION_MIN);
    lprintf("compiled: %s %s\n", __DATE__, __TIME__);
    
    cfg_reload(CALLED_FROM_MAIN);
	
	if (!alt_port) {
		FILE *fp = fopen("/root/.kiwi_down", "r");
		if (fp != NULL) {
			fclose(fp);
			lprintf("down by lock file\n");
			down = 1;
		}
	}
    
	TaskInit();

	bool need_hardware = (do_gps || do_sdr) && !down;

	// called early, in case another server already running so we can detect the busy socket and bail
	web_server_init(WS_INIT_CREATE);

	if (need_hardware) {
		peri_init();
		fpga_init();
		//pru_start();
		
		u2_t ctrl = CTRL_EEPROM_WP;
		ctrl_clr_set(0xffff, ctrl);
		
		if (do_off) {
			printf("ADC_CLOCK *OFF*\n");
			xit(0);
		}

#ifdef BUILD_PROTOTYPE
		if (!do_gps)		// prevent interference to GPS by external ADC clock on prototype
#endif
		{
			ctrl |= adc_clock_enable? CTRL_OSC_EN : CTRL_ADCLK_GEN;
		}
		
		ctrl_clr_set(0, ctrl);

		if (ctrl & (CTRL_OSC_EN | CTRL_ADCLK_GEN))
			printf("ADC_CLOCK %.6f MHz, CTRL_OSC_EN=%d, CTRL_ADCLK_GEN=%d\n",
				adc_clock/MHz, (ctrl&CTRL_OSC_EN)?1:0, (ctrl&CTRL_ADCLK_GEN)?1:0);
		else
			printf("ADC_CLOCK *OFF*\n");
	}
	
	if (do_fft) {
		printf("==== IQ %s\n", rev_iq? "reverse":"normal");
		if (ineg) printf("==== I neg\n");
		if (qneg) printf("==== Q neg\n");
		printf("==== unwrap %s\n", (unwrap==0)? "none" : ((unwrap==1)? "normal":"reverse"));
	}
	
	rx_server_init();
	web_server_init(WS_INIT_START);

	if (do_gps) {
		if (!GPS_CHANS) panic("no GPS_CHANS configured");
		gps_main(argc, argv);
	}

	#if 0
	static int tty;
	if (!background_mode) {
		tty = open("/dev/tty", O_RDONLY | O_NONBLOCK);
		if (tty < 0) sys_panic("open tty");
	}
	#endif

	#if 0
	static int tty;
	if (!background_mode) {
		tty = open("/dev/tty", O_RDONLY | O_NONBLOCK);
		if (tty < 0) sys_panic("open tty");
	}
	#endif

	static u64_t stats_deadline = timer_us64() + 1000000;
	static u64_t secs;
	while (TRUE) {
	
		if (!need_hardware) {
			usleep(10000);		// pause so we don't hog the machine
			NextTask("main usleep");
			continue;
		}
	
		#if 0
		if (!background_mode && (now - last_input) >= 1000) {
			#define N_IBUF 32
			char ib[N_IBUF+1];
			int n = read(tty, ib, N_IBUF);
			printf("tty %d\n", n);
			if (n >= 1) {
				ib[n] = 0;
				webserver_collect_print_stats(1);
			}
			last_input = now;
		}
		#endif
		
		if ((secs % STATS_INTERVAL_SECS) == 0) {
			if (do_sdr) {
				webserver_collect_print_stats(!do_gps);
				if (!do_gps) nbuf_stat();
			}
			TaskCheckStacks();
		}
		NextTask("main stats");

		if (!do_gps && print_stats) {
			if (!background_mode) {
				lprintf("ECPU %4.1f%% cmds %d/%d malloc %d\n",
					ecpu_use(), ecpu_cmds, ecpu_tcmds, kiwi_malloc_stat());
				ecpu_cmds = ecpu_tcmds = 0;
				TaskDump();
				printf("\n");
			}
		}

		u64_t now_us = timer_us64();
		s64_t diff = stats_deadline - now_us;
		if (diff > 0) TaskSleep(diff);
		stats_deadline += 1000000;
		secs++;
	}
}