/*---------------------------------------------------------------------------*/
int
main(void)
{
  clock_init();                                   // 初始化 睡眠定时器 必要
  soc_init();                                     // 还函数中启动了全局中断 可修改
  rtimer_init();                                  // rtimer为定时器1 必要

  /* Init LEDs here */
  leds_init();                                    // 初始化LED 可修改
  leds_off(LEDS_ALL);                             // 关闭所有LED 非必要
  fade(LEDS_GREEN);                               // 绿色闪烁一下 非必要

  /* initialize process manager. */
  process_init();                                 // 任务初始化 必要

  /* Init UART */
  uart0_init();                                   // 初始化串口0,先用于调试,可修改

#if DMA_ON
  dma_init();                                     // 非必要
#endif

#if SLIP_ARCH_CONF_ENABLE
  slip_arch_init(0);
#else
  uart0_set_input(serial_line_input_byte);
  serial_line_init();
#endif
  fade(LEDS_RED);                                 // 红色LED闪烁一下 非必要

  // 打印若干提示信息 非必要 可修改
  putstring("**************************************\r\n");
  putstring(CONTIKI_VERSION_STRING "\r\n");       // 打印若干信息
  putstring("Platform CC2530 NB\r\n");
  switch(CHIPID) {
  case 0xA5:
    putstring("CC2530");
    break;
  case 0xB5:
    putstring("CC2531");
    break;
  case 0x95:
    putstring("CC2533");
    break;
  case 0x8D:
    putstring("CC2540");
    break;
  }

  putstring("-F");
  switch(CHIPINFO0 & 0x70) {
  case 0x40:
    putstring("256,");
    break;
  case 0x30:
    putstring("128,");
    break;
  case 0x20:
    putstring("64,");
    break;
  case 0x10:
    putstring("32,");
    break;
  }
  puthex(CHIPINFO1 + 1);
  putstring("KB SRAM\r\n");

#if STARTUP_VERBOSE

  PUTSTRING("Net: ");                      // NETWORK名称
  PUTSTRING(NETSTACK_NETWORK.name);
  PUTCHAR('\r');PUTCHAR('\n');              
  PUTSTRING("MAC: ");                      // MAC名称
  PUTSTRING(NETSTACK_MAC.name);
  PUTCHAR('\r');PUTCHAR('\n');
  PUTSTRING("RDC: ");                      // RDC名称
  PUTSTRING(NETSTACK_RDC.name);
  PUTCHAR('\r');PUTCHAR('\n');
  PUTSTRING("**************************************\r\n");
#endif

  watchdog_init();                         // 初始化看门狗

  /* Initialise the H/W RNG engine. */
  random_init(0);                           //

  /* start services */
  process_start(&etimer_process, NULL);     // 启动etimer任务
  ctimer_init();                            // ctimer初始化 

  /* initialize the netstack */
  netstack_init();                          // NET协议栈初始化
  set_rime_addr();                          // 设置RIME地址,相当于设置IP地址

#if BUTTON_SENSOR_ON || ADC_SENSOR_ON
  process_start(&sensors_process, NULL);
  BUTTON_SENSOR_ACTIVATE();
  ADC_SENSOR_ACTIVATE();
#endif

#if UIP_CONF_IPV6                         // 非常重要,启动TCPIP查询任务
  memcpy(&uip_lladdr.addr, &rimeaddr_node_addr, sizeof(uip_lladdr.addr));
  queuebuf_init();
  process_start(&tcpip_process, NULL);
#endif /* UIP_CONF_IPV6 */

#if VIZTOOL_CONF_ON
  process_start(&viztool_process, NULL);
#endif

  energest_init();                        // 能量估计初始化,但是该功能未被打开
  ENERGEST_ON(ENERGEST_TYPE_CPU);         // 该功能未被打开

  autostart_start(autostart_processes);   // 启动被定义为自动启动的任务

  watchdog_start();                       // 看门狗初始化     

  fade(LEDS_YELLOW);                      // 黄色LED闪烁,完成所有初始化工作

  while(1) {
    do {
      /* Reset watchdog and handle polls and events */
      watchdog_periodic();                // 喂狗操作
      r = process_run();
    } while(r > 0);
#if SHORTCUTS_CONF_NETSTACK               // 循环查询无线输入数据包长度 tcpip_process
    len = NETSTACK_RADIO.pending_packet();
    if(len) {
      packetbuf_clear();
      len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
      if(len > 0) {
        packetbuf_set_datalen(len);
        NETSTACK_RDC.input();
      }
    }
#endif

#if LPM_MODE                              // 该宏被定义为0,没有休眠功能,以下代码均无效
#if (LPM_MODE==LPM_MODE_PM2)
    SLEEP &= ~OSC_PD;            /* Make sure both HS OSCs are on */
    while(!(SLEEP & HFRC_STB));  /* Wait for RCOSC to be stable */
    CLKCON |= OSC;               /* Switch to the RCOSC */
    while(!(CLKCON & OSC));      /* Wait till it's happened */
    SLEEP |= OSC_PD;             /* Turn the other one off */
#endif /* LPM_MODE==LPM_MODE_PM2 */

    /*
     * Set MCU IDLE or Drop to PM1. Any interrupt will take us out of LPM
     * Sleep Timer will wake us up in no more than 7.8ms (max idle interval)
     */
    SLEEPCMD = (SLEEPCMD & 0xFC) | (LPM_MODE - 1);

#if (LPM_MODE==LPM_MODE_PM2)
    /*
     * Wait 3 NOPs. Either an interrupt occurred and SLEEP.MODE was cleared or
     * no interrupt occurred and we can safely power down
     */
    __asm
      nop
      nop
      nop
    __endasm;

    if(SLEEPCMD & SLEEP_MODE0) {
#endif /* LPM_MODE==LPM_MODE_PM2 */

      ENERGEST_OFF(ENERGEST_TYPE_CPU);
      ENERGEST_ON(ENERGEST_TYPE_LPM);

      /* We are only interested in IRQ energest while idle or in LPM */
      ENERGEST_IRQ_RESTORE(irq_energest);

      /* Go IDLE or Enter PM1 */
      PCON |= PCON_IDLE;

      /* First instruction upon exiting PM1 must be a NOP */
      __asm
        nop
      __endasm;

      /* Remember energest IRQ for next pass */
      ENERGEST_IRQ_SAVE(irq_energest);

      ENERGEST_ON(ENERGEST_TYPE_CPU);
      ENERGEST_OFF(ENERGEST_TYPE_LPM);

#if (LPM_MODE==LPM_MODE_PM2)
      SLEEPCMD &= ~SLEEP_OSC_PD;            /* Make sure both HS OSCs are on */
      while(!(SLEEPCMD & SLEEP_XOSC_STB));  /* Wait for XOSC to be stable */
      CLKCONCMD &= ~CLKCONCMD_OSC;              /* Switch to the XOSC */
      /*
       * On occasion the XOSC is reported stable when in reality it's not.
       * We need to wait for a safeguard of 64us or more before selecting it
       */
      clock_delay(10);
      while(CLKCONCMD & CLKCONCMD_OSC);         /* Wait till it's happened */
    }
#endif /* LPM_MODE==LPM_MODE_PM2 */
#endif /* LPM_MODE */
  }
}
/*---------------------------------------------------------------------------*/
int
main(void)
{
    /* Hardware initialization */
    clock_init();
    soc_init();
    rtimer_init();

    /* Init LEDs here */
    leds_init();
    leds_off(LEDS_ALL);
    fade(LEDS_GREEN);

    /* initialize process manager. */
    process_init();

    /* Init UART */
    uart0_init();

#if DMA_ON
    dma_init();
#endif

#if SLIP_ARCH_CONF_ENABLE
    slip_arch_init(0);
#else
    uart0_set_input(serial_line_input_byte);
    serial_line_init();
#endif
    fade(LEDS_RED);

    PUTSTRING("##########################################\n");
    putstring(CONTIKI_VERSION_STRING "\n");
    putstring("TI SmartRF05 EB\n");
    switch(CHIPID) {
    case 0xA5:
        putstring("cc2530");
        break;
    case 0xB5:
        putstring("cc2531");
        break;
    case 0x95:
        putstring("cc2533");
        break;
    case 0x8D:
        putstring("cc2540");
        break;
    }

    putstring("-F");
    switch(CHIPINFO0 & 0x70) {
    case 0x40:
        putstring("256, ");
        break;
    case 0x30:
        putstring("128, ");
        break;
    case 0x20:
        putstring("64, ");
        break;
    case 0x10:
        putstring("32, ");
        break;
    }
    puthex(CHIPINFO1 + 1);
    putstring("KB SRAM\n");

    PUTSTRING("\nSDCC Build:\n");
#if STARTUP_VERBOSE
#ifdef HAVE_SDCC_BANKING
    PUTSTRING("  With Banking.\n");
#endif /* HAVE_SDCC_BANKING */
#ifdef SDCC_MODEL_LARGE
    PUTSTRING("  --model-large\n");
#endif /* SDCC_MODEL_LARGE */
#ifdef SDCC_MODEL_HUGE
    PUTSTRING("  --model-huge\n");
#endif /* SDCC_MODEL_HUGE */
#ifdef SDCC_STACK_AUTO
    PUTSTRING("  --stack-auto\n");
#endif /* SDCC_STACK_AUTO */

    PUTCHAR('\n');

    PUTSTRING(" Net: ");
    PUTSTRING(NETSTACK_NETWORK.name);
    PUTCHAR('\n');
    PUTSTRING(" MAC: ");
    PUTSTRING(NETSTACK_MAC.name);
    PUTCHAR('\n');
    PUTSTRING(" RDC: ");
    PUTSTRING(NETSTACK_RDC.name);
    PUTCHAR('\n');

    PUTSTRING("##########################################\n");
#endif

    watchdog_init();

    /* Initialise the H/W RNG engine. */
    random_init(0);

    /* start services */
    process_start(&etimer_process, NULL);
    ctimer_init();

    /* initialize the netstack */
    netstack_init();
    set_rime_addr();

#if BUTTON_SENSOR_ON || ADC_SENSOR_ON
    process_start(&sensors_process, NULL);
    BUTTON_SENSOR_ACTIVATE();
    ADC_SENSOR_ACTIVATE();
#endif

#if UIP_CONF_IPV6
    memcpy(&uip_lladdr.addr, &rimeaddr_node_addr, sizeof(uip_lladdr.addr));
    queuebuf_init();
    process_start(&tcpip_process, NULL);
#endif /* UIP_CONF_IPV6 */

#if VIZTOOL_CONF_ON
    process_start(&viztool_process, NULL);
#endif

    energest_init();
    ENERGEST_ON(ENERGEST_TYPE_CPU);

    autostart_start(autostart_processes);

    watchdog_start();

    fade(LEDS_YELLOW);

    while(1) {
        do {
            /* Reset watchdog and handle polls and events */
            watchdog_periodic();

#if CLOCK_CONF_STACK_FRIENDLY
            if(sleep_flag) {
                if(etimer_pending() &&
                        (etimer_next_expiration_time() - clock_time() - 1) > MAX_TICKS) {
                    etimer_request_poll();
                }
                sleep_flag = 0;
            }
#endif
            r = process_run();
        } while(r > 0);
        len = NETSTACK_RADIO.pending_packet();
        if(len) {
            packetbuf_clear();
            len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
            if(len > 0) {
                packetbuf_set_datalen(len);
                NETSTACK_RDC.input();
            }
        }

#if LPM_MODE
#if (LPM_MODE==LPM_MODE_PM2)
        SLEEP &= ~OSC_PD;            /* Make sure both HS OSCs are on */
        while(!(SLEEP & HFRC_STB));  /* Wait for RCOSC to be stable */
        CLKCON |= OSC;               /* Switch to the RCOSC */
        while(!(CLKCON & OSC));      /* Wait till it's happened */
        SLEEP |= OSC_PD;             /* Turn the other one off */
#endif /* LPM_MODE==LPM_MODE_PM2 */

        /*
         * Set MCU IDLE or Drop to PM1. Any interrupt will take us out of LPM
         * Sleep Timer will wake us up in no more than 7.8ms (max idle interval)
         */
        SLEEPCMD = (SLEEPCMD & 0xFC) | (LPM_MODE - 1);

#if (LPM_MODE==LPM_MODE_PM2)
        /*
         * Wait 3 NOPs. Either an interrupt occurred and SLEEP.MODE was cleared or
         * no interrupt occurred and we can safely power down
         */
        __asm
        nop
        nop
        nop
        __endasm;

        if(SLEEPCMD & SLEEP_MODE0) {
#endif /* LPM_MODE==LPM_MODE_PM2 */

            ENERGEST_OFF(ENERGEST_TYPE_CPU);
            ENERGEST_ON(ENERGEST_TYPE_LPM);

            /* We are only interested in IRQ energest while idle or in LPM */
            ENERGEST_IRQ_RESTORE(irq_energest);

            /* Go IDLE or Enter PM1 */
            PCON |= PCON_IDLE;

            /* First instruction upon exiting PM1 must be a NOP */
            __asm
            nop
            __endasm;

            /* Remember energest IRQ for next pass */
            ENERGEST_IRQ_SAVE(irq_energest);

            ENERGEST_ON(ENERGEST_TYPE_CPU);
            ENERGEST_OFF(ENERGEST_TYPE_LPM);

#if (LPM_MODE==LPM_MODE_PM2)
            SLEEPCMD &= ~SLEEP_OSC_PD;            /* Make sure both HS OSCs are on */
            while(!(SLEEPCMD & SLEEP_XOSC_STB));  /* Wait for XOSC to be stable */
            CLKCONCMD &= ~CLKCONCMD_OSC;              /* Switch to the XOSC */
            /*
             * On occasion the XOSC is reported stable when in reality it's not.
             * We need to wait for a safeguard of 64us or more before selecting it
             */
            clock_delay(10);
            while(CLKCONCMD & CLKCONCMD_OSC);         /* Wait till it's happened */
        }
#endif /* LPM_MODE==LPM_MODE_PM2 */
#endif /* LPM_MODE */
    }
}