int main()
{
    static char address[5];

    sd_mbr_command(&startSdCmd);
    sd_softdevice_vector_table_base_set(BOOTLOADER_ADDRESS);

    // If the master boot switch has detected short or no click: boot the firmware
    if (((NRF_POWER->GPREGRET&0x86U) != 0x82U) &&
            ((NRF_POWER->GPREGRET&0x40U) != 0x40U) &&
            (*(uint32_t *)FW_ADDRESS != 0xFFFFFFFFU) ) {
        start_firmware();
    }

    if (NRF_POWER->GPREGRET&0x40U) {
        address[4] = 0xb1;
        memcpy(&address[0], (char*)&NRF_FICR->DEVICEADDR[0], 4);
        esbSetAddress(address);
    }

    NRF_POWER->GPREGRET &= ~(0x60U);

    // Enable the radio LNA
    nrf_gpio_cfg_output(RADIO_PAEN_PIN);
    nrf_gpio_pin_set(RADIO_PAEN_PIN);

    // Initialize timer module.
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);

    ble_init();
    /*
      NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSTAT_SRC_Synth;

      NRF_CLOCK->TASKS_LFCLKSTART = 1UL;
      while(!NRF_CLOCK->EVENTS_LFCLKSTARTED);
    */
    systickInit();
    buttonInit(buttonIdle);

#ifndef DEBUG_TIMESLOT
    //sd_ppi_channel_assign(0, &(NRF_TIMER1->EVENTS_COMPARE[0]), &(NRF_GPIOTE->TASKS_OUT[0]));
    //sd_ppi_channel_enable_set(PPI_CHEN_CH0_Msk);

    //NRF_PPI->CH[0].EEP = &(NRF_TIMER1->EVENTS_COMPARE[0]);
    //NRF_PPI->CH[0].TEP = &(NRF_GPIOTE->TASKS_OUT[0]);
    //NRF_PPI->CHENSET = 1;
#endif

    // Start (or continue) to blink  the LED at 0.5Hz
    //NRF_TIMER1->TASKS_STOP = 1;

    //NRF_TIMER1->MODE      = TIMER_MODE_MODE_Timer;
    //NRF_TIMER1->PRESCALER = 7;
    //NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos;
    //NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk; // | TIMER_SHORTS_COMPARE1_CLEAR_Msk;

    //NRF_TIMER1->TASKS_CLEAR = 1;

    NRF_TIMER1->CC[0] = 1*SEC; //0x1E84 ;
    NRF_TIMER1->CC[1] = 2*SEC;


    nrf_gpio_cfg_output(LED_PIN);

    nrf_gpiote_task_config(0,
                           LED_PIN,
                           NRF_GPIOTE_POLARITY_TOGGLE,
                           NRF_GPIOTE_INITIAL_VALUE_LOW);
    NRF_TIMER1->TASKS_START = 1;


    // Enable 500mA USB input and enable battery charging
    nrf_gpio_cfg_output(PM_EN1);
    nrf_gpio_pin_set(PM_EN1);
    nrf_gpio_cfg_output(PM_EN2);
    nrf_gpio_pin_clear(PM_EN2);
    nrf_gpio_cfg_output(PM_CHG_EN);
    nrf_gpio_pin_clear(PM_CHG_EN);


    // Power STM32, hold reset
    nrf_gpio_cfg_output(PM_VCCEN_PIN);
    nrf_gpio_pin_set(PM_VCCEN_PIN);
    nrf_gpio_cfg_output(STM_NRST_PIN);
    nrf_gpio_pin_clear(STM_NRST_PIN);

    // Set flow control and activate pull-down on RX data pin
    nrf_gpio_cfg_output(UART_TX_PIN);
    nrf_gpio_pin_set(UART_TX_PIN);
    nrf_gpio_cfg_output(UART_RTS_PIN);
    nrf_gpio_pin_set(UART_RTS_PIN);
    nrf_gpio_cfg_input(UART_RX_PIN, NRF_GPIO_PIN_PULLDOWN);


    nrf_gpio_pin_set(STM_NRST_PIN);

    //systickInit();
    //syslinkInit();
    //buttonInit();

//  nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP);

    mainLoop();

    while(1);
}
void mainloop()
{
  static struct syslinkPacket slRxPacket;
  static struct syslinkPacket slTxPacket;
  static EsbPacket esbRxPacket;
  bool esbReceived = false;
  bool slReceived;
  static int vbatSendTime;
	static int radioRSSISendTime;
	static uint8_t rssi;

  while(1)
  {

#ifdef BLE
    if ((esbReceived == false) && bleCrazyfliesIsPacketReceived()) {
      EsbPacket* packet = bleCrazyfliesGetRxPacket();
      memcpy(esbRxPacket.data, packet->data, packet->size);
      esbRxPacket.size = packet->size;
      esbReceived = true;
      bleCrazyfliesReleaseRxPacket(packet);
    }

#endif
#ifndef CONT_WAVE_TEST

    if ((esbReceived == false) && esbIsRxPacket())
    {
      EsbPacket* packet = esbGetRxPacket();
      //Store RSSI here so that we can send it to STM later
      rssi = packet->rssi;
      memcpy(esbRxPacket.data, packet->data, packet->size);
      esbRxPacket.size = packet->size;
      esbReceived = true;
      esbReleaseRxPacket(packet);
    }

    if (esbReceived)
    {
      EsbPacket* packet = &esbRxPacket;
      esbReceived = false;

      if((packet->size >= 4) && (packet->data[0]==0xff) && (packet->data[1]==0x03))
      {
        handleRadioCmd(packet);
      }
      else if ((packet->size >2) && (packet->data[0]==0xff) && (packet->data[1]==0xfe))
      {
        handleBootloaderCmd(packet);
      }
      else
      {
        memcpy(slTxPacket.data, packet->data, packet->size);
        slTxPacket.length = packet->size;
        slTxPacket.type = SYSLINK_RADIO_RAW;

        syslinkSend(&slTxPacket);
      }
    }

    slReceived = syslinkReceive(&slRxPacket);
    if (slReceived)
    {
      switch (slRxPacket.type)
      {
        case SYSLINK_RADIO_RAW:
          if (esbCanTxPacket() && (slRxPacket.length < SYSLINK_MTU))
          {
            EsbPacket* packet = esbGetTxPacket();

            if (packet) {
              memcpy(packet->data, slRxPacket.data, slRxPacket.length);
              packet->size = slRxPacket.length;

              esbSendTxPacket(packet);
            }
            bzero(slRxPacket.data, SYSLINK_MTU);
          }
#ifdef BLE
          if (slRxPacket.length < SYSLINK_MTU) {
            static EsbPacket pk;
            memcpy(pk.data,  slRxPacket.data, slRxPacket.length);
            pk.size = slRxPacket.length;
            bleCrazyfliesSendPacket(&pk);
          }
#endif

          break;
        case SYSLINK_RADIO_CHANNEL:
          if(slRxPacket.length == 1)
          {
            esbSetChannel(slRxPacket.data[0]);

            slTxPacket.type = SYSLINK_RADIO_CHANNEL;
            slTxPacket.data[0] = slRxPacket.data[0];
            slTxPacket.length = 1;
            syslinkSend(&slTxPacket);
          }
          break;
        case SYSLINK_RADIO_DATARATE:
          if(slRxPacket.length == 1)
          {
            esbSetDatarate(slRxPacket.data[0]);

            slTxPacket.type = SYSLINK_RADIO_DATARATE;
            slTxPacket.data[0] = slRxPacket.data[0];
            slTxPacket.length = 1;
            syslinkSend(&slTxPacket);
          }
          break;
        case SYSLINK_RADIO_CONTWAVE:
          if(slRxPacket.length == 1) {
            esbSetContwave(slRxPacket.data[0]);

            slTxPacket.type = SYSLINK_RADIO_CONTWAVE;
            slTxPacket.data[0] = slRxPacket.data[0];
            slTxPacket.length = 1;
            syslinkSend(&slTxPacket);
          }
          break;
        case SYSLINK_RADIO_ADDRESS:
          if(slRxPacket.length == 5)
          {
            uint64_t address = 0;
            memcpy(&address, &slRxPacket.data[0], 5);
            esbSetAddress(address);

            slTxPacket.type = SYSLINK_RADIO_ADDRESS;
            memcpy(slTxPacket.data, slRxPacket.data, 5);
            slTxPacket.length = 5;
            syslinkSend(&slTxPacket);
          }
          break;
        case SYSLINK_PM_ONOFF_SWITCHOFF:
          pmSetState(pmAllOff);
          break;
        case SYSLINK_OW_GETINFO:
        case SYSLINK_OW_READ:
        case SYSLINK_OW_SCAN:
        case SYSLINK_OW_WRITE:
          if (memorySyslink(&slRxPacket)) {
            syslinkSend(&slRxPacket);
          }
          break;
      }
    }

    // Wait a while to start pushing over the syslink since UART pins are used to launch STM32 i bootloader as well
    if (systickGetTick() > SYSLINK_STARTUP_DELAY_TIME_MS) {
      // Send the battery voltage and state to the STM every SYSLINK_SEND_PERIOD_MS
      if (systickGetTick() >= vbatSendTime + SYSLINK_SEND_PERIOD_MS) {
        float fdata;
        uint8_t flags = 0;

        vbatSendTime = systickGetTick();
        slTxPacket.type = SYSLINK_PM_BATTERY_STATE;
        slTxPacket.length = 9;

        flags |= (pmIsCharging() == true)?0x01:0;
        flags |= (pmUSBPower() == true)?0x02:0;

        slTxPacket.data[0] = flags;

        fdata = pmGetVBAT();
        memcpy(slTxPacket.data+1, &fdata, sizeof(float));

        fdata = pmGetISET();
        memcpy(slTxPacket.data+1+4, &fdata, sizeof(float));

        syslinkSend(&slTxPacket);
      }
      //Send an RSSI sample to the STM every 10ms(100Hz)

      if (systickGetTick() >= radioRSSISendTime + 10) {
        radioRSSISendTime = systickGetTick();
        slTxPacket.type = SYSLINK_RADIO_RSSI;
        //This message contains only the RSSI measurement which consist
        //of a single uint8_t
        slTxPacket.length = sizeof(uint8_t);
        memcpy(slTxPacket.data, &rssi, sizeof(uint8_t));

        syslinkSend(&slTxPacket);
      }
    }
#endif

    // Button event handling
    ButtonEvent be = buttonGetState();
    bool usbConnected = pmUSBPower();
    if ((pmGetState() != pmSysOff) && (be == buttonShortPress) && !usbConnected)
    {
      pmSetState(pmAllOff);
      /*swdInit();
      swdTest();*/
    }
    else if ((pmGetState() != pmSysOff) && (be == buttonShortPress)
                                        && usbConnected)
    {
    	//pmSetState(pmSysOff);
      pmSetState(pmAllOff);
        /*swdInit();
        swdTest();*/
    }
    else if ((pmGetState() == pmSysOff) && (be == buttonShortPress))
    {
      //Normal boot
      pmSysBootloader(false);
      pmSetState(pmSysRunning);
    }
    else if ((pmGetState() == pmSysOff) && boottedFromBootloader)
    {
      //Normal boot after bootloader
      pmSysBootloader(false);
      pmSetState(pmSysRunning);
    }
    else if ((pmGetState() == pmSysOff) && (be == buttonLongPress))
    {
      //stm bootloader
      pmSysBootloader(true);
      pmSetState(pmSysRunning);
    }
    boottedFromBootloader = false;

    // processes loop
    buttonProcess();
    pmProcess();
    //owRun();       //TODO!
  }
}