diff --git a/software/libcariboulite/CMakeLists.txt b/software/libcariboulite/CMakeLists.txt index 67e7d4f..d9dc601 100644 --- a/software/libcariboulite/CMakeLists.txt +++ b/software/libcariboulite/CMakeLists.txt @@ -10,7 +10,7 @@ include_directories(${PROJECT_SOURCE_DIR}/src) # ------------------------------------ # MAIN - Source files for main library # ------------------------------------ -set(SOURCES_LIB src/cariboulite_setup.c src/cariboulite_events.c src/cariboulite_radios.c) +set(SOURCES_LIB src/cariboulite_setup.c src/cariboulite_events.c src/cariboulite_radios.c src/cariboulite_radio.c) # Add internal project dependencies add_subdirectory(src/datatypes EXCLUDE_FROM_ALL) diff --git a/software/libcariboulite/src/cariboulite_radio.c b/software/libcariboulite/src/cariboulite_radio.c new file mode 100644 index 0000000..ec07dd5 --- /dev/null +++ b/software/libcariboulite/src/cariboulite_radio.c @@ -0,0 +1,878 @@ +#ifndef ZF_LOG_LEVEL + #define ZF_LOG_LEVEL ZF_LOG_VERBOSE +#endif +#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG +#define ZF_LOG_TAG "CARIBOULITE Radio" +#include "zf_log/zf_log.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "cariboulite_radio.h" +#include "cariboulite_events.h" +#include "cariboulite_setup.h" + +#define GET_CH(rad_ch) ((rad_ch)==cariboulite_channel_s1g ?at86rf215_rf_channel_900mhz : at86rf215_rf_channel_2400mhz) +#define GET_SMI_CH(rad_ch) ((rad_ch)==cariboulite_channel_s1g ?caribou_smi_channel_900 : caribou_smi_channel_2400) +#define GET_SMI_DIR(ch_dir) ((dir) == cariboulite_channel_dir_rx ? caribou_smi_stream_type_read : caribou_smi_stream_type_write) + +//========================================================================= +void cariboulite_radio_init(cariboulite_radio_state_st* radio, cariboulite_st *sys, cariboulite_channel_en type) +{ + memset (radio, 0, sizeof(cariboulite_radio_state_st)); + + radio->cariboulite_sys = sys; + radio->active = true; + radio->channel_direction = cariboulite_channel_dir_rx; + radio->type = type; + radio->cw_output = false; + radio->lo_output = false; + radio->rx_stream_id = -1; + radio->tx_stream_id = -1; +} + +//========================================================================= +int cariboulite_radio_dispose(cariboulite_radio_state_st* radio) +{ + radio->active = false; + + // If streams are active - destroy them + if (radio->rx_stream_id != -1) + { + caribou_smi_destroy_stream(&radio->cariboulite_sys->smi, radio->rx_stream_id); + radio->rx_stream_id = -1; + } + + if (radio->tx_stream_id != -1) + { + caribou_smi_destroy_stream(&radio->cariboulite_sys->smi, radio->tx_stream_id); + radio->tx_stream_id = -1; + } + + usleep(100000); + + at86rf215_radio_set_state( &radio->cariboulite_sys->modem, + GET_CH(radio->type), + at86rf215_radio_state_cmd_trx_off); + radio->state = at86rf215_radio_state_cmd_trx_off; + + // Type specific + if (radio->type == cariboulite_channel_6g) + { + caribou_fpga_set_io_ctrl_mode (&radio->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_low_power); + } +} + +//========================================================================= +int cariboulite_radio_sync_information(cariboulite_radio_state_st* radio) +{ + cariboulite_radio_get_mod_state (radio, NULL); + cariboulite_radio_get_rx_gain_control(radio, NULL, NULL); + cariboulite_radio_get_rx_bandwidth(radio, NULL); + cariboulite_radio_get_tx_power(radio, NULL); + cariboulite_radio_get_rssi(radio, NULL); + cariboulite_radio_get_energy_det(radio, NULL); +} + +//========================================================================= +int cariboulite_radio_get_mod_state (cariboulite_radio_state_st* radio, at86rf215_radio_state_cmd_en *state) +{ + radio->state = at86rf215_radio_get_state(&radio->cariboulite_sys->modem, GET_CH(radio->type)); + + if (state) *state = radio->state; + return 0; +} + +//========================================================================= +int cariboulite_radio_get_mod_intertupts (cariboulite_radio_state_st* radio, at86rf215_radio_irq_st **irq_table) +{ + at86rf215_irq_st irq = {0}; + at86rf215_get_irqs(&radio->cariboulite_sys->modem, &irq, 0); + + memcpy (&radio->interrupts, + (radio->type == cariboulite_channel_s1g) ? (&irq.radio09) : (&irq.radio24), + sizeof(at86rf215_radio_irq_st)); + + if (irq_table) *irq_table = &radio->interrupts; + + return 0; +} + +//========================================================================= +int cariboulite_radio_set_rx_gain_control(cariboulite_radio_state_st* radio, + bool rx_agc_on, + int rx_gain_value_db) +{ + int control_gain_val = (int)roundf((float)(rx_gain_value_db) / 3.0f); + if (control_gain_val < 0) control_gain_val = 0; + if (control_gain_val > 23) control_gain_val = 23; + + at86rf215_radio_agc_ctrl_st rx_gain_control = + { + .agc_measure_source_not_filtered = 1, + .avg = at86rf215_radio_agc_averaging_32, + .reset_cmd = 0, + .freeze_cmd = 0, + .enable_cmd = rx_agc_on, + .att = at86rf215_radio_agc_relative_atten_21_db, + .gain_control_word = control_gain_val, + }; + + at86rf215_radio_setup_agc(&radio->cariboulite_sys->modem, GET_CH(radio->type), &rx_gain_control); + radio->rx_agc_on = rx_agc_on; + radio->rx_gain_value_db = rx_gain_value_db; + return 0; +} + +//========================================================================= +int cariboulite_radio_get_rx_gain_control(cariboulite_radio_state_st* radio, + bool *rx_agc_on, + int *rx_gain_value_db) +{ + at86rf215_radio_agc_ctrl_st agc_ctrl = {0}; + at86rf215_radio_get_agc(&radio->cariboulite_sys->modem, GET_CH(radio->type), &agc_ctrl); + + radio->rx_agc_on = agc_ctrl.enable_cmd; + radio->rx_gain_value_db = agc_ctrl.gain_control_word * 3; + if (rx_agc_on) *rx_agc_on = radio->rx_agc_on; + if (rx_gain_value_db) *rx_gain_value_db = radio->rx_gain_value_db; + return 0; +} + +//========================================================================= +int cariboulite_radio_get_rx_gain_limits(cariboulite_radio_state_st* radio, + int *rx_min_gain_value_db, + int *rx_max_gain_value_db, + int *rx_gain_value_resolution_db) +{ + if (rx_min_gain_value_db) *rx_min_gain_value_db = 0; + if (rx_max_gain_value_db) *rx_max_gain_value_db = 23*3; + if (rx_gain_value_resolution_db) *rx_gain_value_resolution_db = 3; + return 0; +} + +//========================================================================= +int cariboulite_radio_set_rx_bandwidth(cariboulite_radio_state_st* radio, + at86rf215_radio_rx_bw_en rx_bw) +{ + at86rf215_radio_f_cut_en fcut = at86rf215_radio_rx_f_cut_half_fs; + + // Automatically calculate the digital f_cut + if (rx_bw >= at86rf215_radio_rx_bw_BW160KHZ_IF250KHZ && rx_bw <= at86rf215_radio_rx_bw_BW500KHZ_IF500KHZ) + fcut = at86rf215_radio_rx_f_cut_0_25_half_fs; + else if (rx_bw >= at86rf215_radio_rx_bw_BW630KHZ_IF1000KHZ && rx_bw <= at86rf215_radio_rx_bw_BW630KHZ_IF1000KHZ) + fcut = at86rf215_radio_rx_f_cut_0_375_half_fs; + else if (rx_bw >= at86rf215_radio_rx_bw_BW800KHZ_IF1000KHZ && rx_bw <= at86rf215_radio_rx_bw_BW1000KHZ_IF1000KHZ) + fcut = at86rf215_radio_rx_f_cut_0_5_half_fs; + else if (rx_bw >= at86rf215_radio_rx_bw_BW1250KHZ_IF2000KHZ && rx_bw <= at86rf215_radio_rx_bw_BW1250KHZ_IF2000KHZ) + fcut = at86rf215_radio_rx_f_cut_0_75_half_fs; + else + fcut = at86rf215_radio_rx_f_cut_half_fs; + + radio->rx_fcut = fcut; + + at86rf215_radio_set_rx_bw_samp_st cfg = + { + .inverter_sign_if = 0, + .shift_if_freq = 1, // A value of one configures the receiver to shift the IF frequency + // by factor of 1.25. This is useful to place the image frequency according + // to channel scheme. This increases the IF frequency to max 2.5MHz + // thus places the internal LO fasr away from the signal => lower noise + .bw = rx_bw, + .fcut = radio->rx_fcut, // keep the same + .fs = radio->rx_fs, // keep the same + }; + at86rf215_radio_set_rx_bandwidth_sampling(&radio->cariboulite_sys->modem, GET_CH(radio->type), &cfg); + radio->rx_bw = rx_bw; + return 0; +} + +//========================================================================= +int cariboulite_radio_get_rx_bandwidth(cariboulite_radio_state_st* radio, + at86rf215_radio_rx_bw_en *rx_bw) +{ + at86rf215_radio_set_rx_bw_samp_st cfg = {0}; + at86rf215_radio_get_rx_bandwidth_sampling(&radio->cariboulite_sys->modem, GET_CH(radio->type), &cfg); + radio->rx_bw = cfg.bw; + radio->rx_fcut = cfg.fcut; + radio->rx_fs = cfg.fs; + if (rx_bw) *rx_bw = radio->rx_bw; + return 0; +} + +//========================================================================= +int cariboulite_radio_set_rx_samp_cutoff(cariboulite_radio_state_st* radio, + at86rf215_radio_sample_rate_en rx_sample_rate, + at86rf215_radio_f_cut_en rx_cutoff) +{ + at86rf215_radio_set_rx_bw_samp_st cfg = + { + .inverter_sign_if = 0, // A value of one configures the receiver to implement the inverted-sign + // IF frequency. Use default setting for normal operation + .shift_if_freq = 1, // A value of one configures the receiver to shift the IF frequency + // by factor of 1.25. This is useful to place the image frequency according + // to channel scheme. + .bw = radio->rx_bw, // keep the same + .fcut = rx_cutoff, + .fs = rx_sample_rate, + }; + at86rf215_radio_set_rx_bandwidth_sampling(&radio->cariboulite_sys->modem, GET_CH(radio->type), &cfg); + radio->rx_fs = rx_sample_rate; + radio->rx_fcut = rx_cutoff; + return 0; +} + +//========================================================================= +int cariboulite_radio_get_rx_samp_cutoff(cariboulite_radio_state_st* radio, + at86rf215_radio_sample_rate_en *rx_sample_rate, + at86rf215_radio_f_cut_en *rx_cutoff) +{ + cariboulite_radio_get_rx_bandwidth(radio, NULL); + if (rx_sample_rate) *rx_sample_rate = radio->rx_fs; + if (rx_cutoff) *rx_cutoff = radio->rx_fcut; + return 0; +} + +//========================================================================= +int cariboulite_radio_set_tx_power(cariboulite_radio_state_st* radio, + int tx_power_dbm) +{ + if (tx_power_dbm < -18) tx_power_dbm = -18; + if (tx_power_dbm > 13) tx_power_dbm = 13; + int tx_power_ctrl = 18 + tx_power_dbm; + + at86rf215_radio_tx_ctrl_st cfg = + { + .pa_ramping_time = at86rf215_radio_tx_pa_ramp_16usec, + .current_reduction = at86rf215_radio_pa_current_reduction_0ma, // we can use this to gain some more + // granularity with the tx gain control + .tx_power = tx_power_ctrl, + .analog_bw = radio->tx_bw, // same as before + .digital_bw = radio->tx_fcut, // same as before + .fs = radio->tx_fs, // same as before + .direct_modulation = 0, + }; + + at86rf215_radio_setup_tx_ctrl(&radio->cariboulite_sys->modem, GET_CH(radio->type), &cfg); + radio->tx_power = tx_power_dbm; + + return 0; +} + +//========================================================================= +int cariboulite_radio_get_tx_power(cariboulite_radio_state_st* radio, + int *tx_power_dbm) +{ + at86rf215_radio_tx_ctrl_st cfg = {0}; + at86rf215_radio_get_tx_ctrl(&radio->cariboulite_sys->modem, GET_CH(radio->type), &cfg); + radio->tx_power = cfg.tx_power - 18; + radio->tx_bw = cfg.analog_bw; + radio->tx_fcut = cfg.digital_bw; + radio->tx_fs = cfg.fs; + + if (tx_power_dbm) *tx_power_dbm = radio->tx_power; + return 0; +} + +//========================================================================= +int cariboulite_radio_set_tx_bandwidth(cariboulite_radio_state_st* radio, + at86rf215_radio_tx_cut_off_en tx_bw) +{ + at86rf215_radio_tx_ctrl_st cfg = + { + .pa_ramping_time = at86rf215_radio_tx_pa_ramp_16usec, + .current_reduction = at86rf215_radio_pa_current_reduction_0ma, // we can use this to gain some more + // granularity with the tx gain control + .tx_power = 18 + radio->tx_power, // same as before + .analog_bw = tx_bw, + .digital_bw = radio->tx_fcut, // same as before + .fs = radio->tx_fs, // same as before + .direct_modulation = 0, + }; + + at86rf215_radio_setup_tx_ctrl(&radio->cariboulite_sys->modem, GET_CH(radio->type), &cfg); + radio->tx_bw = tx_bw; + + return 0; +} + +//========================================================================= +int cariboulite_radio_get_tx_bandwidth(cariboulite_radio_state_st* radio, + at86rf215_radio_tx_cut_off_en *tx_bw) +{ + cariboulite_radio_get_tx_power(radio, NULL); + if (tx_bw) *tx_bw = radio->tx_bw; + return 0; +} + +//========================================================================= +int cariboulite_radio_set_tx_samp_cutoff(cariboulite_radio_state_st* radio, + at86rf215_radio_sample_rate_en tx_sample_rate, + at86rf215_radio_f_cut_en tx_cutoff) +{ + at86rf215_radio_tx_ctrl_st cfg = + { + .pa_ramping_time = at86rf215_radio_tx_pa_ramp_16usec, + .current_reduction = at86rf215_radio_pa_current_reduction_0ma, // we can use this to gain some more + // granularity with the tx gain control + .tx_power = 18 + radio->tx_power, // same as before + .analog_bw = radio->tx_bw, // same as before + .digital_bw = tx_cutoff, + .fs = tx_sample_rate, + .direct_modulation = 0, + }; + + at86rf215_radio_setup_tx_ctrl(&radio->cariboulite_sys->modem, GET_CH(radio->type), &cfg); + radio->tx_fcut = tx_cutoff; + radio->tx_fs = tx_sample_rate; + + return 0; +} + +//========================================================================= +int cariboulite_radio_get_tx_samp_cutoff(cariboulite_radio_state_st* radio, + at86rf215_radio_sample_rate_en *tx_sample_rate, + at86rf215_radio_f_cut_en *tx_cutoff) +{ + cariboulite_radio_get_tx_power(radio, NULL); + if (tx_sample_rate) *tx_sample_rate = radio->tx_fs; + if (tx_cutoff) *tx_cutoff = radio->tx_fcut; + return 0; +} + +//========================================================================= +int cariboulite_radio_get_rssi(cariboulite_radio_state_st* radio, float *rssi_dbm) +{ + float rssi = at86rf215_radio_get_rssi_dbm(&radio->cariboulite_sys->modem, GET_CH(radio->type)); + if (rssi >= -127.0 && rssi <= 4) // register only valid values + { + radio->rx_rssi = rssi; + if (rssi_dbm) *rssi_dbm = rssi; + return 0; + } + + // if error maintain the older number and return error + if (rssi_dbm) *rssi_dbm = radio->rx_rssi; + + return -1; +} + +//========================================================================= +int cariboulite_radio_get_energy_det(cariboulite_radio_state_st* radio, float *energy_det_val) +{ + at86rf215_radio_energy_detection_st det = {0}; + at86rf215_radio_get_energy_detection(&radio->cariboulite_sys->modem, GET_CH(radio->type), &det); + + if (det.energy_detection_value >= -127.0 && det.energy_detection_value <= 4) // register only valid values + { + radio->rx_energy_detection_value = det.energy_detection_value; + if (energy_det_val) *energy_det_val = radio->rx_energy_detection_value; + return 0; + } + + if (energy_det_val) *energy_det_val = radio->rx_energy_detection_value; + + return -1; +} + +//====================================================================== +typedef struct { + int bit_count; /* number of bits of entropy in data */ + int byte_count; /* number of bytes of data in array */ + unsigned char buf[1]; +} entropy_t; + +static int add_entropy(uint8_t byte) +{ + int rand_fid = open("/dev/urandom", O_RDWR); + if (rand_fid != 0) + { + // error opening device + ZF_LOGE("Opening /dev/urandom device file failed"); + return -1; + } + + entropy_t ent = { + .bit_count = 8, + .byte_count = 1, + .buf = {byte}, + }; + + if (ioctl(rand_fid, RNDADDENTROPY, &ent) != 0) + { + ZF_LOGE("IOCTL to /dev/urandom device file failed"); + } + + if (close(rand_fid) !=0 ) + { + ZF_LOGE("Closing /dev/urandom device file failed"); + return -1; + } + + return 0; +} + +//========================================================================= +int cariboulite_radio_get_rand_val(cariboulite_radio_state_st* radio, uint8_t *rnd) +{ + radio->random_value = at86rf215_radio_get_random_value(&radio->cariboulite_sys->modem, GET_CH(radio->type)); + if (rnd) *rnd = radio->random_value; + + // add the random number to the system entropy. why not :) + add_entropy(radio->random_value); + return 0; +} + +//================================================= +// FREQUENCY CONVERSION LOGIC +//================================================= +#define CARIBOULITE_MIN_MIX (1.0e6) // 30 +#define CARIBOULITE_MAX_MIX (6000.0e6) // 6000 +#define CARIBOULITE_MIN_LO (85.0e6) +#define CARIBOULITE_MAX_LO (4200.0e6) +#define CARIBOULITE_2G4_MIN (2395.0e6) // 2400 +#define CARIBOULITE_2G4_MAX (2485.0e6) // 2483.5 +#define CARIBOULITE_S1G_MIN1 (350.0e6) // 389.5e6 +#define CARIBOULITE_S1G_MAX1 (510.0e6) +#define CARIBOULITE_S1G_MIN2 (779.0e6) +#define CARIBOULITE_S1G_MAX2 (1020.0e6) + +typedef enum +{ + conversion_dir_none = 0, + conversion_dir_up = 1, + conversion_dir_down = 2, +} conversion_dir_en; + +//================================================= +bool cariboulite_radio_wait_mixer_lock(cariboulite_radio_state_st* radio, int retries) +{ + rffc507x_device_status_st stat = {0}; + + // applicable only to the 6G channel + if (radio->type != cariboulite_channel_6g) + { + return false; + } + + int relock_retries = retries; + do + { + rffc507x_readback_status(&radio->cariboulite_sys->mixer, NULL, &stat); + rffc507x_print_stat(&stat); + if (!stat.pll_lock) rffc507x_relock(&radio->cariboulite_sys->mixer); + } while (!stat.pll_lock && relock_retries--); + + return stat.pll_lock; +} + +//================================================= +bool cariboulite_radio_wait_modem_lock(cariboulite_radio_state_st* radio, int retries) +{ + at86rf215_radio_pll_ctrl_st cfg = {0}; + int relock_retries = retries; + do + { + at86rf215_radio_get_pll_ctrl(&radio->cariboulite_sys->modem, GET_CH(radio->type), &cfg); + } while (!cfg.pll_locked && relock_retries--); + + return cfg.pll_locked; +} + +//================================================= +bool cariboulite_radio_wait_for_lock( cariboulite_radio_state_st* radio, bool *mod, bool *mix, int retries) +{ + bool mix_lock = true, mod_lock = true; + if (radio->type == cariboulite_channel_6g) + { + mix_lock = cariboulite_radio_wait_mixer_lock(radio, retries); + if (mix) *mix = mix_lock; + } + + mod_lock = cariboulite_radio_wait_modem_lock(radio, retries); + if (mod) *mod = mod_lock; + + return mix_lock && mod_lock; +} + +//========================================================================= +int cariboulite_radio_set_frequency(cariboulite_radio_state_st* radio, + bool break_before_make, + double *freq) +{ + double f_rf = *freq; + double modem_act_freq = 0.0; + double lo_act_freq = 0.0; + double act_freq = 0.0; + int error = 0; + cariboulite_ext_ref_freq_en ext_ref_choice = cariboulite_ext_ref_off; + conversion_dir_en conversion_direction = conversion_dir_none; + + //-------------------------------------------------------------------------------- + // SUB 1GHZ CONFIGURATION + //-------------------------------------------------------------------------------- + if (radio->type == cariboulite_channel_s1g) + { + if ( (f_rf >= CARIBOULITE_S1G_MIN1 && f_rf <= CARIBOULITE_S1G_MAX1) || + (f_rf >= CARIBOULITE_S1G_MIN2 && f_rf <= CARIBOULITE_S1G_MAX2) ) + { + // setup modem frequency <= f_rf + if (break_before_make) + { + at86rf215_radio_set_state(&radio->cariboulite_sys->modem, + at86rf215_rf_channel_900mhz, + at86rf215_radio_state_cmd_trx_off); + radio->state = at86rf215_radio_state_cmd_trx_off; + } + + modem_act_freq = at86rf215_setup_channel (&radio->cariboulite_sys->modem, + at86rf215_rf_channel_900mhz, + (uint32_t)f_rf); + + radio->if_frequency = 0; + radio->lo_pll_locked = 1; + radio->modem_pll_locked = cariboulite_radio_wait_modem_lock(radio, 3); + radio->if_frequency = modem_act_freq; + radio->actual_rf_frequency = radio->if_frequency; + radio->requested_rf_frequency = f_rf; + radio->rf_frequency_error = radio->actual_rf_frequency - radio->requested_rf_frequency; + + // return actual frequency + *freq = radio->actual_rf_frequency; + } + else + { + ZF_LOGE("unsupported frequency for S1G channel - %.2f Hz", f_rf); + error = -1; + } + } + + //-------------------------------------------------------------------------------- + // 30-6GHz CONFIGURATION + //-------------------------------------------------------------------------------- + else if (radio->type == cariboulite_channel_6g) + { + // Changing the frequency may sometimes need to break RX / TX + if (break_before_make) + { + // make sure that during the transition the modem is not transmitting and then + // verify that the FE is in low power mode + at86rf215_radio_set_state( &radio->cariboulite_sys->modem, + at86rf215_rf_channel_2400mhz, + at86rf215_radio_state_cmd_trx_off); + radio->state = at86rf215_radio_state_cmd_trx_off; + + caribou_fpga_set_io_ctrl_mode (&radio->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_low_power); + } + + // Calculate the best ext_ref + double f_rf_mod_32 = (f_rf / 32e6); + double f_rf_mod_26 = (f_rf / 26e6); + f_rf_mod_32 -= (uint64_t)(f_rf_mod_32); + f_rf_mod_26 -= (uint64_t)(f_rf_mod_26); + f_rf_mod_32 *= 32e6; + f_rf_mod_26 *= 26e6; + if (f_rf_mod_32 > 16e6) f_rf_mod_32 = 32e6 - f_rf_mod_32; + if (f_rf_mod_26 > 13e6) f_rf_mod_26 = 26e6 - f_rf_mod_26; + ext_ref_choice = f_rf_mod_32 > f_rf_mod_26 ? cariboulite_ext_ref_32mhz : cariboulite_ext_ref_26mhz; + cariboulite_setup_ext_ref (radio->cariboulite_sys, ext_ref_choice); + + // Decide the conversion direction and IF/RF/LO + //------------------------------------- + if (f_rf >= CARIBOULITE_MIN_MIX && + f_rf <= (CARIBOULITE_2G4_MIN) ) + { + // region #1 - UP CONVERSION + uint32_t modem_freq = CARIBOULITE_2G4_MAX; + //if (f_rf > (CARIBOULITE_2G4_MAX/2 - 15e6) && f_rf < (CARIBOULITE_2G4_MAX/2 + 15e6)) modem_freq = CARIBOULITE_2G4_MIN; + modem_act_freq = (double)at86rf215_setup_channel (&radio->cariboulite_sys->modem, + at86rf215_rf_channel_2400mhz, + modem_freq); + + // setup mixer LO according to the actual modem frequency + lo_act_freq = rffc507x_set_frequency(&radio->cariboulite_sys->mixer, modem_act_freq - f_rf); + act_freq = modem_act_freq - lo_act_freq; + + // setup fpga RFFE <= upconvert (tx / rx) + conversion_direction = conversion_dir_up; + } + //------------------------------------- + else if ( f_rf > CARIBOULITE_2G4_MIN && + f_rf <= CARIBOULITE_2G4_MAX ) + { + cariboulite_setup_ext_ref (radio->cariboulite_sys, cariboulite_ext_ref_off); + // region #2 - bypass mode + // setup modem frequency <= f_rf + modem_act_freq = (double)at86rf215_setup_channel (&radio->cariboulite_sys->modem, + at86rf215_rf_channel_2400mhz, + (uint32_t)f_rf); + lo_act_freq = 0; + act_freq = modem_act_freq; + conversion_direction = conversion_dir_none; + } + //------------------------------------- + else if ( f_rf > (CARIBOULITE_2G4_MAX) && + f_rf <= CARIBOULITE_MAX_MIX ) + { + // region #3 - DOWN-CONVERSION + // setup modem frequency <= CARIBOULITE_2G4_MIN + modem_act_freq = (double)at86rf215_setup_channel (&radio->cariboulite_sys->modem, + at86rf215_rf_channel_2400mhz, + (uint32_t)(CARIBOULITE_2G4_MIN)); + + uint32_t lo = f_rf + modem_act_freq; + //if (f_rf > (CARIBOULITE_2G4_MIN*2 + CARIBOULITE_MIN_LO)) lo = f_rf - modem_act_freq; + // setup mixer LO to according to actual modem frequency + lo_act_freq = rffc507x_set_frequency(&radio->cariboulite_sys->mixer, f_rf - modem_act_freq); + act_freq = lo_act_freq + modem_act_freq; + //if (f_rf > (CARIBOULITE_2G4_MIN*2 + CARIBOULITE_MIN_LO)) act_freq = modem_act_freq + lo_act_freq; + + // setup fpga RFFE <= downconvert (tx / rx) + conversion_direction = conversion_dir_down; + } + //------------------------------------- + else + { + ZF_LOGE("unsupported frequency for 6GHz channel - %.2f Hz", f_rf); + error = -1; + } + + // Setup the frontend + // This step takes the current radio direction of communication + // and the down/up conversion decision made before to setup the RF front-end + switch (conversion_direction) + { + case conversion_dir_up: + if (radio->channel_direction == cariboulite_channel_dir_rx) + { + caribou_fpga_set_io_ctrl_mode (&radio->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_rx_lowpass); + } + else if (radio->channel_direction == cariboulite_channel_dir_tx) + { + caribou_fpga_set_io_ctrl_mode (&radio->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_tx_lowpass); + } + break; + case conversion_dir_none: + caribou_fpga_set_io_ctrl_mode (&radio->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_bypass); + break; + case conversion_dir_down: + if (radio->channel_direction == cariboulite_channel_dir_rx) + { + caribou_fpga_set_io_ctrl_mode (&radio->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_rx_hipass); + } + else if (radio->channel_direction == cariboulite_channel_dir_tx) + { + caribou_fpga_set_io_ctrl_mode (&radio->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_tx_hipass); + } + break; + default: break; + } + + // Make sure the LO and the IF PLLs are locked + at86rf215_radio_set_state( &radio->cariboulite_sys->modem, + GET_CH(radio->type), + at86rf215_radio_state_cmd_tx_prep); + radio->state = at86rf215_radio_state_cmd_tx_prep; + + if (!cariboulite_radio_wait_for_lock(radio, &radio->modem_pll_locked, + lo_act_freq > CARIBOULITE_MIN_LO ? &radio->lo_pll_locked : NULL, + 100)) + { + if (!radio->lo_pll_locked) ZF_LOGE("PLL MIXER failed to lock LO frequency (%.2f Hz)", lo_act_freq); + if (!radio->modem_pll_locked) ZF_LOGE("PLL MODEM failed to lock IF frequency (%.2f Hz)", modem_act_freq); + error = 1; + } + + // Update the actual frequencies + radio->lo_frequency = lo_act_freq; + radio->if_frequency = modem_act_freq; + radio->actual_rf_frequency = act_freq; + radio->requested_rf_frequency = f_rf; + radio->rf_frequency_error = radio->actual_rf_frequency - radio->requested_rf_frequency; + if (freq) *freq = act_freq; + + // activate the channel according to the new configuration + cariboulite_radio_activate_channel(radio, 1); + } + + if (error >= 0) + { + ZF_LOGD("Frequency setting CH: %d, Wanted: %.2f Hz, Set: %.2f Hz (MOD: %.2f, MIX: %.2f)", + radio->type, f_rf, act_freq, modem_act_freq, lo_act_freq); + } + + return -error; +} + +//========================================================================= +int cariboulite_radio_get_frequency(cariboulite_radio_state_st* radio, + double *freq, double *lo, double* i_f) +{ + if (freq) *freq = radio->actual_rf_frequency; + if (lo) *lo = radio->lo_frequency; + if (i_f) *i_f = radio->if_frequency; +} + +//========================================================================= +int cariboulite_radio_activate_channel(cariboulite_radio_state_st* radio, + bool active) +{ + ZF_LOGD("Activating channel %d, dir = %s, active = %d", radio->type, radio->channel_direction==cariboulite_channel_dir_rx?"RX":"TX", active); + + // if the channel state is active, turn it off before reactivating + if (radio->state != at86rf215_radio_state_cmd_tx_prep) + { + at86rf215_radio_set_state( &radio->cariboulite_sys->modem, + GET_CH(radio->type), + at86rf215_radio_state_cmd_tx_prep); + radio->state = at86rf215_radio_state_cmd_tx_prep; + ZF_LOGD("Setup Modem state tx_prep"); + } + + if (!active) + { + at86rf215_radio_set_state( &radio->cariboulite_sys->modem, + GET_CH(radio->type), + at86rf215_radio_state_cmd_trx_off); + radio->state = at86rf215_radio_state_cmd_trx_off; + ZF_LOGD("Setup Modem state trx_off"); + return 0; + } + + // Activate the channel according to the configurations + // RX on both channels looks the same + if (radio->channel_direction == cariboulite_channel_dir_rx) + { + at86rf215_radio_set_state( &radio->cariboulite_sys->modem, + GET_CH(radio->type), + at86rf215_radio_state_cmd_rx); + ZF_LOGD("Setup Modem state cmd_rx"); + } + else if (radio->channel_direction == cariboulite_channel_dir_tx) + { + // if its an LO frequency output from the mixer - no need for modem output + // LO applicable only to the channel with the mixer + if (radio->lo_output && radio->type == cariboulite_channel_6g) + { + // here we need to configure lo bypass on the mixer + rffc507x_output_lo(&radio->cariboulite_sys->mixer, 1); + } + // otherwise we need the modem + else + { + // make sure the mixer doesn't bypass the lo + rffc507x_output_lo(&radio->cariboulite_sys->mixer, 0); + + cariboulite_radio_set_tx_bandwidth(radio, radio->cw_output?at86rf215_radio_tx_cut_off_80khz:radio->tx_bw); + + // CW output - constant I/Q values override + at86rf215_radio_set_tx_dac_input_iq(&radio->cariboulite_sys->modem, + GET_CH(radio->type), + radio->cw_output, 0x7E, + radio->cw_output, 0x3F); + + // transition to state TX + at86rf215_radio_set_state(&radio->cariboulite_sys->modem, + GET_CH(radio->type), + at86rf215_radio_state_cmd_tx); + + } + } + + return 0; +} + +//========================================================================= +int cariboulite_radio_set_cw_outputs(cariboulite_radio_state_st* radio, + bool lo_out, bool cw_out) +{ + if (radio->lo_output && radio->type == cariboulite_channel_6g) + { + radio->lo_output = lo_out; + } + else + { + radio->lo_output = false; + } + radio->cw_output = cw_out; + + if (cw_out) + { + radio->channel_direction = cariboulite_channel_dir_tx; + } + else + { + radio->channel_direction = cariboulite_channel_dir_rx; + } + + return 0; +} + +//========================================================================= +int cariboulite_radio_get_cw_outputs(cariboulite_radio_state_st* radio, + bool *lo_out, bool *cw_out) +{ + if (lo_out) *lo_out = radio->lo_output; + if (cw_out) *cw_out = radio->cw_output; + + return 0; +} + +//========================================================================= +int cariboulite_radio_create_smi_stream(cariboulite_radio_state_st* radio, + cariboulite_channel_dir_en dir, + void* context) +{ + caribou_smi_channel_en ch = GET_SMI_CH(radio->type); + caribou_smi_stream_type_en type = GET_SMI_DIR(dir); + + int stream_id = caribou_smi_setup_stream(&radio->cariboulite_sys->smi, + type, + ch, + caribou_smi_data_event, + context); + + // store the stream id's + if (type == caribou_smi_stream_type_read) + { + radio->rx_stream_id = stream_id; + } + else if (type == caribou_smi_stream_type_write) + { + radio->tx_stream_id = stream_id; + } + return stream_id; +} + +//========================================================================= +int cariboulite_radio_destroy_smi_stream(cariboulite_radio_state_st* radio, + cariboulite_channel_dir_en dir) +{ + int stream_id = (dir == cariboulite_channel_dir_rx) ? radio->rx_stream_id : radio->tx_stream_id; + if (stream_id == -1) + { + ZF_LOGE("The specified channel (%d) doesn't have open stream of type %d", radio->type, dir); + return -1; + } + + return caribou_smi_destroy_stream(&radio->cariboulite_sys->smi, stream_id); +} + +//========================================================================= +int cariboulite_radio_run_pause_stream(cariboulite_radio_state_st* radio, + cariboulite_channel_dir_en dir, + bool run) +{ + int stream_id = (dir == cariboulite_channel_dir_rx) ? radio->rx_stream_id : radio->tx_stream_id; + if (stream_id == -1) + { + ZF_LOGE("The specified channel (%d) doesn't have open stream of type %d", radio->type, dir); + return -1; + } + return caribou_smi_run_pause_stream (&radio->cariboulite_sys->smi, stream_id, run); +} \ No newline at end of file diff --git a/software/libcariboulite/src/cariboulite_radio.h b/software/libcariboulite/src/cariboulite_radio.h new file mode 100644 index 0000000..f7fd5d1 --- /dev/null +++ b/software/libcariboulite/src/cariboulite_radio.h @@ -0,0 +1,191 @@ +#ifndef __CARIBOULABS_RADIO_H__ +#define __CARIBOULABS_RADIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cariboulite_config/cariboulite_config.h" +#include "at86rf215/at86rf215.h" + + +typedef enum +{ + cariboulite_channel_dir_rx = 0, + cariboulite_channel_dir_tx = 1, +} cariboulite_channel_dir_en; + +typedef enum +{ + cariboulite_channel_s1g = 0, + cariboulite_channel_6g = 1, +} cariboulite_channel_en; + +typedef struct +{ + cariboulite_channel_en type; + bool cw_out; + bool lo_out; + cariboulite_ext_ref_src_en ext_ref_src; + uint32_t ext_ref_freq_hz; + + double requested_freq; + double modem_actual_freq; + double mixer_actual_freq; + double actual_freq; + double actual_freq_error; + + bool modem_lock; + bool mixer_lock; +} cariboulite_freq_construction_st; + +typedef struct +{ + cariboulite_st* cariboulite_sys; + cariboulite_channel_dir_en channel_direction; + cariboulite_channel_en type; + bool active; + bool cw_output; + bool lo_output; + + // MODEM STATES + at86rf215_radio_state_cmd_en state; + at86rf215_radio_irq_st interrupts; + + bool rx_agc_on; + int rx_gain_value_db; + + at86rf215_radio_rx_bw_en rx_bw; + at86rf215_radio_f_cut_en rx_fcut; + at86rf215_radio_sample_rate_en rx_fs; + + int tx_power; + at86rf215_radio_tx_cut_off_en tx_bw; + at86rf215_radio_f_cut_en tx_fcut; + at86rf215_radio_sample_rate_en tx_fs; + + // at86rf215_radio_energy_detection_st rx_energy_detection; + float rx_energy_detection_value; + float rx_rssi; + + // FREQUENCY + bool modem_pll_locked; + bool lo_pll_locked; + double lo_frequency; + double if_frequency; + double actual_rf_frequency; + double requested_rf_frequency; + double rf_frequency_error; + //cariboulite_freq_construction_st freq; + + // SMI STREAMS + int rx_stream_id; + int tx_stream_id; + + // OTHERS + uint8_t random_value; + float rx_thermal_noise_floor; + + // CALIBRATION + int num_of_rx_cal_points; + int num_of_tx_cal_points; + float rx_power_gain_calibration[6001]; + float tx_power_gain_calibration[6001]; +} cariboulite_radio_state_st; + +void cariboulite_radio_init(cariboulite_radio_state_st* radio, cariboulite_st *sys, cariboulite_channel_en type); +int cariboulite_radio_dispose(cariboulite_radio_state_st* radio); +int cariboulite_radio_sync_information(cariboulite_radio_state_st* radio); + +int cariboulite_radio_get_mod_state (cariboulite_radio_state_st* radio, at86rf215_radio_state_cmd_en *state); + +int cariboulite_radio_get_mod_intertupts (cariboulite_radio_state_st* radio, at86rf215_radio_irq_st **irq_table); + +int cariboulite_radio_set_rx_gain_control(cariboulite_radio_state_st* radio, + bool rx_agc_on, + int rx_gain_value_db); + +int cariboulite_radio_get_rx_gain_control(cariboulite_radio_state_st* radio, + bool *rx_agc_on, + int *rx_gain_value_db); + +int cariboulite_radio_get_rx_gain_limits(cariboulite_radio_state_st* radio, + int *rx_min_gain_value_db, + int *rx_max_gain_value_db, + int *rx_gain_value_resolution_db); + +int cariboulite_radio_set_rx_bandwidth(cariboulite_radio_state_st* radio, + at86rf215_radio_rx_bw_en rx_bw); + +int cariboulite_radio_get_rx_bandwidth(cariboulite_radio_state_st* radio, + at86rf215_radio_rx_bw_en *rx_bw); + +int cariboulite_radio_set_rx_samp_cutoff(cariboulite_radio_state_st* radio, + at86rf215_radio_sample_rate_en rx_sample_rate, + at86rf215_radio_f_cut_en rx_cutoff); + +int cariboulite_radio_get_rx_samp_cutoff(cariboulite_radio_state_st* radio, + at86rf215_radio_sample_rate_en *rx_sample_rate, + at86rf215_radio_f_cut_en *rx_cutoff); + + +int cariboulite_radio_set_tx_power(cariboulite_radio_state_st* radio, + int tx_power_dbm); + +int cariboulite_radio_get_tx_power(cariboulite_radio_state_st* radio, + int *tx_power_dbm); + + +int cariboulite_radio_set_tx_bandwidth(cariboulite_radio_state_st* radio, + at86rf215_radio_tx_cut_off_en tx_bw); + +int cariboulite_radio_get_tx_bandwidth(cariboulite_radio_state_st* radio, + at86rf215_radio_tx_cut_off_en *tx_bw); + +int cariboulite_radio_set_tx_samp_cutoff(cariboulite_radio_state_st* radio, + at86rf215_radio_sample_rate_en tx_sample_rate, + at86rf215_radio_f_cut_en tx_cutoff); + +int cariboulite_radio_get_tx_samp_cutoff(cariboulite_radio_state_st* radio, + at86rf215_radio_sample_rate_en *tx_sample_rate, + at86rf215_radio_f_cut_en *tx_cutoff); + + +int cariboulite_radio_get_rssi(cariboulite_radio_state_st* radio, float *rssi_dbm); +int cariboulite_radio_get_energy_det(cariboulite_radio_state_st* radio, float *energy_det_val); +int cariboulite_radio_get_rand_val(cariboulite_radio_state_st* radio, uint8_t *rnd); + +bool cariboulite_radio_wait_mixer_lock(cariboulite_radio_state_st* radio, int retries); +bool cariboulite_radio_wait_modem_lock(cariboulite_radio_state_st* radio, int retries); +int cariboulite_radio_set_frequency(cariboulite_radio_state_st* radio, + bool break_before_make, + double *freq); + +int cariboulite_radio_get_frequency(cariboulite_radio_state_st* radio, + double *freq, double *lo, double* i_f); + +int cariboulite_radio_activate_channel(cariboulite_radio_state_st* radio, + bool active); + +int cariboulite_radio_set_cw_outputs(cariboulite_radio_state_st* radio, + bool lo_out, bool cw_out); + +int cariboulite_radio_get_cw_outputs(cariboulite_radio_state_st* radio, + bool *lo_out, bool *cw_out); + +int cariboulite_radio_create_smi_stream(cariboulite_radio_state_st* radio, + cariboulite_channel_dir_en dir, + void* context); + +int cariboulite_radio_destroy_smi_stream(cariboulite_radio_state_st* radio, + cariboulite_channel_dir_en dir); + +int cariboulite_radio_run_pause_stream(cariboulite_radio_state_st* radio, + cariboulite_channel_dir_en dir, + bool run); + +#ifdef __cplusplus +} +#endif + +#endif // __CARIBOULABS_RADIO_H__ \ No newline at end of file diff --git a/software/libcariboulite/src/cariboulite_radios.c b/software/libcariboulite/src/cariboulite_radios.c index aa25399..ad27719 100644 --- a/software/libcariboulite/src/cariboulite_radios.c +++ b/software/libcariboulite/src/cariboulite_radios.c @@ -19,43 +19,6 @@ #define GET_RADIO_PTR(radio,chan) ((chan)==cariboulite_channel_s1g?&((radio)->radio_sub1g):&((radio)->radio_6g)) -#define GET_CH(rad_ch) ((rad_ch)==cariboulite_channel_s1g?at86rf215_rf_channel_900mhz:at86rf215_rf_channel_2400mhz) -//====================================================================== -typedef struct { - int bit_count; /* number of bits of entropy in data */ - int byte_count; /* number of bytes of data in array */ - unsigned char buf[1]; -} entropy_t; - -static int add_entropy(uint8_t byte) -{ - int rand_fid = open("/dev/urandom", O_RDWR); - if (rand_fid != 0) - { - // error opening device - ZF_LOGE("Opening /dev/urandom device file failed"); - return -1; - } - - entropy_t ent = { - .bit_count = 8, - .byte_count = 1, - .buf = {byte}, - }; - - if (ioctl(rand_fid, RNDADDENTROPY, &ent) != 0) - { - ZF_LOGE("IOCTL to /dev/urandom device file failed"); - } - - if (close(rand_fid) !=0 ) - { - ZF_LOGE("Closing /dev/urandom device file failed"); - return -1; - } - - return 0; -} //====================================================================== int cariboulite_init_radios(cariboulite_radios_st* radios, cariboulite_st *sys) @@ -63,96 +26,27 @@ int cariboulite_init_radios(cariboulite_radios_st* radios, cariboulite_st *sys) memset (radios, 0, sizeof(cariboulite_radios_st)); // Sub-1GHz - radios->radio_sub1g.cariboulite_sys = sys; - radios->radio_sub1g.active = true; - radios->radio_sub1g.channel_direction = cariboulite_channel_dir_rx; - radios->radio_sub1g.type = cariboulite_channel_s1g; - radios->radio_sub1g.cw_output = false; - radios->radio_sub1g.lo_output = false; - radios->radio_sub1g.rx_stream_id = -1; - radios->radio_sub1g.tx_stream_id = -1; + cariboulite_radio_init(&radios->radio_sub1g, sys, cariboulite_channel_s1g); // Wide band channel - radios->radio_6g.cariboulite_sys = sys; - radios->radio_6g.active = true; - radios->radio_6g.channel_direction = cariboulite_channel_dir_rx; - radios->radio_6g.type = cariboulite_channel_6g; - radios->radio_6g.cw_output = false; - radios->radio_6g.lo_output = false; - radios->radio_6g.rx_stream_id = -1; - radios->radio_6g.tx_stream_id = -1; + cariboulite_radio_init(&radios->radio_6g, sys, cariboulite_channel_6g); - cariboulite_sync_radio_information(radios); + cariboulite_radio_sync_information(&radios->radio_sub1g); + cariboulite_radio_sync_information(&radios->radio_6g); } //====================================================================== int cariboulite_dispose_radios(cariboulite_radios_st* radios) { - radios->radio_sub1g.active = false; - radios->radio_6g.active = false; - - // If streams are active - destroy them - if (radios->radio_sub1g.rx_stream_id != -1) - { - caribou_smi_destroy_stream(&radios->radio_sub1g.cariboulite_sys->smi, radios->radio_sub1g.rx_stream_id); - radios->radio_sub1g.rx_stream_id = -1; - } - - if (radios->radio_sub1g.tx_stream_id != -1) - { - caribou_smi_destroy_stream(&radios->radio_sub1g.cariboulite_sys->smi, radios->radio_sub1g.tx_stream_id); - radios->radio_sub1g.tx_stream_id = -1; - } - - if (radios->radio_6g.rx_stream_id != -1) - { - caribou_smi_destroy_stream(&radios->radio_6g.cariboulite_sys->smi, radios->radio_sub1g.rx_stream_id); - radios->radio_6g.rx_stream_id = -1; - } - - if (radios->radio_6g.tx_stream_id != -1) - { - caribou_smi_destroy_stream(&radios->radio_6g.cariboulite_sys->smi, radios->radio_sub1g.tx_stream_id); - radios->radio_6g.tx_stream_id = -1; - } - usleep(100000); - - cariboulite_radio_state_st* rad_s1g = GET_RADIO_PTR(radios,cariboulite_channel_s1g); - cariboulite_radio_state_st* rad_6g = GET_RADIO_PTR(radios,cariboulite_channel_6g); - - at86rf215_radio_set_state( &rad_s1g->cariboulite_sys->modem, - GET_CH(cariboulite_channel_s1g), - at86rf215_radio_state_cmd_trx_off); - rad_s1g->state = at86rf215_radio_state_cmd_trx_off; - - at86rf215_radio_set_state( &rad_6g->cariboulite_sys->modem, - GET_CH(cariboulite_channel_6g), - at86rf215_radio_state_cmd_trx_off); - rad_6g->state = at86rf215_radio_state_cmd_trx_off; - - caribou_fpga_set_io_ctrl_mode (&rad_6g->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_low_power); + cariboulite_radio_dispose(&radios->radio_sub1g); + cariboulite_radio_dispose(&radios->radio_6g); } //====================================================================== int cariboulite_sync_radio_information(cariboulite_radios_st* radios) { - cariboulite_get_mod_state (radios, cariboulite_channel_s1g, NULL); - cariboulite_get_mod_state (radios, cariboulite_channel_6g, NULL); - - cariboulite_get_rx_gain_control(radios, cariboulite_channel_s1g, NULL, NULL); - cariboulite_get_rx_gain_control(radios, cariboulite_channel_6g, NULL, NULL); - - cariboulite_get_rx_bandwidth(radios, cariboulite_channel_s1g, NULL); - cariboulite_get_rx_bandwidth(radios, cariboulite_channel_6g, NULL); - - cariboulite_get_tx_power(radios, cariboulite_channel_s1g, NULL); - cariboulite_get_tx_power(radios, cariboulite_channel_6g, NULL); - - cariboulite_get_rssi(radios, cariboulite_channel_s1g, NULL); - cariboulite_get_rssi(radios, cariboulite_channel_6g, NULL); - - cariboulite_get_energy_det(radios, cariboulite_channel_s1g, NULL); - cariboulite_get_energy_det(radios, cariboulite_channel_6g, NULL); + cariboulite_radio_sync_information(&radios->radio_sub1g); + cariboulite_radio_sync_information(&radios->radio_6g); } //====================================================================== @@ -160,35 +54,15 @@ int cariboulite_get_mod_state ( cariboulite_radios_st* radios, cariboulite_channel_en channel, at86rf215_radio_state_cmd_en *state) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - rad->state = at86rf215_radio_get_state(&rad->cariboulite_sys->modem, GET_CH(channel)); - - if (state) *state = rad->state; - return 0; + return cariboulite_radio_get_mod_state (GET_RADIO_PTR(radios,channel), state); } - //====================================================================== int cariboulite_get_mod_intertupts (cariboulite_radios_st* radios, cariboulite_channel_en channel, at86rf215_radio_irq_st **irq_table) { - at86rf215_irq_st irq = {0}; - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - at86rf215_get_irqs(&rad->cariboulite_sys->modem, &irq, 0); - - if (channel == cariboulite_channel_s1g) - { - memcpy (&rad->interrupts, &irq.radio09, sizeof(at86rf215_radio_irq_st)); - if (irq_table) *irq_table = &irq.radio09; - } - else - { - memcpy (&rad->interrupts, &irq.radio24, sizeof(at86rf215_radio_irq_st)); - if (irq_table) *irq_table = &irq.radio24; - } - - return 0; + return cariboulite_radio_get_mod_intertupts (GET_RADIO_PTR(radios,channel), irq_table); } //====================================================================== @@ -197,27 +71,9 @@ int cariboulite_set_rx_gain_control(cariboulite_radios_st* radios, bool rx_agc_on, int rx_gain_value_db) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - - int control_gain_val = (int)roundf((float)(rx_gain_value_db) / 3.0f); - if (control_gain_val < 0) control_gain_val = 0; - if (control_gain_val > 23) control_gain_val = 23; - - at86rf215_radio_agc_ctrl_st rx_gain_control = - { - .agc_measure_source_not_filtered = 1, - .avg = at86rf215_radio_agc_averaging_32, - .reset_cmd = 0, - .freeze_cmd = 0, - .enable_cmd = rx_agc_on, - .att = at86rf215_radio_agc_relative_atten_21_db, - .gain_control_word = control_gain_val, - }; - - at86rf215_radio_setup_agc(&rad->cariboulite_sys->modem, GET_CH(channel), &rx_gain_control); - rad->rx_agc_on = rx_agc_on; - rad->rx_gain_value_db = rx_gain_value_db; - return 0; + return cariboulite_radio_set_rx_gain_control(GET_RADIO_PTR(radios,channel), + rx_agc_on, + rx_gain_value_db); } //====================================================================== @@ -226,15 +82,9 @@ int cariboulite_get_rx_gain_control(cariboulite_radios_st* radios, bool *rx_agc_on, int *rx_gain_value_db) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - at86rf215_radio_agc_ctrl_st agc_ctrl = {0}; - at86rf215_radio_get_agc(&rad->cariboulite_sys->modem, GET_CH(channel), &agc_ctrl); - - rad->rx_agc_on = agc_ctrl.enable_cmd; - rad->rx_gain_value_db = agc_ctrl.gain_control_word * 3; - if (rx_agc_on) *rx_agc_on = rad->rx_agc_on; - if (rx_gain_value_db) *rx_gain_value_db = rad->rx_gain_value_db; - return 0; + return cariboulite_radio_get_rx_gain_control(GET_RADIO_PTR(radios,channel), + rx_agc_on, + rx_gain_value_db); } //====================================================================== @@ -244,10 +94,10 @@ int cariboulite_get_rx_gain_limits(cariboulite_radios_st* radios, int *rx_max_gain_value_db, int *rx_gain_value_resolution_db) { - if (rx_min_gain_value_db) *rx_min_gain_value_db = 0; - if (rx_max_gain_value_db) *rx_max_gain_value_db = 23*3; - if (rx_gain_value_resolution_db) *rx_gain_value_resolution_db = 3; - return 0; + return cariboulite_radio_get_rx_gain_limits(NULL, + rx_min_gain_value_db, + rx_max_gain_value_db, + rx_gain_value_resolution_db); } //====================================================================== @@ -255,37 +105,8 @@ int cariboulite_set_rx_bandwidth(cariboulite_radios_st* radios, cariboulite_channel_en channel, at86rf215_radio_rx_bw_en rx_bw) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - at86rf215_radio_f_cut_en fcut = at86rf215_radio_rx_f_cut_half_fs; + return cariboulite_radio_set_rx_bandwidth(GET_RADIO_PTR(radios,channel), rx_bw); - // Automatically calculate the digital f_cut - if (rx_bw >= at86rf215_radio_rx_bw_BW160KHZ_IF250KHZ && rx_bw <= at86rf215_radio_rx_bw_BW500KHZ_IF500KHZ) - fcut = at86rf215_radio_rx_f_cut_0_25_half_fs; - else if (rx_bw >= at86rf215_radio_rx_bw_BW630KHZ_IF1000KHZ && rx_bw <= at86rf215_radio_rx_bw_BW630KHZ_IF1000KHZ) - fcut = at86rf215_radio_rx_f_cut_0_375_half_fs; - else if (rx_bw >= at86rf215_radio_rx_bw_BW800KHZ_IF1000KHZ && rx_bw <= at86rf215_radio_rx_bw_BW1000KHZ_IF1000KHZ) - fcut = at86rf215_radio_rx_f_cut_0_5_half_fs; - else if (rx_bw >= at86rf215_radio_rx_bw_BW1250KHZ_IF2000KHZ && rx_bw <= at86rf215_radio_rx_bw_BW1250KHZ_IF2000KHZ) - fcut = at86rf215_radio_rx_f_cut_0_75_half_fs; - else - fcut = at86rf215_radio_rx_f_cut_half_fs; - - rad->rx_fcut = fcut; - - at86rf215_radio_set_rx_bw_samp_st cfg = - { - .inverter_sign_if = 0, - .shift_if_freq = 1, // A value of one configures the receiver to shift the IF frequency - // by factor of 1.25. This is useful to place the image frequency according - // to channel scheme. This increases the IF frequency to max 2.5MHz - // thus places the internal LO fasr away from the signal => lower noise - .bw = rx_bw, - .fcut = rad->rx_fcut, // keep the same - .fs = rad->rx_fs, // keep the same - }; - at86rf215_radio_set_rx_bandwidth_sampling(&rad->cariboulite_sys->modem, GET_CH(channel), &cfg); - rad->rx_bw = rx_bw; - return 0; } //====================================================================== @@ -293,14 +114,7 @@ int cariboulite_get_rx_bandwidth(cariboulite_radios_st* radios, cariboulite_channel_en channel, at86rf215_radio_rx_bw_en *rx_bw) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - at86rf215_radio_set_rx_bw_samp_st cfg = {0}; - at86rf215_radio_get_rx_bandwidth_sampling(&rad->cariboulite_sys->modem, GET_CH(channel), &cfg); - rad->rx_bw = cfg.bw; - rad->rx_fcut = cfg.fcut; - rad->rx_fs = cfg.fs; - if (rx_bw) *rx_bw = rad->rx_bw; - return 0; + cariboulite_radio_get_rx_bandwidth(GET_RADIO_PTR(radios,channel), rx_bw); } //====================================================================== @@ -309,23 +123,9 @@ int cariboulite_set_rx_samp_cutoff(cariboulite_radios_st* radios, at86rf215_radio_sample_rate_en rx_sample_rate, at86rf215_radio_f_cut_en rx_cutoff) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - - at86rf215_radio_set_rx_bw_samp_st cfg = - { - .inverter_sign_if = 0, // A value of one configures the receiver to implement the inverted-sign - // IF frequency. Use default setting for normal operation - .shift_if_freq = 1, // A value of one configures the receiver to shift the IF frequency - // by factor of 1.25. This is useful to place the image frequency according - // to channel scheme. - .bw = rad->rx_bw, // keep the same - .fcut = rx_cutoff, - .fs = rx_sample_rate, - }; - at86rf215_radio_set_rx_bandwidth_sampling(&rad->cariboulite_sys->modem, GET_CH(channel), &cfg); - rad->rx_fs = rx_sample_rate; - rad->rx_fcut = rx_cutoff; - return 0; + return cariboulite_radio_set_rx_samp_cutoff(GET_RADIO_PTR(radios,channel), + rx_sample_rate, + rx_cutoff); } //====================================================================== @@ -334,11 +134,9 @@ int cariboulite_get_rx_samp_cutoff(cariboulite_radios_st* radios, at86rf215_radio_sample_rate_en *rx_sample_rate, at86rf215_radio_f_cut_en *rx_cutoff) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - cariboulite_get_rx_bandwidth(radios, channel, NULL); - if (rx_sample_rate) *rx_sample_rate = rad->rx_fs; - if (rx_cutoff) *rx_cutoff = rad->rx_fcut; - return 0; + return cariboulite_radio_get_rx_samp_cutoff(GET_RADIO_PTR(radios,channel), + rx_sample_rate, + rx_cutoff); } //====================================================================== @@ -346,27 +144,7 @@ int cariboulite_set_tx_power(cariboulite_radios_st* radios, cariboulite_channel_en channel, int tx_power_dbm) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - if (tx_power_dbm < -18) tx_power_dbm = -18; - if (tx_power_dbm > 13) tx_power_dbm = 13; - int tx_power_ctrl = 18 + tx_power_dbm; - - at86rf215_radio_tx_ctrl_st cfg = - { - .pa_ramping_time = at86rf215_radio_tx_pa_ramp_16usec, - .current_reduction = at86rf215_radio_pa_current_reduction_0ma, // we can use this to gain some more - // granularity with the tx gain control - .tx_power = tx_power_ctrl, - .analog_bw = rad->tx_bw, // same as before - .digital_bw = rad->tx_fcut, // same as before - .fs = rad->tx_fs, // same as before - .direct_modulation = 0, - }; - - at86rf215_radio_setup_tx_ctrl(&rad->cariboulite_sys->modem, GET_CH(channel), &cfg); - rad->tx_power = tx_power_dbm; - - return 0; + return cariboulite_radio_set_tx_power(GET_RADIO_PTR(radios,channel), tx_power_dbm); } //====================================================================== @@ -374,16 +152,7 @@ int cariboulite_get_tx_power(cariboulite_radios_st* radios, cariboulite_channel_en channel, int *tx_power_dbm) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - at86rf215_radio_tx_ctrl_st cfg = {0}; - at86rf215_radio_get_tx_ctrl(&rad->cariboulite_sys->modem, GET_CH(channel), &cfg); - rad->tx_power = cfg.tx_power - 18; - rad->tx_bw = cfg.analog_bw; - rad->tx_fcut = cfg.digital_bw; - rad->tx_fs = cfg.fs; - - if (tx_power_dbm) *tx_power_dbm = rad->tx_power; - return 0; + return cariboulite_radio_get_tx_power(GET_RADIO_PTR(radios,channel), tx_power_dbm); } //====================================================================== @@ -391,23 +160,7 @@ int cariboulite_set_tx_bandwidth(cariboulite_radios_st* radios, cariboulite_channel_en channel, at86rf215_radio_tx_cut_off_en tx_bw) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - at86rf215_radio_tx_ctrl_st cfg = - { - .pa_ramping_time = at86rf215_radio_tx_pa_ramp_16usec, - .current_reduction = at86rf215_radio_pa_current_reduction_0ma, // we can use this to gain some more - // granularity with the tx gain control - .tx_power = 18 + rad->tx_power, // same as before - .analog_bw = tx_bw, - .digital_bw = rad->tx_fcut, // same as before - .fs = rad->tx_fs, // same as before - .direct_modulation = 0, - }; - - at86rf215_radio_setup_tx_ctrl(&rad->cariboulite_sys->modem, GET_CH(channel), &cfg); - rad->tx_bw = tx_bw; - - return 0; + return cariboulite_radio_set_tx_bandwidth(GET_RADIO_PTR(radios,channel), tx_bw); } //====================================================================== @@ -415,10 +168,7 @@ int cariboulite_get_tx_bandwidth(cariboulite_radios_st* radios, cariboulite_channel_en channel, at86rf215_radio_tx_cut_off_en *tx_bw) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - cariboulite_get_tx_power(radios, channel, NULL); - if (tx_bw) *tx_bw = rad->tx_bw; - return 0; + return cariboulite_radio_get_tx_bandwidth(GET_RADIO_PTR(radios,channel), tx_bw); } //====================================================================== @@ -427,139 +177,38 @@ int cariboulite_set_tx_samp_cutoff(cariboulite_radios_st* radios, at86rf215_radio_sample_rate_en tx_sample_rate, at86rf215_radio_f_cut_en tx_cutoff) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - at86rf215_radio_tx_ctrl_st cfg = - { - .pa_ramping_time = at86rf215_radio_tx_pa_ramp_16usec, - .current_reduction = at86rf215_radio_pa_current_reduction_0ma, // we can use this to gain some more - // granularity with the tx gain control - .tx_power = 18 + rad->tx_power, // same as before - .analog_bw = rad->tx_bw, // same as before - .digital_bw = tx_cutoff, - .fs = tx_sample_rate, - .direct_modulation = 0, - }; - - at86rf215_radio_setup_tx_ctrl(&rad->cariboulite_sys->modem, GET_CH(channel), &cfg); - rad->tx_fcut = tx_cutoff; - rad->tx_fs = tx_sample_rate; - - return 0; + return cariboulite_radio_set_tx_samp_cutoff(GET_RADIO_PTR(radios,channel), + tx_sample_rate, + tx_cutoff); } //====================================================================== int cariboulite_get_tx_samp_cutoff(cariboulite_radios_st* radios, cariboulite_channel_en channel, at86rf215_radio_sample_rate_en *tx_sample_rate, - at86rf215_radio_f_cut_en *rx_cutoff) + at86rf215_radio_f_cut_en *tx_cutoff) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - cariboulite_get_tx_power(radios, channel, NULL); - if (tx_sample_rate) *tx_sample_rate = rad->tx_fs; - if (rx_cutoff) *rx_cutoff = rad->tx_fcut; - return 0; + return cariboulite_radio_get_tx_samp_cutoff(GET_RADIO_PTR(radios,channel), + tx_sample_rate, + tx_cutoff); } //====================================================================== int cariboulite_get_rssi(cariboulite_radios_st* radios, cariboulite_channel_en channel, float *rssi_dbm) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - float rssi = at86rf215_radio_get_rssi_dbm(&rad->cariboulite_sys->modem, GET_CH(channel)); - if (rssi >= -127.0 && rssi <= 4) // register only valid values - { - rad->rx_rssi = rssi; - if (rssi_dbm) *rssi_dbm = rssi; - return 0; - } - - if (rssi_dbm) *rssi_dbm = rad->rx_rssi; - return -1; + return cariboulite_radio_get_rssi(GET_RADIO_PTR(radios,channel), rssi_dbm); } //====================================================================== int cariboulite_get_energy_det(cariboulite_radios_st* radios, cariboulite_channel_en channel, float *energy_det_val) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - at86rf215_radio_energy_detection_st det = {0}; - at86rf215_radio_get_energy_detection(&rad->cariboulite_sys->modem, GET_CH(channel), &det); - - if (det.energy_detection_value >= -127.0 && det.energy_detection_value <= 4) // register only valid values - { - rad->rx_energy_detection_value = det.energy_detection_value; - if (energy_det_val) *energy_det_val = rad->rx_energy_detection_value; - return 0; - } - - if (energy_det_val) *energy_det_val = rad->rx_energy_detection_value; - return -1; + return cariboulite_radio_get_energy_det(GET_RADIO_PTR(radios,channel), energy_det_val); } //====================================================================== int cariboulite_get_rand_val(cariboulite_radios_st* radios, cariboulite_channel_en channel, uint8_t *rnd) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - rad->random_value = at86rf215_radio_get_random_value(&rad->cariboulite_sys->modem, GET_CH(channel)); - if (rnd) *rnd = rad->random_value; - add_entropy(rad->random_value); - return 0; -} - - -//================================================= -#define CARIBOULITE_MIN_MIX (1.0e6) // 30 -#define CARIBOULITE_MAX_MIX (6000.0e6) // 6000 -#define CARIBOULITE_MIN_LO (85.0e6) -#define CARIBOULITE_MAX_LO (4200.0e6) -#define CARIBOULITE_2G4_MIN (2395.0e6) // 2400 -#define CARIBOULITE_2G4_MAX (2485.0e6) // 2483.5 -//#define CARIBOULITE_S1G_MIN1 (389.5e6) -#define CARIBOULITE_S1G_MIN1 (350.0e6) -#define CARIBOULITE_S1G_MAX1 (510.0e6) -#define CARIBOULITE_S1G_MIN2 (779.0e6) -#define CARIBOULITE_S1G_MAX2 (1020.0e6) - -typedef enum -{ - conversion_dir_none = 0, - conversion_dir_up = 1, - conversion_dir_down = 2, -} conversion_dir_en; - -//================================================= -bool cariboulite_wait_for_lock( cariboulite_radio_state_st* rad, bool *mod, bool *mix, int retries) -{ - bool mix_lock = true, mod_lock = true; - if (mix) - { - rffc507x_device_status_st stat = {0}; - int relock_retries = retries; - do - { - rffc507x_readback_status(&rad->cariboulite_sys->mixer, NULL, &stat); - rffc507x_print_stat(&stat); - if (!stat.pll_lock) rffc507x_relock(&rad->cariboulite_sys->mixer); - } while (!stat.pll_lock && relock_retries--); - - *mix = stat.pll_lock; - mix_lock = (bool)stat.pll_lock; - } - - if (mod) - { - at86rf215_radio_pll_ctrl_st cfg = {0}; - int relock_retries = retries; - do - { - at86rf215_rf_channel_en ch = rad->type == cariboulite_channel_s1g ? - at86rf215_rf_channel_900mhz : at86rf215_rf_channel_2400mhz; - at86rf215_radio_get_pll_ctrl(&rad->cariboulite_sys->modem, ch, &cfg); - } while (!cfg.pll_locked && relock_retries--); - - *mod = cfg.pll_locked; - mod_lock = (bool)cfg.pll_locked; - } - - return mix_lock && mod_lock; + return cariboulite_radio_get_rand_val(GET_RADIO_PTR(radios,channel), rnd); } //================================================= @@ -568,214 +217,9 @@ int cariboulite_set_frequency( cariboulite_radios_st* radios, bool break_before_make, double *freq) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - - double f_rf = *freq; - double modem_act_freq = 0.0; - double lo_act_freq = 0.0; - double act_freq = 0.0; - int error = 0; - cariboulite_ext_ref_freq_en ext_ref_choice = cariboulite_ext_ref_off; - conversion_dir_en conversion_direction = conversion_dir_none; - - //-------------------------------------------------------------------------------- - // SUB 1GHZ CONFIGURATION - //-------------------------------------------------------------------------------- - if (channel == cariboulite_channel_s1g) - { - if ( (f_rf >= CARIBOULITE_S1G_MIN1 && f_rf <= CARIBOULITE_S1G_MAX1) || - (f_rf >= CARIBOULITE_S1G_MIN2 && f_rf <= CARIBOULITE_S1G_MAX2) ) - { - // setup modem frequency <= f_rf - if (break_before_make) - { - at86rf215_radio_set_state( &rad->cariboulite_sys->modem, - at86rf215_rf_channel_900mhz, - at86rf215_radio_state_cmd_trx_off); - rad->state = at86rf215_radio_state_cmd_trx_off; - } - - modem_act_freq = at86rf215_setup_channel (&rad->cariboulite_sys->modem, - at86rf215_rf_channel_900mhz, - (uint32_t)f_rf); - - at86rf215_radio_pll_ctrl_st cfg = {0}; - at86rf215_radio_get_pll_ctrl(&rad->cariboulite_sys->modem, at86rf215_rf_channel_900mhz, &cfg); - - rad->if_frequency = 0; - rad->lo_pll_locked = 1; - rad->modem_pll_locked = cfg.pll_locked; - rad->if_frequency = modem_act_freq; - rad->actual_rf_frequency = rad->if_frequency; - rad->requested_rf_frequency = f_rf; - rad->rf_frequency_error = rad->actual_rf_frequency - rad->requested_rf_frequency; - - // return actual frequency - *freq = rad->actual_rf_frequency; - } - else - { - // error - unsupported frequency for S1G channel - ZF_LOGE("unsupported frequency for S1G channel - %.2f Hz", f_rf); - error = -1; - } - } - //-------------------------------------------------------------------------------- - // 30-6GHz CONFIGURATION - //-------------------------------------------------------------------------------- - else if (channel == cariboulite_channel_6g) - { - // Changing the frequency may sometimes need to break RX / TX - if (break_before_make) - { - // make sure that during the transition the modem is not transmitting and then - // verify that the FE is in low power mode - at86rf215_radio_set_state( &rad->cariboulite_sys->modem, - at86rf215_rf_channel_2400mhz, - at86rf215_radio_state_cmd_trx_off); - rad->state = at86rf215_radio_state_cmd_trx_off; - - caribou_fpga_set_io_ctrl_mode (&rad->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_low_power); - } - - // Calculate the best ext_ref - double f_rf_mod_32 = (f_rf / 32e6); - double f_rf_mod_26 = (f_rf / 26e6); - f_rf_mod_32 -= (uint64_t)(f_rf_mod_32); - f_rf_mod_26 -= (uint64_t)(f_rf_mod_26); - f_rf_mod_32 *= 32e6; - f_rf_mod_26 *= 26e6; - if (f_rf_mod_32 > 16e6) f_rf_mod_32 = 32e6 - f_rf_mod_32; - if (f_rf_mod_26 > 13e6) f_rf_mod_26 = 26e6 - f_rf_mod_26; - ext_ref_choice = f_rf_mod_32 > f_rf_mod_26 ? cariboulite_ext_ref_32mhz : cariboulite_ext_ref_26mhz; - cariboulite_setup_ext_ref (rad->cariboulite_sys, ext_ref_choice); - - // Decide the conversion direction and IF/RF/LO - //------------------------------------- - if (f_rf >= CARIBOULITE_MIN_MIX && - f_rf <= (CARIBOULITE_2G4_MIN) ) - { - // region #1 - UP CONVERSION - uint32_t modem_freq = CARIBOULITE_2G4_MAX; - //if (f_rf > (CARIBOULITE_2G4_MAX/2 - 15e6) && f_rf < (CARIBOULITE_2G4_MAX/2 + 15e6)) modem_freq = CARIBOULITE_2G4_MIN; - modem_act_freq = (double)at86rf215_setup_channel (&rad->cariboulite_sys->modem, - at86rf215_rf_channel_2400mhz, - modem_freq); - - // setup mixer LO according to the actual modem frequency - lo_act_freq = rffc507x_set_frequency(&rad->cariboulite_sys->mixer, modem_act_freq - f_rf); - act_freq = modem_act_freq - lo_act_freq; - - // setup fpga RFFE <= upconvert (tx / rx) - conversion_direction = conversion_dir_up; - } - //------------------------------------- - else if ( f_rf > CARIBOULITE_2G4_MIN && - f_rf <= CARIBOULITE_2G4_MAX ) - { - cariboulite_setup_ext_ref (rad->cariboulite_sys, cariboulite_ext_ref_off); - // region #2 - bypass mode - // setup modem frequency <= f_rf - modem_act_freq = (double)at86rf215_setup_channel (&rad->cariboulite_sys->modem, - at86rf215_rf_channel_2400mhz, - (uint32_t)f_rf); - lo_act_freq = 0; - act_freq = modem_act_freq; - conversion_direction = conversion_dir_none; - } - //------------------------------------- - else if ( f_rf > (CARIBOULITE_2G4_MAX) && - f_rf <= CARIBOULITE_MAX_MIX ) - { - // region #3 - DOWN-CONVERSION - // setup modem frequency <= CARIBOULITE_2G4_MIN - modem_act_freq = (double)at86rf215_setup_channel (&rad->cariboulite_sys->modem, - at86rf215_rf_channel_2400mhz, - (uint32_t)(CARIBOULITE_2G4_MIN)); - - uint32_t lo = f_rf + modem_act_freq; - //if (f_rf > (CARIBOULITE_2G4_MIN*2 + CARIBOULITE_MIN_LO)) lo = f_rf - modem_act_freq; - // setup mixer LO to according to actual modem frequency - lo_act_freq = rffc507x_set_frequency(&rad->cariboulite_sys->mixer, f_rf - modem_act_freq); - act_freq = lo_act_freq + modem_act_freq; - //if (f_rf > (CARIBOULITE_2G4_MIN*2 + CARIBOULITE_MIN_LO)) act_freq = modem_act_freq + lo_act_freq; - - // setup fpga RFFE <= downconvert (tx / rx) - conversion_direction = conversion_dir_down; - } - //------------------------------------- - else - { - // error - unsupported frequency for 6G channel - ZF_LOGE("unsupported frequency for 6GHz channel - %.2f Hz", f_rf); - error = -1; - } - - // Setup the frontend - // This step takes the current radio direction of communication - // and the down/up conversion decision made before to setup the RF front-end - switch (conversion_direction) - { - case conversion_dir_up: - if (rad->channel_direction == cariboulite_channel_dir_rx) - { - caribou_fpga_set_io_ctrl_mode (&rad->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_rx_lowpass); - } - else if (rad->channel_direction == cariboulite_channel_dir_tx) - { - caribou_fpga_set_io_ctrl_mode (&rad->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_tx_lowpass); - } - break; - case conversion_dir_none: - caribou_fpga_set_io_ctrl_mode (&rad->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_bypass); - break; - case conversion_dir_down: - if (rad->channel_direction == cariboulite_channel_dir_rx) - { - caribou_fpga_set_io_ctrl_mode (&rad->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_rx_hipass); - } - else if (rad->channel_direction == cariboulite_channel_dir_tx) - { - caribou_fpga_set_io_ctrl_mode (&rad->cariboulite_sys->fpga, 0, caribou_fpga_io_ctrl_rfm_tx_hipass); - } - break; - default: break; - } - - // Make sure the LO and the IF PLLs are locked - at86rf215_radio_set_state( &rad->cariboulite_sys->modem, - GET_CH(channel), - at86rf215_radio_state_cmd_tx_prep); - rad->state = at86rf215_radio_state_cmd_tx_prep; - - if (!cariboulite_wait_for_lock(rad, &rad->modem_pll_locked, - lo_act_freq > CARIBOULITE_MIN_LO ? &rad->lo_pll_locked : NULL, - 100)) - { - if (!rad->lo_pll_locked) ZF_LOGE("PLL MIXER failed to lock LO frequency (%.2f Hz)", lo_act_freq); - if (!rad->modem_pll_locked) ZF_LOGE("PLL MODEM failed to lock IF frequency (%.2f Hz)", modem_act_freq); - error = 1; - } - - // Update the actual frequencies - rad->lo_frequency = lo_act_freq; - rad->if_frequency = modem_act_freq; - rad->actual_rf_frequency = act_freq; - rad->requested_rf_frequency = f_rf; - rad->rf_frequency_error = rad->actual_rf_frequency - rad->requested_rf_frequency; - if (freq) *freq = act_freq; - - // activate the channel according to the new configuration - cariboulite_activate_channel(radios, channel, 1); - } - - if (error >= 0) - { - ZF_LOGD("Frequency setting CH: %d, Wanted: %.2f Hz, Set: %.2f Hz (MOD: %.2f, MIX: %.2f)", - channel, f_rf, act_freq, modem_act_freq, lo_act_freq); - } - - return -error; + return cariboulite_radio_set_frequency(GET_RADIO_PTR(radios,channel), + break_before_make, + freq); } //====================================================================== @@ -783,10 +227,8 @@ int cariboulite_get_frequency( cariboulite_radios_st* radios, cariboulite_channel_en channel, double *freq, double *lo, double* i_f) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - if (freq) *freq = rad->actual_rf_frequency; - if (lo) *lo = rad->lo_frequency; - if (i_f) *i_f = rad->if_frequency; + return cariboulite_radio_get_frequency(GET_RADIO_PTR(radios,channel), + freq, lo, i_f); } //====================================================================== @@ -794,142 +236,34 @@ int cariboulite_activate_channel(cariboulite_radios_st* radios, cariboulite_channel_en channel, bool active) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - - ZF_LOGD("Activating channel %d, dir = %s, active = %d", channel, rad->channel_direction==cariboulite_channel_dir_rx?"RX":"TX", active); - // if the channel state is active, turn it off before reactivating - if (rad->state != at86rf215_radio_state_cmd_tx_prep) - { - at86rf215_radio_set_state( &rad->cariboulite_sys->modem, - GET_CH(channel), - at86rf215_radio_state_cmd_tx_prep); - rad->state = at86rf215_radio_state_cmd_tx_prep; - ZF_LOGD("Setup Modem state tx_prep"); - } - - if (!active) - { - at86rf215_radio_set_state( &rad->cariboulite_sys->modem, - GET_CH(channel), - at86rf215_radio_state_cmd_trx_off); - rad->state = at86rf215_radio_state_cmd_trx_off; - ZF_LOGD("Setup Modem state trx_off"); - return 0; - } - - // Activate the channel according to the configurations - // RX on both channels looks the same - if (rad->channel_direction == cariboulite_channel_dir_rx) - { - at86rf215_radio_set_state( &rad->cariboulite_sys->modem, - GET_CH(channel), - at86rf215_radio_state_cmd_rx); - ZF_LOGD("Setup Modem state cmd_rx"); - } - else if (rad->channel_direction == cariboulite_channel_dir_tx) - { - // if its an LO frequency output from the mixer - no need for modem output - // LO applicable only to the channel with the mixer - if (rad->lo_output && channel == cariboulite_channel_6g) - { - // here we need to configure lo bypass on the mixer - rffc507x_output_lo(&rad->cariboulite_sys->mixer, 1); - } - // otherwise we need the modem - else - { - // make sure the mixer doesn't bypass the lo - rffc507x_output_lo(&rad->cariboulite_sys->mixer, 0); - - cariboulite_set_tx_bandwidth(radios, channel, - rad->cw_output?at86rf215_radio_tx_cut_off_80khz:rad->tx_bw); - - // CW output - constant I/Q values override - at86rf215_radio_set_tx_dac_input_iq(&rad->cariboulite_sys->modem, - GET_CH(channel), - rad->cw_output, 0x7E, - rad->cw_output, 0x3F); - - // transition to state TX - at86rf215_radio_set_state(&rad->cariboulite_sys->modem, - GET_CH(channel), - at86rf215_radio_state_cmd_tx); - - } - } - - return 0; + return cariboulite_radio_activate_channel(GET_RADIO_PTR(radios,channel), active); } //====================================================================== int cariboulite_set_cw_outputs(cariboulite_radios_st* radios, cariboulite_channel_en channel, bool lo_out, bool cw_out) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - - if (rad->lo_output && channel == cariboulite_channel_6g) - { - rad->lo_output = lo_out; - } - else - { - rad->lo_output = false; - } - rad->cw_output = cw_out; - - if (cw_out) - { - rad->channel_direction = cariboulite_channel_dir_tx; - } - else - { - rad->channel_direction = cariboulite_channel_dir_rx; - } - - return 0; + return cariboulite_radio_set_cw_outputs(GET_RADIO_PTR(radios,channel), + lo_out, cw_out); } //====================================================================== int cariboulite_get_cw_outputs(cariboulite_radios_st* radios, cariboulite_channel_en channel, bool *lo_out, bool *cw_out) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - if (lo_out) *lo_out = rad->lo_output; - if (cw_out) *cw_out = rad->cw_output; - - return 0; + return cariboulite_radio_get_cw_outputs(GET_RADIO_PTR(radios,channel), + lo_out, cw_out); } //================================================= int cariboulite_create_smi_stream(cariboulite_radios_st* radios, cariboulite_channel_en channel, cariboulite_channel_dir_en dir, - int buffer_length, void* context) { - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - - caribou_smi_channel_en ch = (channel == cariboulite_channel_s1g) ? - caribou_smi_channel_900 : caribou_smi_channel_2400; - caribou_smi_stream_type_en type = (dir == cariboulite_channel_dir_rx) ? - caribou_smi_stream_type_read : caribou_smi_stream_type_write; - - int stream_id = caribou_smi_setup_stream(&rad->cariboulite_sys->smi, - type, - ch, - caribou_smi_data_event, - context); - - // keep the stream ids - if (type == caribou_smi_stream_type_read) - { - rad->rx_stream_id = stream_id; - } - else if (type == caribou_smi_stream_type_write) - { - rad->tx_stream_id = stream_id; - } - return stream_id; + return cariboulite_radio_create_smi_stream(GET_RADIO_PTR(radios,channel), + dir, + context); } //================================================= @@ -937,15 +271,14 @@ int cariboulite_destroy_smi_stream(cariboulite_radios_st* radios, cariboulite_channel_en channel, cariboulite_channel_dir_en dir) { - // fetch the stream id - cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - - int stream_id = (dir == cariboulite_channel_dir_rx) ? rad->rx_stream_id : rad->tx_stream_id; - if (stream_id == -1) - { - ZF_LOGE("The specified channel (%d) doesn't have open stream of type %d", channel, dir); - return -1; - } - - caribou_smi_destroy_stream(&rad->cariboulite_sys->smi, stream_id); + return cariboulite_radio_destroy_smi_stream(GET_RADIO_PTR(radios,channel), dir); +} + +//================================================= +int cariboulite_run_pause_stream(cariboulite_radios_st* radios, + cariboulite_channel_en channel, + cariboulite_channel_dir_en dir, + bool run) +{ + return cariboulite_radio_run_pause_stream(GET_RADIO_PTR(radios,channel), dir, run); } diff --git a/software/libcariboulite/src/cariboulite_radios.h b/software/libcariboulite/src/cariboulite_radios.h index 42cd463..64ea675 100644 --- a/software/libcariboulite/src/cariboulite_radios.h +++ b/software/libcariboulite/src/cariboulite_radios.h @@ -6,93 +6,10 @@ extern "C" { #endif #include "cariboulite_config/cariboulite_config.h" +#include "cariboulite_radio.h" #include "at86rf215/at86rf215.h" -typedef enum -{ - cariboulite_channel_dir_rx = 0, - cariboulite_channel_dir_tx = 1, -} cariboulite_channel_dir_en; - -typedef enum -{ - cariboulite_channel_s1g = 0, - cariboulite_channel_6g = 1, -} cariboulite_channel_en; - -typedef struct -{ - cariboulite_channel_en type; - bool cw_out; - bool lo_out; - cariboulite_ext_ref_src_en ext_ref_src; - uint32_t ext_ref_freq_hz; - - double requested_freq; - double modem_actual_freq; - double mixer_actual_freq; - double actual_freq; - double actual_freq_error; - - bool modem_lock; - bool mixer_lock; -} cariboulite_freq_construction_st; - -typedef struct -{ - cariboulite_st* cariboulite_sys; - cariboulite_channel_dir_en channel_direction; - cariboulite_channel_en type; - bool active; - bool cw_output; - bool lo_output; - - // MODEM STATES - at86rf215_radio_state_cmd_en state; - at86rf215_radio_irq_st interrupts; - - bool rx_agc_on; - int rx_gain_value_db; - - at86rf215_radio_rx_bw_en rx_bw; - at86rf215_radio_f_cut_en rx_fcut; - at86rf215_radio_sample_rate_en rx_fs; - - int tx_power; - at86rf215_radio_tx_cut_off_en tx_bw; - at86rf215_radio_f_cut_en tx_fcut; - at86rf215_radio_sample_rate_en tx_fs; - - // at86rf215_radio_energy_detection_st rx_energy_detection; - float rx_energy_detection_value; - float rx_rssi; - - // FREQUENCY - bool modem_pll_locked; - bool lo_pll_locked; - double lo_frequency; - double if_frequency; - double actual_rf_frequency; - double requested_rf_frequency; - double rf_frequency_error; - //cariboulite_freq_construction_st freq; - - // SMI STREAMS - int rx_stream_id; - int tx_stream_id; - - // OTHERS - uint8_t random_value; - float rx_thermal_noise_floor; - - // CALIBRATION - int num_of_rx_cal_points; - int num_of_tx_cal_points; - float rx_power_gain_calibration[6001]; - float tx_power_gain_calibration[6001]; -} cariboulite_radio_state_st; - typedef struct { cariboulite_radio_state_st radio_sub1g; @@ -200,7 +117,6 @@ int cariboulite_get_cw_outputs(cariboulite_radios_st* radios, int cariboulite_create_smi_stream(cariboulite_radios_st* radios, cariboulite_channel_en channel, cariboulite_channel_dir_en dir, - int buffer_length, void* context); int cariboulite_destroy_smi_stream(cariboulite_radios_st* radios, diff --git a/software/libcariboulite/src/soapy_api/Cariboulite.cpp b/software/libcariboulite/src/soapy_api/Cariboulite.cpp index 07cc65b..3cc71ab 100644 --- a/software/libcariboulite/src/soapy_api/Cariboulite.cpp +++ b/software/libcariboulite/src/soapy_api/Cariboulite.cpp @@ -10,44 +10,40 @@ SoapyCaribouliteSession Cariboulite::sess; Cariboulite::Cariboulite(const SoapySDR::Kwargs &args) { int stream_id = 0; - - CARIBOULITE_CONFIG_DEFAULT(temp); - caribou_smi_stream_type_en types[] = {caribou_smi_stream_type_write, - caribou_smi_stream_type_write, - caribou_smi_stream_type_read, - caribou_smi_stream_type_read}; - caribou_smi_channel_en channels[] = {caribou_smi_channel_900, - caribou_smi_channel_2400, - caribou_smi_channel_900, - caribou_smi_channel_2400}; + SoapySDR_logf(SOAPY_SDR_INFO, "Initializing DeviceID: %s, Label: %s, ChannelType: %s", + args.at("device_id").c_str(), + args.at("label").c_str(), + args.at("channel").c_str()); - for (int i = 0; i < 4; i++) - { - int stream_id = CARIBOU_SMI_GET_STREAM_ID(types[i], channels[i]); - sample_queues[i] = new SampleQueue(getStreamMTU(NULL)*NUM_BYTES_PER_CPLX_ELEM, NUM_SAMPLEQUEUE_BUFS); - int dir = (types[i] == caribou_smi_stream_type_write)? SOAPY_SDR_TX : SOAPY_SDR_RX; - int ch = (channels[i] == caribou_smi_channel_900)? cariboulite_channel_s1g : cariboulite_channel_6g; - sample_queues[i]->AttachStreamId(stream_id, dir, ch); - } + // Initialize the stream Sample Queues + sample_queue_tx = new SampleQueue(getStreamMTU(NULL)*NUM_BYTES_PER_CPLX_ELEM, NUM_SAMPLEQUEUE_BUFS); + sample_queue_rx = new SampleQueue(getStreamMTU(NULL)*NUM_BYTES_PER_CPLX_ELEM, NUM_SAMPLEQUEUE_BUFS); - cariboulite_init_radios(&radios, &sess.cariboulite_sys); - - //SoapySDR_logf(SOAPY_SDR_INFO, "Cariboulite c'tor"); - - // TODO: Exception when error + if (!args.at("channel").compare ("HiF")) + { + sample_queue_tx->AttachStreamId(0, caribou_smi_stream_type_write, caribou_smi_channel_2400); + sample_queue_rx->AttachStreamId(1, caribou_smi_stream_type_read, caribou_smi_channel_2400); + cariboulite_radio_init(&radio, &sess.cariboulite_sys, cariboulite_channel_6g); + } + else if (!args.at("channel").compare ("S1G")) + { + sample_queue_tx->AttachStreamId(0, caribou_smi_stream_type_write, caribou_smi_channel_900); + sample_queue_rx->AttachStreamId(1, caribou_smi_stream_type_read, caribou_smi_channel_900); + cariboulite_radio_init(&radio, &sess.cariboulite_sys, cariboulite_channel_s1g); + } + else + { + throw std::string("Channel type is not specified correctly"); + } } //======================================================== Cariboulite::~Cariboulite() { - cariboulite_dispose_radios(&radios); - - for (int i = 0; i < 4; i++) - { - delete sample_queues[i]; - } - //SoapySDR_logf(SOAPY_SDR_INFO, "Cariboulite d'tor"); + cariboulite_radio_dispose(&radio); + delete sample_queue_tx; + delete sample_queue_rx; } /******************************************************************* @@ -81,8 +77,8 @@ std::vector Cariboulite::listAntennas( const int direction, const s { //printf("listAntennas dir: %d, channel: %ld\n", direction, channel); std::vector options; - if (channel == cariboulite_channel_s1g) options.push_back( "TX/RX Sub1GHz" ); - else if (channel == cariboulite_channel_6g) options.push_back( "TX/RX 6GHz" ); + if (radio.type == cariboulite_channel_s1g) options.push_back( "TX/RX Sub1GHz" ); + else if (radio.type == cariboulite_channel_6g) options.push_back( "TX/RX 6GHz" ); return(options); } @@ -91,8 +87,8 @@ std::vector Cariboulite::listAntennas( const int direction, const s std::string Cariboulite::getAntenna( const int direction, const size_t channel ) const { //printf("getAntenna dir: %d, channel: %ld\n", direction, channel); - if (channel == cariboulite_channel_s1g) return "TX/RX Sub1GHz"; - else if (channel == cariboulite_channel_6g) return "TX/RX 6GHz"; + if (radio.type == cariboulite_channel_s1g) return "TX/RX Sub1GHz"; + else if (radio.type == cariboulite_channel_6g) return "TX/RX 6GHz"; return ""; } @@ -126,17 +122,16 @@ std::vector Cariboulite::listGains(const int direction, const size_ void Cariboulite::setGain(const int direction, const size_t channel, const double value) { //printf("setGain dir: %d, channel: %ld, value: %.2f\n", direction, channel, value); - cariboulite_radio_state_st* rad = channel == cariboulite_channel_s1g? &radios.radio_sub1g : &radios.radio_6g; - bool cur_agc_mode = rad->rx_agc_on; + bool cur_agc_mode = radio.rx_agc_on; if (direction == SOAPY_SDR_RX) { - cariboulite_set_rx_gain_control(&radios, (cariboulite_channel_en)channel, cur_agc_mode, value); + cariboulite_radio_set_rx_gain_control(&radio, cur_agc_mode, value); } else if (direction == SOAPY_SDR_TX) { // base if -18dBm output so, given a gain of 0dB we should have -18 dBm - cariboulite_set_tx_power(&radios, (cariboulite_channel_en)channel, value - 18.0); + cariboulite_radio_set_tx_power(&radio, value - 18.0); } } @@ -154,12 +149,12 @@ double Cariboulite::getGain(const int direction, const size_t channel) const if (direction == SOAPY_SDR_RX) { - cariboulite_get_rx_gain_control((cariboulite_radios_st*)&radios, (cariboulite_channel_en)channel, NULL, &value); + cariboulite_radio_get_rx_gain_control((cariboulite_radio_state_st*)&radio, NULL, &value); } else if (direction == SOAPY_SDR_TX) { int temp = 0; - cariboulite_get_tx_power((cariboulite_radios_st*)&radios, (cariboulite_channel_en)channel, &temp); + cariboulite_radio_get_tx_power((cariboulite_radio_state_st*)&radio, &temp); value = temp + 18.0; } SoapySDR_logf(SOAPY_SDR_INFO, "getGain dir: %d, channel: %ld, value: %d", direction, channel, value); @@ -209,12 +204,11 @@ bool Cariboulite::hasGainMode(const int direction, const size_t channel) const void Cariboulite::setGainMode( const int direction, const size_t channel, const bool automatic ) { //printf("setGainMode dir: %d, channel: %ld, auto: %d\n", direction, channel, automatic); - cariboulite_radio_state_st* rad = channel == cariboulite_channel_s1g? &radios.radio_sub1g : &radios.radio_6g; - bool rx_gain = rad->rx_gain_value_db; + bool rx_gain = radio.rx_gain_value_db; if (direction == SOAPY_SDR_RX) { - cariboulite_set_rx_gain_control(&radios, (cariboulite_channel_en)channel, automatic, rx_gain); + cariboulite_radio_set_rx_gain_control(&radio, automatic, rx_gain); } } @@ -231,8 +225,7 @@ bool Cariboulite::getGainMode( const int direction, const size_t channel ) const if (direction == SOAPY_SDR_RX) { - cariboulite_get_rx_gain_control((cariboulite_radios_st*)&radios, (cariboulite_channel_en)channel, - &mode, NULL); + cariboulite_radio_get_rx_gain_control((cariboulite_radio_state_st*)&radio, &mode, NULL); SoapySDR_logf(SOAPY_SDR_INFO, "getGainMode dir: %d, channel: %ld, auto: %d", direction, channel, mode); return mode; } @@ -245,24 +238,17 @@ bool Cariboulite::getGainMode( const int direction, const size_t channel ) const ******************************************************************/ void Cariboulite::setSampleRate( const int direction, const size_t channel, const double rate ) { - cariboulite_radio_state_st* rad = channel == cariboulite_channel_s1g? &radios.radio_sub1g : &radios.radio_6g; - at86rf215_radio_f_cut_en rx_cuttof = rad->rx_fcut; - at86rf215_radio_f_cut_en tx_cuttof = rad->tx_fcut; + at86rf215_radio_f_cut_en rx_cuttof = radio.rx_fcut; + at86rf215_radio_f_cut_en tx_cuttof = radio.tx_fcut; //printf("setSampleRate dir: %d, channel: %ld, rate: %.2f\n", direction, channel, rate); if (direction == SOAPY_SDR_RX) { - cariboulite_set_rx_samp_cutoff(&radios, - (cariboulite_channel_en)channel, - at86rf215_radio_rx_sample_rate_4000khz, - rx_cuttof); + cariboulite_radio_set_rx_samp_cutoff(&radio, at86rf215_radio_rx_sample_rate_4000khz, rx_cuttof); } else if (direction == SOAPY_SDR_TX) { - cariboulite_set_tx_samp_cutoff(&radios, - (cariboulite_channel_en)channel, - at86rf215_radio_rx_sample_rate_4000khz, - tx_cuttof); + cariboulite_radio_set_tx_samp_cutoff(&radio, at86rf215_radio_rx_sample_rate_4000khz, tx_cuttof); } } @@ -393,14 +379,12 @@ void Cariboulite::setBandwidth( const int direction, const size_t channel, const if (direction == SOAPY_SDR_RX) { - cariboulite_set_rx_bandwidth(&radios,(cariboulite_channel_en)channel, convertRxBandwidth(setbw)); - if (channel == 0) sample_queues[2]->dig_filt = filt; - else if (channel == 1) sample_queues[3]->dig_filt = filt; + cariboulite_radio_set_rx_bandwidth(&radio, convertRxBandwidth(setbw)); + sample_queue_rx->dig_filt = filt; } else if (direction == SOAPY_SDR_TX) { - cariboulite_set_tx_bandwidth(&radios,(cariboulite_channel_en)channel, - convertTxBandwidth(setbw)); + cariboulite_radio_set_tx_bandwidth(&radio, convertTxBandwidth(setbw)); } } @@ -412,13 +396,13 @@ double Cariboulite::getBandwidth( const int direction, const size_t channel ) co if (direction == SOAPY_SDR_RX) { at86rf215_radio_rx_bw_en bw; - cariboulite_get_rx_bandwidth((cariboulite_radios_st*)&radios,(cariboulite_channel_en)channel, &bw); + cariboulite_radio_get_rx_bandwidth((cariboulite_radio_state_st*)&radio, &bw); return convertRxBandwidth(bw); } else if (direction == SOAPY_SDR_TX) { at86rf215_radio_tx_cut_off_en bw; - cariboulite_get_tx_bandwidth((cariboulite_radios_st*)&radios,(cariboulite_channel_en)channel, &bw); + cariboulite_radio_get_tx_bandwidth((cariboulite_radio_state_st*)&radio, &bw); return convertTxBandwidth(bw); } return 0.0; @@ -483,7 +467,7 @@ void Cariboulite::setFrequency( const int direction, const size_t channel, const return; } - err = cariboulite_set_frequency(&radios, (cariboulite_channel_en)channel, true, (double *)&frequency); + err = cariboulite_radio_set_frequency(&radio, true, (double *)&frequency); if (err == 0) SoapySDR_logf(SOAPY_SDR_INFO, "setFrequency dir: %d, channel: %ld, freq: %.2f", direction, channel, frequency); else SoapySDR_logf(SOAPY_SDR_ERROR, "setFrequency dir: %d, channel: %ld, freq: %.2f FAILED", direction, channel, frequency); } @@ -498,7 +482,7 @@ double Cariboulite::getFrequency( const int direction, const size_t channel, con return 0.0; } - cariboulite_get_frequency((cariboulite_radios_st*)&radios,(cariboulite_channel_en)channel, &freq, NULL, NULL); + cariboulite_radio_get_frequency((cariboulite_radio_state_st*)&radio, &freq, NULL, NULL); return freq; } @@ -530,14 +514,14 @@ SoapySDR::RangeList Cariboulite::getFrequencyRange( const int direction, const s throw std::runtime_error( "getFrequencyRange(" + name + ") unknown name" ); } - if (channel == cariboulite_channel_s1g) + if (radio.type == cariboulite_channel_s1g) { SoapySDR::RangeList list; list.push_back(SoapySDR::Range( 389.5e6, 510e6 )); list.push_back(SoapySDR::Range( 779e6, 1020e6 )); return list; } - else if (channel == cariboulite_channel_6g) + else if (radio.type == cariboulite_channel_6g) { return (SoapySDR::RangeList( 1, SoapySDR::Range( 1e6, 6000e6 ) ) ); } diff --git a/software/libcariboulite/src/soapy_api/Cariboulite.hpp b/software/libcariboulite/src/soapy_api/Cariboulite.hpp index ce41f05..d6962ca 100644 --- a/software/libcariboulite/src/soapy_api/Cariboulite.hpp +++ b/software/libcariboulite/src/soapy_api/Cariboulite.hpp @@ -21,6 +21,7 @@ #include "datatypes/circular_buffer.h" #include "cariboulite_setup.h" #include "cariboulite_radios.h" +#include "cariboulite_radio.h" enum Cariboulite_Format { @@ -175,8 +176,8 @@ public: long long &timeNs, const long timeoutUs = 100000); - int findSampleQueue(const int direction, const size_t channel); - int findSampleQueueById(int stream_id); + //int findSampleQueue(const int direction, const size_t channel); + //int findSampleQueueById(int stream_id); /******************************************************************* * Antenna API @@ -232,8 +233,9 @@ public: Type readSensor(const int direction, const size_t channel, const std::string &key) const; public: - cariboulite_radios_st radios; - SampleQueue* sample_queues[4]; + cariboulite_radio_state_st radio; + SampleQueue* sample_queue_tx; + SampleQueue* sample_queue_rx; // Static load time initializations static SoapyCaribouliteSession sess; diff --git a/software/libcariboulite/src/soapy_api/CaribouliteSession.cpp b/software/libcariboulite/src/soapy_api/CaribouliteSession.cpp index 97746ac..90f315f 100644 --- a/software/libcariboulite/src/soapy_api/CaribouliteSession.cpp +++ b/software/libcariboulite/src/soapy_api/CaribouliteSession.cpp @@ -38,7 +38,6 @@ void soapy_sighandler( struct cariboulite_st_t *sys, SoapyCaribouliteSession::SoapyCaribouliteSession(void) { std::lock_guard lock(sessionMutex); - //printf("SoapyCaribouliteSession, sessionCount: %ld\n", sessionCount); SoapySDR_logf(SOAPY_SDR_INFO, "SoapyCaribouliteSession, sessionCount: %ld", sessionCount); if (sessionCount == 0) { @@ -63,7 +62,6 @@ SoapyCaribouliteSession::SoapyCaribouliteSession(void) SoapyCaribouliteSession::~SoapyCaribouliteSession(void) { std::lock_guard lock(sessionMutex); - //printf("~SoapyCaribouliteSession, sessionCount: %ld\n", sessionCount); //SoapySDR_logf(SOAPY_SDR_INFO, "~SoapyCaribouliteSession, sessionCount: %ld", sessionCount); sessionCount--; if (sessionCount == 0) diff --git a/software/libcariboulite/src/soapy_api/CaribouliteStream.cpp b/software/libcariboulite/src/soapy_api/CaribouliteStream.cpp index 9479ad2..1568318 100644 --- a/software/libcariboulite/src/soapy_api/CaribouliteStream.cpp +++ b/software/libcariboulite/src/soapy_api/CaribouliteStream.cpp @@ -106,29 +106,6 @@ SoapySDR::ArgInfoList Cariboulite::getStreamArgsInfo(const int direction, const return streamArgs; } -//======================================================== -int Cariboulite::findSampleQueue(const int direction, const size_t channel) -{ - for (uint32_t i = 0; i < 4; i++) - { - if (sample_queues[i]->stream_dir == direction && - sample_queues[i]->stream_channel == (int)channel) - return i; - } - return -1; -} - -//======================================================== -int Cariboulite::findSampleQueueById(int stream_id) -{ - for (uint32_t i = 0; i < 4; i++) - { - if (sample_queues[i]->stream_id == stream_id) - return i; - } - return -1; -} - //======================================================== /*! * Initialize a stream given a list of channels and stream arguments. @@ -190,6 +167,7 @@ SoapySDR::Stream *Cariboulite::setupStream(const int direction, channels.size()?channels[0]:0); std::vector channels_internal = channels; + // default channel - sub1GHz if ( channels_internal.size() == 0 ) { @@ -258,7 +236,6 @@ SoapySDR::Stream *Cariboulite::setupStream(const int direction, */ void Cariboulite::closeStream(SoapySDR::Stream *stream) { - //SoapySDR_logf(SOAPY_SDR_INFO, "closeStream"); if (stream == NULL) return; int stream_id = (intptr_t)stream; @@ -277,7 +254,6 @@ void Cariboulite::closeStream(SoapySDR::Stream *stream) */ size_t Cariboulite::getStreamMTU(SoapySDR::Stream *stream) const { - //printf("getStreamMTU\n"); return 1024 * 1024 / 2 / 4; } diff --git a/software/libcariboulite/src/soapy_api/SoapyCariboulite.cpp b/software/libcariboulite/src/soapy_api/SoapyCariboulite.cpp index e55bcc6..6f24997 100644 --- a/software/libcariboulite/src/soapy_api/SoapyCariboulite.cpp +++ b/software/libcariboulite/src/soapy_api/SoapyCariboulite.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "Cariboulite.hpp" @@ -18,45 +19,41 @@ SoapySDR::KwargsList findCariboulite(const SoapySDR::Kwargs &args) SoapySDR_logf(SOAPY_SDR_DEBUG, "CaribouLite Lib v%d.%d rev %d", lib_version.major_version, lib_version.minor_version, lib_version.revision); - // When multiboard will be supported, change this to enumertion with count >1 - if ( ( count = cariboulite_config_detect_board(&board_info) ) <= 0) { SoapySDR_logf(SOAPY_SDR_DEBUG, "No Cariboulite boards found"); return results; } + // to support for two channels, each CaribouLite detected will be identified as + // two boards for the SoapyAPI int devId = 0; for (int i = 0; i < count; i++) { - std::stringstream serialstr; - - serialstr.str(""); - serialstr << std::hex << board_info.numeric_serial_number; - - SoapySDR_logf(SOAPY_SDR_DEBUG, "Serial %s", serialstr.str().c_str()); + for (int ch = 0; ch < 2; ch ++) + { + std::stringstream serialstr; + std::stringstream label; + SoapySDR::Kwargs soapyInfo; + serialstr.str(""); + serialstr << std::hex << ((board_info.numeric_serial_number << 1) | ch); + label.str(""); + label << (ch?std::string("CaribouLite HiF"):std::string("CaribouLite S1G")) << "[" << serialstr.str() << "]"; - SoapySDR::Kwargs soapyInfo; + SoapySDR_logf(SOAPY_SDR_DEBUG, "Serial %s", serialstr.str().c_str()); - soapyInfo["device_id"] = std::to_string(devId); - soapyInfo["label"] = "Cariboulite [" + serialstr.str() + "]"; - soapyInfo["serial"] = serialstr.str(); - soapyInfo["name"] = board_info.product_name; - soapyInfo["vendor"] = board_info.product_vendor; - soapyInfo["uuid"] = board_info.product_uuid; - soapyInfo["version"] = board_info.product_version; - devId++; + soapyInfo["device_id"] = std::to_string(devId); + soapyInfo["label"] = label.str(); + soapyInfo["serial"] = serialstr.str(); + soapyInfo["name"] = board_info.product_name; + soapyInfo["vendor"] = board_info.product_vendor; + soapyInfo["uuid"] = board_info.product_uuid; + soapyInfo["version"] = board_info.product_version; + soapyInfo["channel"] = ch?"HiF":"S1G"; + devId++; - if (args.count("device_id") != 0) - { - if (args.at("device_id") != soapyInfo.at("device_id")) - { - continue; - } - SoapySDR_logf(SOAPY_SDR_DEBUG, "Found device by device_id %s", soapyInfo.at("device_id").c_str()); - } - - results.push_back(soapyInfo); + results.push_back(soapyInfo); + } } return results;