void configure_radio(modulation_t mod){
#if defined USE_SI4460 || defined USE_SX127X
    if(mod == MODULATION_CW){
        hw_radio_continuous_tx(&tx_cfg, true);
    } else {
        hw_radio_continuous_tx(&tx_cfg, false);
    }

#elif defined USE_CC1101

    hw_radio_set_rx(&tx_cfg, NULL, NULL); // we 'misuse' hw_radio_set_rx to configure the channel (using the public API)
    hw_radio_set_idle(); // go straight back to idle

    /* Configure */
    cc1101_interface_write_single_patable(current_eirp_level);
    //cc1101_interface_write_single_reg(0x08, 0x22); // PKTCTRL0 random PN9 mode + disable data whitening
    cc1101_interface_write_single_reg(0x08, 0x22); // PKTCTRL0 disable data whitening, continious preamble
    if(mod == MODULATION_CW) {
      cc1101_interface_write_single_reg(0x12, 0x30); // MDMCFG2
    } else {
      cc1101_interface_write_single_reg(0x12, 0x12); // MDMCFG2
    }

    cc1101_interface_strobe(0x32); // strobe calibrate
#endif
}
static void stop() {
  // make sure to cancel tasks which might me pending already
  hw_radio_set_idle();

	if(is_mode_rx) {
		sched_cancel_task(&start_rx);
  }	else {
		sched_cancel_task(&transmit_packet);
  }
}
static void start() {
    counter = 0;
    missed_packets_counter = 0;
    received_packets_counter = 0;
    uint8_t lcd_line = 0;

    switch(current_state)
    {
        case STATE_CONFIG_DIRECTION:
            is_mode_rx? sprintf(lcd_msg, "PER RX") : sprintf(lcd_msg, "PER TX");
            break;
        case STATE_CONFIG_DATARATE:
        	lcd_line = 1;
            switch(current_channel_id.channel_header.ch_class)
            {
                case PHY_CLASS_LO_RATE:
                    sprintf(lcd_msg, "LO-RATE");
                    break;
                case PHY_CLASS_NORMAL_RATE:
                    sprintf(lcd_msg, "NOR-RATE");
                    break;
                case PHY_CLASS_HI_RATE:
                    sprintf(lcd_msg, "HI-RATE");
                    break;
            }
            break;
        case STATE_RUNNING:
        	lcd_line = 2;
            if(is_mode_rx)
            {
                sprintf(lcd_msg, "RUN RX");
                //lcd_write_string(lcd_msg);
                console_printf("%s,%s,%s,%s,%s,%s\n", "channel_id", "counter", "rssi", "tx_id", "rx_id", "timestamp");
                rx_cfg.channel_id = current_channel_id;
                timer_post_task(&start_rx, TIMER_TICKS_PER_SEC * 5);
            }
            else
            {
                hw_radio_set_idle();
                sprintf(lcd_msg, "RUN TX");
                //lcd_write_string(lcd_msg);
                timer_post_task(&transmit_packet, TIMER_TICKS_PER_SEC * 5);
            }
            break;
    }

#ifdef PLATFORM_EFM32GG_STK3700
    lcd_write_string(lcd_msg);
#else
    lcd_write_line(lcd_line, lcd_msg);
#endif

}
static void start()
{
    counter = 0;
    missed_packets_counter = 0;
    received_packets_counter = 0;

    switch(current_state)
    {
        case STATE_CONFIG_DIRECTION:
            is_mode_rx? sprintf(lcd_msg, "PER RX") : sprintf(lcd_msg, "PER TX");
            break;
        case STATE_CONFIG_DATARATE:
            switch(current_channel_id.channel_header.ch_class)
            {
                case PHY_CLASS_LO_RATE:
                    sprintf(lcd_msg, "LO-RATE");
                    break;
                case PHY_CLASS_NORMAL_RATE:
                    sprintf(lcd_msg, "NOR-RATE");
                    break;
                case PHY_CLASS_HI_RATE:
                    sprintf(lcd_msg, "HI-RATE");
                    break;
            }
            break;
        case STATE_RUNNING:
            if(is_mode_rx)
            {
                sprintf(lcd_msg, "RUN RX");
                lcd_write_string(lcd_msg);
                sprintf(record, "%s,%s,%s,%s,%s,%s\n", "channel_id", "counter", "rssi", "tx_id", "rx_id", "timestamp");
                uart_transmit_message(record, strlen(record));
                rx_cfg.channel_id = current_channel_id;
                timer_post_task(&start_rx, TIMER_TICKS_PER_SEC * 5);
            }
            else
            {
                hw_radio_set_idle();
                sprintf(lcd_msg, "RUN TX");
                lcd_write_string(lcd_msg);
                timer_post_task(&transmit_packet, TIMER_TICKS_PER_SEC * 5);
            }
            break;
    }

    lcd_write_string(lcd_msg);
}
void start()
{
    hw_rx_cfg_t rx_cfg;
    rx_cfg.channel_id.channel_header.ch_coding = PHY_CODING_PN9;
    rx_cfg.channel_id.channel_header.ch_class = current_channel_class;
    rx_cfg.channel_id.channel_header.ch_freq_band = current_channel_band;
    rx_cfg.channel_id.center_freq_index = channel_indexes[current_channel_indexes_index];

#ifdef HAS_LCD
    char string[10] = "";
    char rate;
    char band[3];
    switch(current_channel_class)
    {
        case PHY_CLASS_LO_RATE: rate = 'L'; break;
        case PHY_CLASS_NORMAL_RATE: rate = 'N'; break;
        case PHY_CLASS_HI_RATE: rate = 'H'; break;
    }

    switch(current_channel_band)
    {
        case PHY_BAND_433: strncpy(band, "433", sizeof(band)); break;
        case PHY_BAND_868: strncpy(band, "868", sizeof(band)); break;
        case PHY_BAND_915: strncpy(band, "915", sizeof(band)); break;
    }

    sprintf(string, "%.3s%c-%i", band, rate, rx_cfg.channel_id.center_freq_index),
    lcd_write_string(string);
#endif

    hw_radio_set_rx(&rx_cfg, NULL, &rssi_valid_cb); // we 'misuse' hw_radio_set_rx to configure the channel (using the public API)
    hw_radio_set_idle(); // go straight back to idle

    cc1101_interface_write_single_reg(0x08, 0x22); // PKTCTRL0 random PN9 mode + disable data whitening
    //cc1101_interface_write_single_reg(0x12, 0x30); // MDMCFG2: use OOK modulation to clearly view centre freq on spectrum analyzer, comment for GFSK
    cc1101_interface_write_single_patable(0xc0); // 10dBm TX EIRP
    cc1101_interface_strobe(0x35); // strobe TX
}
static void packet_transmitted(hw_radio_packet_t* hw_radio_packet)
{
    assert(dll_state == DLL_STATE_TX_FOREGROUND);
    switch_state(DLL_STATE_TX_FOREGROUND_COMPLETED);
    DPRINT("Transmitted packet with length = %i", hw_radio_packet->length);
    packet_t* packet = packet_queue_find_packet(hw_radio_packet);

    d7anp_signal_packet_transmitted(packet);

    if(process_received_packets_after_tx)
    {
        sched_post_task(&process_received_packets);
        process_received_packets_after_tx = false;
    }

#ifdef RESPONDER_USE_FG_SCAN_OUTSIDE_TRANSACTION // TODO validate if still needed, if yes: needs to be tested
    /*
     * Resume the FG scan only after an unicast packet, otherwise, wait the
     * response period expiration.
     */
    if (resume_fg_scan && packet->dll_header.control_target_address_set)
    {
        switch_state(DLL_STATE_FOREGROUND_SCAN);

        hw_rx_cfg_t rx_cfg = (hw_rx_cfg_t){
            .channel_id.channel_header = current_access_profile->subbands[0].channel_header,
            .channel_id.center_freq_index = current_access_profile->subbands[0].channel_index_start,
            .syncword_class = PHY_SYNCWORD_CLASS1,
        };

        hw_radio_set_rx(&rx_cfg, &packet_received, NULL);
        resume_fg_scan = false;
    }
#else
    if (resume_fg_scan)
    {
        switch_state(DLL_STATE_FOREGROUND_SCAN);

        hw_rx_cfg_t rx_cfg = (hw_rx_cfg_t){
            .channel_id.channel_header = current_access_profile->subbands[0].channel_header,
            .channel_id.center_freq_index = current_access_profile->subbands[0].channel_index_start,
            .syncword_class = PHY_SYNCWORD_CLASS1,
        };

        hw_radio_set_rx(&rx_cfg, &packet_received, NULL);
        resume_fg_scan = false;
    }
#endif

}

static void cca_rssi_valid(int16_t cur_rssi)
{
    // When the radio goes back to Rx state, the rssi_valid callback may be still set. Skip it in this case
    if (dll_state != DLL_STATE_CCA1 && dll_state != DLL_STATE_CCA2)
        return;

    if (cur_rssi <= E_CCA)
    {
        if(dll_state == DLL_STATE_CCA1)
        {
            DPRINT("CCA1 RSSI: %d", cur_rssi);
            switch_state(DLL_STATE_CCA2);
            timer_post_task_delay(&execute_cca, 5);
            return;
        }
        else if(dll_state == DLL_STATE_CCA2)
        {
            // OK, send packet
            DPRINT("CCA2 RSSI: %d", cur_rssi);
            DPRINT("CCA2 succeeded, transmitting ...");
            // log_print_data(current_packet->hw_radio_packet.data, current_packet->hw_radio_packet.length + 1); // TODO tmp

            switch_state(DLL_STATE_TX_FOREGROUND);

            d7anp_signal_packet_csma_ca_insertion_completed(true);
            error_t err = hw_radio_send_packet(&current_packet->hw_radio_packet, &packet_transmitted);
            assert(err == SUCCESS);

            if (!resume_fg_scan)
                hw_radio_set_idle(); // ensure radio goes back to IDLE after transmission instead of to RX
            return;
        }
    }
    else
    {
        DPRINT("Channel not clear, RSSI: %i", cur_rssi);
        switch_state(DLL_STATE_CSMA_CA_RETRY);
        execute_csma_ca();

        //switch_state(DLL_STATE_CCA_FAIL);
        //d7atp_signal_packet_csma_ca_insertion_completed(false);
    }
}

static void execute_cca()
{
    assert(dll_state == DLL_STATE_CCA1 || dll_state == DLL_STATE_CCA2);

    hw_rx_cfg_t rx_cfg =(hw_rx_cfg_t){
        .channel_id.channel_header = current_access_profile->subbands[0].channel_header,
        .channel_id.center_freq_index = current_access_profile->subbands[0].channel_index_start,
        .syncword_class = PHY_SYNCWORD_CLASS1,
    };

    hw_radio_set_rx(&rx_cfg, NULL, &cca_rssi_valid);
}

static uint16_t calculate_tx_duration()
{
    int data_rate = 6; // Normal rate: 6.9 bytes/tick
    // TODO select correct subband
    switch (current_access_profile->subbands[0].channel_header.ch_class)
    {
    case PHY_CLASS_LO_RATE:
        data_rate = 1; // Lo Rate: 1.2 bytes/tick
        break;
    case PHY_CLASS_HI_RATE:
        data_rate = 20; // High rate: 20.83 byte/tick
    }

    uint16_t duration = (current_packet->hw_radio_packet.length / data_rate) + 1;
    return duration;
}