/*
	"THE CHINOTTO-WARE LICENSE" (Revision 42):

	IZ4KLL a.k.a. cesco@ventuordici.org wrote this code.

	As long as you retain this notice you can do whatever you want with this stuff.
	I reserve the right to do the absolute minimum provided by law, up to and including absolutely nothing.
	If we meet some day, and you think this stuff is worth it, you can buy me a chinotto in return.
*/

#include <stdint.h>
#include "bassofono.h"
#include "tx.h"
#include "rx.h"
#include "interface.h"
#ifdef USE_I2C
        #include "si5351.h"
        #include "i2c_eeprom.h"
#endif
#include "main.h"
#include "FIRFilterCode.h"
#include <arm_math.h>
#include <stm32g4xx_ll_cordic.h>

/*
                  BASSOFONO         .-.
	(___________________________()6 `-,
	(   ______________________   /''"`
	//\\                      //\\
	"" ""                     "" ""
	~~~~ ricetrasmettitore basso ~~~~

	Ricetrasmettittore multimodo per
	onde lunghe e lunghissime.
*/

/*
TIM6 7680 -> 21875 Hz audio
TIM7 1680000 -> 100 Hz eventi
TIM8 240 -> 700000 Hz rf
*/

struct s_canale canale;
struct s_stato stato;

// state
uint8_t ricezione, trasmissione;
int32_t rit;
int32_t rx_gain;
int32_t peak, peakset;
int32_t squelch;
int32_t mic_gain;
int32_t scan;
// q31_t nco1_increment;
uint32_t audio_filter_freq, audio_filter_bw, audio_filter_beta;

uint8_t s_meter;

// maschera, ogni bit uno stato
uint16_t state_changed;

uint8_t scrittura_stato_pendente;

// uart rx
char uart_rx_buf[2], rx_cmd_rb[RX_CMD_RB_SIZE];
uint8_t rx_cmd_rb_in_idx, rx_cmd_rb_out_idx;

// uart tx
char uart_tx_buf[UART_TX_BUFFER_SIZE];
uint16_t uart_tx_buf_in_idx;

q31_t if_I[RX_DAC_BUFFER_SIZE];
q31_t if_Q[RX_DAC_BUFFER_SIZE];

// ============

inline uint16_t ringbuf_increment(uint8_t *index, uint8_t buff_size_mask) {
    (*index)++;
    *index &= buff_size_mask;
    return *index;
}

q31_t sat_mult_q31(q31_t a, q31_t b){
	q31_t out;
	out = ((q63_t) a * b) >> 32;
	out = __SSAT(out, 31);
	return out << 1U;
}

// uart

void enqueue_cmd(char in){
	rx_cmd_rb[rx_cmd_rb_in_idx] = in;
	ringbuf_increment(&rx_cmd_rb_in_idx, RX_CMD_RB_SIZE_MASK);
}

void dequeue_cmd(void){
	decode_cmd(rx_cmd_rb[rx_cmd_rb_out_idx]);
	ringbuf_increment(&rx_cmd_rb_out_idx, RX_CMD_RB_SIZE_MASK);
}

/*
void enqueue_tx(char * data, uint16_t len){
        for( uint8_t index = 0; index < len; index++){
        	uart_tx_buf[uart_tx_buf_in_idx] = data[index];
        	uart_tx_buf_in_idx++;
        	if(uart_tx_buf_in_idx == UART_TX_BUFFER_SIZE) break;
        }
}
*/

// cambio stati
void set_frequency(void){
	set_rx_nco1_freq(canale.frequenza+rit);
	set_tx_nco1_freq(canale.frequenza);
}

void imposta_modulazione(void){
	st2_filter_init();
	// cambia offset
	set_frequency();
}

void set_dummy(void){
	// non fare NULLAH
}

// cambiato stato 
void set_changed(uint8_t state){
	state_changed |= (1U<<state);
}

void reset_changed(uint8_t state){
	state_changed &= ~(1U<<state);
}

uint8_t get_changed(uint8_t state){
	return (state_changed >> state) & 1U;
}

void state_set_default(void){
        canale.modulazione = MOD_DC;
        canale.frequenza = 128000;
        rit = 0;
        set_frequency();
        rx_gain = 2;
        stato.volume = 8;
        audio_filter_freq = RX_AUDIO_FILTER_FREQ_DEF;
        audio_filter_bw = RX_AUDIO_FILTER_BW_DEF;
        audio_filter_beta = RX_AUDIO_FILTER_BETA_DEF;
        audio_filter_generate_coeffs(audio_filter_coeffs, audio_filter_freq, audio_filter_bw, audio_filter_beta);

	stato.tx_f_freq = TX_FILTRO_AUDIO_FREQ_DEF;
	stato.tx_f_banda = TX_FILTRO_AUDIO_BANDA_DEF;
	stato.tx_f_beta = TX_FILTRO_AUDIO_BETA_DEF;
        audio_filter_generate_coeffs(tx_filtro_audio_coefficienti, stato.tx_f_freq, stato.tx_f_banda, stato.tx_f_beta);
        state_changed = 0xFFFF;
//        strcpy(tabstring, "TX AUD MEM NO");
}

// diag

void diag(void){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"ADC sample rate: %d\nADC oversampling: %d\n", RX_ADC_SAMPLE_RATE, RX_ADC_OVERSAMPLING);
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"ADC buffer size: %d\n1st decimation factor: %d\n", RX_ADC_BUFFER_SIZE, MS_DECIMATION_FACTOR * 2);
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"1st out sample rate: %d\n", ST1_OUT_SAMPLE_RATE);
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"2st buffer size: %d\n2st decimation factor: %d\n", ST2_BUFFER_SIZE, ST2_DECIMATION_FACTOR * 2);
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"2st out sample rate: %d\n", ST2_OUT_SAMPLE_RATE);
        uart_tx_buf_in_idx += sprintf(uart_tx_buf,"in rx_gain %d\n", rx_gain);
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"af gain %d\n", stato.volume);
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"rx nco1 inc %d\n", rx_nco1_increment);
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"nco2 inc %d\n", NCO2_INCREMENT);
	uart_tx_buf_in_idx += sprintf(uart_tx_buf,"audio filter f %d bw %d\n", audio_filter_freq, audio_filter_bw);
}

/*
uint32_t get_pwm_freq(uint16_t pwm_period){
	return CLOCK/pwm_period;
}

uint16_t get_pwm_period(uint32_t pwm_frequency){
	return CLOCK/pwm_frequency;
}
*/

// misura il logaritmo binario  della media dei valori assoluti in q31
uint8_t measure_log_abs_mean(q31_t *samples, uint16_t size){
        int32_t measured_signal = 0;
        uint16_t index = 0;
        uint8_t log_sig = 31;

        q31_t abs;
        while(index < size){
                abs = (samples[index] > 0) ? samples[index] : (q31_t)__QSUB(0, samples[index]);
                measured_signal += (abs >> 6);
                index++;
        }
        while (log_sig) {
          if((measured_signal >> log_sig) & 1) break;
          log_sig--;
        }
        return log_sig;
}

void set_LO_freq(uint32_t freq){

}
