diff --git a/examples/python/test_soapy.py b/examples/python/test_soapy.py index b09e555..e7420cd 100644 --- a/examples/python/test_soapy.py +++ b/examples/python/test_soapy.py @@ -1,49 +1,57 @@ +from PySimpleGUI.PySimpleGUI import Canvas, Column import numpy as np import matplotlib.pyplot as plt +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import SoapySDR -from SoapySDR import SOAPY_SDR_RX, SOAPY_SDR_CS16 +from SoapySDR import SOAPY_SDR_RX, SOAPY_SDR_TX, SOAPY_SDR_CS16 +from PySimpleGUI import Window, WIN_CLOSED, Slider, Button, theme, Text, Radio, Image +from numpy.lib.arraypad import pad -# Enumerate the Soapy devices -res = SoapySDR.Device.enumerate() -for result in res: - print(result) +def draw_figure_with_toolbar(canvas, fig, canvas_toolbar): + if canvas.children: + for child in canvas.winfo_children(): + child.destroy() + if canvas_toolbar.children: + for child in canvas_toolbar.winfo_children(): + child.destroy() + + figure_canvas_agg = FigureCanvasTkAgg(fig, master=canvas) + figure_canvas_agg.draw() -# Data and Source Configuration -rx_chan = 1 # RX1 = 0, RX2 = 1 -N = 16384 # Number of complex samples per transfer -fs = 4e6 # Radio sample Rate -freq = 868e6 # LO tuning frequency in Hz -use_agc = True # Use or don't use the AGC -timeout_us = int(5e6) + toolbar = Toolbar(figure_canvas_agg, canvas_toolbar) + toolbar.update() + figure_canvas_agg.get_tk_widget().pack(side='right', fill='both', expand=1) -# Initialize CaribouLite -sdr = SoapySDR.Device(dict(driver="Cariboulite")) # Create Cariboulite -sdr.setSampleRate(SOAPY_SDR_RX, rx_chan, fs) # Set sample rate -sdr.setGainMode(SOAPY_SDR_RX, rx_chan, use_agc) # Set the gain mode -sdr.setFrequency(SOAPY_SDR_RX, rx_chan, freq) # Tune the LO -sdr.setBandwidth(SOAPY_SDR_RX, rx_chan, 2.5e6) -# Create data buffer and start streaming samples to it -rx_buff = np.empty(2 * N, np.int16) # Create memory buffer for data stream -rx_stream = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, [ - rx_chan]) # Setup data stream -sdr.activateStream(rx_stream) # this turns the radio on +class Toolbar(NavigationToolbar2Tk): + def __init__(self, *args, **kwargs): + super(Toolbar, self).__init__(*args,**kwargs) -# Save the file names for plotting later. Remove if not plotting. -file_names = [] -file_ctr = 0 -nfiles = 1 +def create_window(): + #theme("Default") + layout = [ + [Column( + layout=[ + [Text('Receiver LO')], + [Text('Transmitter Fc')] + ] + )] + [Canvas(key='controls_cv')], + [Column( + layout=[ + [Canvas(key='fig_cv', size=(400*2, 400))] + ], + background_color='#DAE0E6', + pad=(0,0) + )], + [Button("Correct", size=(10,1)), Button("Exit", size=(10,1))], + ] + window = Window("CaribouLite PlayGround", layout, location=(800,400)) + return window -while file_ctr < nfiles: - print(file_ctr, '. READING ', N, ' samples from CaribouLite') - # Read the samples from the data buffer - sr = sdr.readStream(rx_stream, [rx_buff], N, timeoutUs=timeout_us) - - # Make sure that the proper number of samples was read - rc = sr.ret - assert rc == N, 'Error Reading Samples from Device (error code = %d)!' % rc +def estimate_correct(rx_buff): s_real = rx_buff[::2].astype(np.float32) s_imag = rx_buff[1::2].astype(np.float32) @@ -59,22 +67,98 @@ while file_ctr < nfiles: sin_phi_est = (2/alpha_est)*np.mean(I*Q) cos_phi_est = np.sqrt(1-sin_phi_est**2) + print('phase error: ', np.arccos(cos_phi_est)*360/3.1415, ' degrees') + print('amplitude error: ', 20*np.log10(alpha_est), ' dB' ) + I_new_p = (1/alpha_est) * I Q_new_p = (-sin_phi_est/alpha_est) * I + Q y = (I_new_p + 1j*Q_new_p) / cos_phi_est - print('phase error: ', np.arccos(cos_phi_est)*360/3.1415, ' degrees') - print('amplitude error: ', 20*np.log10(alpha_est), ' dB' ) + return (s_real, s_imag, alpha_est, sin_phi_est, cos_phi_est, I_new_p, Q_new_p) - # plt.plot(s_real, s_imag, 'k', label='I') - plt.scatter(I_new_p, Q_new_p) - plt.ylabel('I / Q Balance') - plt.show() +def main(): + # Data and Source Configuration + tx_chan = 0 # S1G = 0, 6G = 1 + rx_chan = 1 # S1G = 0, 6G = 1 + N = 16384 # Nu5mber of complex samples per transfer + fs = 4e6 # Radio sample Rate + freq = 868e6 # LO tuning frequency in Hz + use_agc = True # Use or don't use the AGC + gain = 60 + n_reads = 0 - file_ctr += 1 - if file_ctr > nfiles: - break + rx_buff = np.empty(2 * N, np.int16) # Create memory buffer for data stream + timeout_us = int(5e6) -# Stop streaming and close the connection to the radio -sdr.deactivateStream(rx_stream) -sdr.closeStream(rx_stream) + # Initialize CaribouLite + sdr = SoapySDR.Device(dict(driver="Cariboulite")) # Create Cariboulite + + # The wide channel parameters + sdr.setSampleRate(SOAPY_SDR_RX, rx_chan, fs) # Set sample rate + sdr.setGainMode(SOAPY_SDR_RX, rx_chan, use_agc) # Set the gain mode + sdr.setGain(SOAPY_SDR_RX, rx_chan, gain) # Set the gain + sdr.setFrequency(SOAPY_SDR_RX, rx_chan, freq) # Tune the LO + sdr.setBandwidth(SOAPY_SDR_RX, rx_chan, 2.5e6) + + # The S1G channel parameter + sdr.setFrequency(SOAPY_SDR_TX, tx_chan, 868.5e6) + sdr.setGain(SOAPY_SDR_TX, tx_chan, 50) + cw_tx_stream = sdr.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CS16, [tx_chan], dict(CW="1")) + sdr.activateStream(cw_tx_stream) + + # Create data buffer and start streaming samples to it + rx_stream = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, + [rx_chan]) # Setup data stream + sdr.activateStream(rx_stream) # this turns the radio on + + # create the window + window = create_window() + + while True: + event, values = window.read(timeout = 20) + + if (event == "Exit" or event == WIN_CLOSED): + break; + + if (event == "Correct"): + n_reads += 1 + sr = sdr.readStream(rx_stream, [rx_buff], N, timeoutUs=timeout_us) + + # Make sure that the proper number of samples was read + rc = sr.ret + if (rc != N): + print("Error Reading Samples from Device (error code = %d)!" % rc) + break; + + I,Q, alpha_est, sin_phi_est, cos_phi_est, I_new, Q_new = estimate_correct(rx_buff) + + plt.figure(1).clf() + fig = plt.gcf() + DPI = fig.get_dpi() + fig.set_size_inches(404*2/float(DPI), 404/float(DPI)) + plt.subplot(121) + plt.scatter(I, Q) + plt.title('I/Q original') + plt.subplot(122) + plt.scatter(I_new, Q_new) + plt.title('I/Q corrected') + plt.grid() + draw_figure_with_toolbar(window['fig_cv'].TKCanvas, fig, window['controls_cv'].TKCanvas) + + + # Stop streaming and close the connection to the radio + window.close() + sdr.deactivateStream(rx_stream) + sdr.deactivateStream(cw_tx_stream) + sdr.closeStream(rx_stream) + + + +########################################################### +## Global Area + +# Enumerate the Soapy devices +#res = SoapySDR.Device.enumerate() +#for result in res: +# print(result) +main() diff --git a/software/libcariboulite/src/cariboulite_config/cariboulite_config_default.h b/software/libcariboulite/src/cariboulite_config/cariboulite_config_default.h index 68d4aad..d1439f0 100644 --- a/software/libcariboulite/src/cariboulite_config/cariboulite_config_default.h +++ b/software/libcariboulite/src/cariboulite_config/cariboulite_config_default.h @@ -80,6 +80,7 @@ extern "C" { { \ .cs_pin = CARIBOULITE_MIXER_SS, \ .reset_pin = CARIBOULITE_MIXER_RESET, \ + .ref_freq_hz = 32e6, \ .initialized = 0, \ }, \ .reset_fpga_on_startup = 1, \ diff --git a/software/libcariboulite/src/cariboulite_radios.c b/software/libcariboulite/src/cariboulite_radios.c index 85422fb..0c236c2 100644 --- a/software/libcariboulite/src/cariboulite_radios.c +++ b/software/libcariboulite/src/cariboulite_radios.c @@ -114,7 +114,7 @@ int cariboulite_dispose_radios(cariboulite_radios_st* radios) caribou_smi_destroy_stream(&radios->radio_6g.cariboulite_sys->smi, radios->radio_sub1g.tx_stream_id); radios->radio_6g.tx_stream_id = -1; } - sleep(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); @@ -774,7 +774,7 @@ int cariboulite_activate_channel(cariboulite_radios_st* radios, { cariboulite_radio_state_st* rad = GET_RADIO_PTR(radios,channel); - ZF_LOGD("Activating channel %d", 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) { @@ -855,6 +855,15 @@ int cariboulite_set_cw_outputs(cariboulite_radios_st* radios, } 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; } diff --git a/software/libcariboulite/src/cariboulite_setup.c b/software/libcariboulite/src/cariboulite_setup.c index 0940045..fd88d35 100644 --- a/software/libcariboulite/src/cariboulite_setup.c +++ b/software/libcariboulite/src/cariboulite_setup.c @@ -160,8 +160,8 @@ int cariboulite_init_submodules (cariboulite_st* sys) // Configure modem //------------------------------------------------------ ZF_LOGD("Configuring modem initial state"); - at86rf215_set_clock_output(&sys->modem, at86rf215_drive_current_8ma, at86rf215_clock_out_freq_32mhz); - at86rf215_setup_rf_irq(&sys->modem, 0, 1, at86rf215_drive_current_4ma); + at86rf215_set_clock_output(&sys->modem, at86rf215_drive_current_2ma, at86rf215_clock_out_freq_32mhz); + at86rf215_setup_rf_irq(&sys->modem, 0, 1, at86rf215_drive_current_2ma); at86rf215_radio_set_state(&sys->modem, at86rf215_rf_channel_900mhz, at86rf215_radio_state_cmd_trx_off); at86rf215_radio_set_state(&sys->modem, at86rf215_rf_channel_2400mhz, at86rf215_radio_state_cmd_trx_off); @@ -211,6 +211,7 @@ int cariboulite_init_submodules (cariboulite_st* sys) // Configure mixer //------------------------------------------------------ + rffc507x_setup_reference_freq(&sys->mixer, 32e6); rffc507x_calibrate(&sys->mixer); ZF_LOGI("Cariboulite submodules successfully initialized"); @@ -295,7 +296,7 @@ int cariboulite_release_submodules(cariboulite_st* sys) //------------------------------------------------------ ZF_LOGD("CLOSE SMI"); caribou_smi_close(&sys->smi); - sleep(1); + usleep(10000); // AT86RF215 //------------------------------------------------------ diff --git a/software/libcariboulite/src/io_utils/io_utils.c b/software/libcariboulite/src/io_utils/io_utils.c index 398e04b..c6855ce 100644 --- a/software/libcariboulite/src/io_utils/io_utils.c +++ b/software/libcariboulite/src/io_utils/io_utils.c @@ -24,6 +24,7 @@ static char *io_utils_gpio_mode_strs[] = {"IN","OUT","ALT5","ALT4","ALT0","ALT1" int io_utils_setup(pigpioSigHandler sigHandler) { ZF_LOGI("initializing pigpio"); + gpioCfgInterfaces(PI_DISABLE_FIFO_IF|PI_DISABLE_SOCK_IF|PI_LOCALHOST_SOCK_IF); int status = gpioInitialise(); if (status < 0) { diff --git a/software/libcariboulite/src/rffc507x/rffc507x.c b/software/libcariboulite/src/rffc507x/rffc507x.c index 74e9b69..4940e19 100644 --- a/software/libcariboulite/src/rffc507x/rffc507x.c +++ b/software/libcariboulite/src/rffc507x/rffc507x.c @@ -43,8 +43,6 @@ #define LO_MAX 5400 #define LO_MAX_HZ (LO_MAX*1e6) -#define REF_FREQ 32 -#define REF_FREQ_HZ (REF_FREQ*1e6) #define FREQ_ONE_MHZ (1000*1000) //=========================================================================== @@ -151,8 +149,8 @@ int rffc507x_init( rffc507x_st* dev, set_RFFC507X_P2CTV(dev, 12); set_RFFC507X_P1CTV(dev, 12); set_RFFC507X_RGBYP(dev, 1); - set_RFFC507X_P2MIXIDD(dev, 6); - set_RFFC507X_P1MIXIDD(dev, 6); + set_RFFC507X_P2MIXIDD(dev, 5); + set_RFFC507X_P1MIXIDD(dev, 5); // Others set_RFFC507X_LDEN(dev, 1); @@ -253,9 +251,10 @@ void rffc507x_enable(rffc507x_st* dev) } //=========================================================================== -void rffc507x_calculate_freq_params(uint8_t lodiv, double fvco, uint8_t fbkdiv, uint16_t *n, uint16_t *p1nmsb, uint8_t *p1nlsb, double* act_freq_hz) +void rffc507x_calculate_freq_params(double ref_freq_hz, uint8_t lodiv, double fvco, uint8_t fbkdiv, + uint16_t *n, uint16_t *p1nmsb, uint8_t *p1nlsb, double* act_freq_hz) { - double n_div = fvco / fbkdiv / REF_FREQ_HZ; + double n_div = fvco / fbkdiv / ref_freq_hz; *n = (uint16_t)(n_div); double temp_p1nmsb = ( (double)(1<<16) ) * ( n_div - (double)(*n) ); @@ -266,7 +265,18 @@ void rffc507x_calculate_freq_params(uint8_t lodiv, double fvco, uint8_t fbkdiv, uint32_t n_div24_bit = (uint32_t)(round(n_div * (1<<24))) & 0xFFFFFFFF; //uint32_t n_div24_bit = (uint32_t)((n_div * (1<<24))) & 0xFFFFFFFF; - if (act_freq_hz) *act_freq_hz = (REF_FREQ_HZ * n_div24_bit * fbkdiv) / ((double)(lodiv) * (double)(1<<24)); + if (act_freq_hz) *act_freq_hz = (ref_freq_hz * n_div24_bit * fbkdiv) / ((double)(lodiv) * (double)(1<<24)); +} + +//=========================================================================== +int rffc507x_setup_reference_freq(rffc507x_st* dev, double ref_freq_hz) +{ + if (ref_freq_hz < 10e6 || ref_freq_hz > 104e6) + { + return -1; + } + dev->ref_freq_hz = ref_freq_hz; + return 0; } //=========================================================================== @@ -298,7 +308,7 @@ double rffc507x_set_frequency(rffc507x_st* dev, double lo_hz) set_RFFC507X_PLLCPL(dev, 2); } - rffc507x_calculate_freq_params(lodiv, fvco, fbkdiv, &n, &p1nmsb, &p1nlsb, &tune_freq_hz); + rffc507x_calculate_freq_params(dev->ref_freq_hz, lodiv, fvco, fbkdiv, &n, &p1nmsb, &p1nlsb, &tune_freq_hz); //ZF_LOGD("----------------------------------------------------------"); //ZF_LOGD("LO_HZ=%.2f n_lo=%d lodiv=%d", lo_hz, n_lo, lodiv); @@ -323,7 +333,7 @@ double rffc507x_set_frequency(rffc507x_st* dev, double lo_hz) // After the device is enabled, the divider values can be reprogrammed with the prescaler divider ratio of 2 // and the new n, nummsb, and numlsb values. Taking the previous example of an LO of 314.159265MHz: fbkdiv = 2; - rffc507x_calculate_freq_params(lodiv, fvco, fbkdiv, &n, &p1nmsb, &p1nlsb, &tune_freq_hz); + rffc507x_calculate_freq_params(dev->ref_freq_hz, lodiv, fvco, fbkdiv, &n, &p1nmsb, &p1nlsb, &tune_freq_hz); //ZF_LOGD("LO_HZ=%.2f n_lo=%d lodiv=%d", lo_hz, n_lo, lodiv); //ZF_LOGD("fvco=%.2f fbkdiv=%d n=%d", fvco, fbkdiv, n); diff --git a/software/libcariboulite/src/rffc507x/rffc507x.h b/software/libcariboulite/src/rffc507x/rffc507x.h index d474574..f213d7a 100644 --- a/software/libcariboulite/src/rffc507x/rffc507x.h +++ b/software/libcariboulite/src/rffc507x/rffc507x.h @@ -61,6 +61,7 @@ typedef struct { int cs_pin; int reset_pin; + double ref_freq_hz; io_utils_spi_st* io_spi; int io_spi_handle; @@ -104,6 +105,7 @@ void rffc507x_print_stat(rffc507x_device_status_st* stat); void rffc507x_calibrate(rffc507x_st* dev); void rffc507x_relock(rffc507x_st* dev); void rffc507x_output_lo(rffc507x_st* dev, int state); +int rffc507x_setup_reference_freq(rffc507x_st* dev, double ref_freq_hz); #ifdef __cplusplus } diff --git a/software/libcariboulite/src/rffc507x/test_rffc507x.c b/software/libcariboulite/src/rffc507x/test_rffc507x.c index e0ae0f6..1811223 100644 --- a/software/libcariboulite/src/rffc507x/test_rffc507x.c +++ b/software/libcariboulite/src/rffc507x/test_rffc507x.c @@ -23,6 +23,7 @@ rffc507x_st dev = { .cs_pin = CARIBOULITE_MXR_SS, .reset_pin = CARIBOULITE_MXR_RESET, + .ref_freq_hz = 32e6, }; int main () diff --git a/software/libcariboulite/src/soapy_api/Cariboulite.hpp b/software/libcariboulite/src/soapy_api/Cariboulite.hpp index 4e77d48..6400b41 100644 --- a/software/libcariboulite/src/soapy_api/Cariboulite.hpp +++ b/software/libcariboulite/src/soapy_api/Cariboulite.hpp @@ -109,6 +109,7 @@ public: int stream_id; int stream_dir; int stream_channel; + int is_cw; Cariboulite_Format chosen_format; private: tsqueue_st queue; diff --git a/software/libcariboulite/src/soapy_api/CaribouliteSampleQueue.cpp b/software/libcariboulite/src/soapy_api/CaribouliteSampleQueue.cpp index fc66059..9cfdfc4 100644 --- a/software/libcariboulite/src/soapy_api/CaribouliteSampleQueue.cpp +++ b/software/libcariboulite/src/soapy_api/CaribouliteSampleQueue.cpp @@ -40,7 +40,7 @@ SampleQueue::SampleQueue(int mtu_bytes, int num_buffers) // a buffer for conversion betwen native and emulated formats // the maximal size is the 2*(mtu_size in bytes) interm_native_buffer = new sample_complex_int16[2*mtu_size_bytes]; - + is_cw = 0; } //================================================================= diff --git a/software/libcariboulite/src/soapy_api/CaribouliteStream.cpp b/software/libcariboulite/src/soapy_api/CaribouliteStream.cpp index 435ac21..bf016c9 100644 --- a/software/libcariboulite/src/soapy_api/CaribouliteStream.cpp +++ b/software/libcariboulite/src/soapy_api/CaribouliteStream.cpp @@ -184,12 +184,11 @@ SoapySDR::Stream *Cariboulite::setupStream(const int direction, const std::vector &channels, const SoapySDR::Kwargs &args) { - SoapySDR_logf(SOAPY_SDR_INFO, "setupStream: dir: %d, format: %s, channels: ", direction, format.c_str()); - for (int i = 0; i < (int)channels.size(); i++) - { - SoapySDR_logf(SOAPY_SDR_INFO, "setupStream: %d. %ld", i, channels[i]); - } - + int cw = (args.count("CW") != 0) ? std::atoi(args.at("CW").c_str()) : 0; + SoapySDR_logf(SOAPY_SDR_INFO, "setupStream: dir= %s, format= %s, is_cw= %d, ch= %d", + direction == SOAPY_SDR_TX?"TX":"RX", format.c_str(), cw, + channels.size()?channels[0]:0); + std::vector channels_internal = channels; // default channel - sub1GHz if ( channels_internal.size() == 0 ) @@ -204,6 +203,7 @@ SoapySDR::Stream *Cariboulite::setupStream(const int direction, caribou_smi_stream_type_en type = (direction == SOAPY_SDR_RX) ? caribou_smi_stream_type_read : caribou_smi_stream_type_write; caribou_smi_channel_en channel = (ch == cariboulite_channel_s1g) ? caribou_smi_channel_900 : caribou_smi_channel_2400; int stream_id = CARIBOU_SMI_GET_STREAM_ID(type, channel); + sample_queues[stream_id]->is_cw = cw; // Setup the SampleQueue's format if (format == SOAPY_SDR_CS16) @@ -228,18 +228,26 @@ SoapySDR::Stream *Cariboulite::setupStream(const int direction, throw std::runtime_error( "setupStream invalid format " + format ); } - // create the stream - stream_id = caribou_smi_setup_stream(&sess.cariboulite_sys.smi, - type, channel, - GET_MTU_MS_BYTES(BUFFER_SIZE_MS), 1, - caribou_stream_data_event, - this); - if (stream_id < 0) + // create the stream (only for non CW streams) + if (sample_queues[stream_id]->is_cw) { - throw std::runtime_error( "setupStream caribou_smi_setup_stream failed" ); + cariboulite_set_cw_outputs(&radios, (cariboulite_channel_en)ch, false, true); + } + else + { + cariboulite_set_cw_outputs(&radios, (cariboulite_channel_en)ch, false, false); + stream_id = caribou_smi_setup_stream(&sess.cariboulite_sys.smi, + type, channel, + GET_MTU_MS_BYTES(BUFFER_SIZE_MS), 1, + caribou_stream_data_event, + this); + if (stream_id < 0) + { + throw std::runtime_error( "setupStream caribou_smi_setup_stream failed" ); + } } - SoapySDR_logf(SOAPY_SDR_INFO, "finished setup stream, stream_id = %d", stream_id); + SoapySDR_logf(SOAPY_SDR_INFO, "finished setup stream, stream_id = %d, CW=%d", stream_id, cw); return (SoapySDR::Stream *)((void*)stream_id); } @@ -305,7 +313,10 @@ int Cariboulite::activateStream(SoapySDR::Stream *stream, (cariboulite_channel_en)sample_queues[stream_id]->stream_channel, true); - caribou_smi_run_pause_stream (&sess.cariboulite_sys.smi, (intptr_t)stream, 1); + if ((cariboulite_channel_en)sample_queues[stream_id]->is_cw == 0) + { + caribou_smi_run_pause_stream (&sess.cariboulite_sys.smi, (intptr_t)stream, 1); + } return 0; } @@ -329,8 +340,11 @@ int Cariboulite::deactivateStream(SoapySDR::Stream *stream, const int flags, con SoapySDR_logf(SOAPY_SDR_INFO, "deactivateStream"); int stream_id = (intptr_t)stream; - caribou_smi_run_pause_stream (&sess.cariboulite_sys.smi, (intptr_t)stream, 0); - sleep(1); + if ((cariboulite_channel_en)sample_queues[stream_id]->is_cw == 0) + { + caribou_smi_run_pause_stream (&sess.cariboulite_sys.smi, (intptr_t)stream, 0); + sleep(1); + } cariboulite_activate_channel(&radios, (cariboulite_channel_en)sample_queues[stream_id]->stream_channel,