use crate::{
coarse_channel,
ffi::{
ffi_create_c_array, ffi_free_c_array, set_c_string, MWALIB_FAILURE,
MWALIB_NO_DATA_FOR_TIMESTEP_COARSECHAN, MWALIB_SUCCESS,
},
timestep, CorrelatorContext, GpuboxError, MWAVersion,
};
use libc::size_t;
use std::{
ffi::{c_char, c_double, c_float, CStr},
slice,
};
#[repr(C)]
pub struct CorrelatorMetadata {
pub common_start_unix_time_ms: u64,
pub common_end_unix_time_ms: u64,
pub common_start_gps_time_ms: u64,
pub common_end_gps_time_ms: u64,
pub common_duration_ms: u64,
pub common_good_start_unix_time_ms: u64,
pub common_good_end_unix_time_ms: u64,
pub common_good_start_gps_time_ms: u64,
pub common_good_end_gps_time_ms: u64,
pub common_good_duration_ms: u64,
pub timesteps: *mut timestep::ffi::TimeStep,
pub coarse_chans: *mut coarse_channel::ffi::CoarseChannel,
pub common_timestep_indices: *mut usize,
pub common_coarse_chan_indices: *mut usize,
pub common_good_timestep_indices: *mut usize,
pub common_good_coarse_chan_indices: *mut usize,
pub provided_timestep_indices: *mut usize,
pub provided_coarse_chan_indices: *mut usize,
pub num_timesteps: usize,
pub num_coarse_chans: usize,
pub num_common_timesteps: usize,
pub num_common_coarse_chans: usize,
pub num_common_good_timesteps: usize,
pub num_common_good_coarse_chans: usize,
pub num_provided_timesteps: usize,
pub num_provided_coarse_chans: usize,
pub num_timestep_coarse_chan_bytes: usize,
pub num_timestep_coarse_chan_floats: usize,
pub num_timestep_coarse_chan_weight_floats: usize,
pub num_gpubox_files: usize,
pub common_bandwidth_hz: u32,
pub common_good_bandwidth_hz: u32,
pub bscale: f32,
pub mwa_version: MWAVersion,
}
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_metadata_get(
correlator_context_ptr: *mut CorrelatorContext,
out_correlator_metadata_ptr: *mut *mut CorrelatorMetadata,
error_message: *mut c_char,
error_message_length: size_t,
) -> i32 {
if correlator_context_ptr.is_null() {
set_c_string(
"mwalib_correlator_metadata_get() ERROR: Warning: null pointer for correlator_context_ptr passed in",
error_message,
error_message_length,
);
if !out_correlator_metadata_ptr.is_null() {
*out_correlator_metadata_ptr = std::ptr::null_mut();
}
return MWALIB_FAILURE;
}
let context = &*correlator_context_ptr;
let (coarse_channels_ptr, coarse_channels_len) =
coarse_channel::ffi::CoarseChannel::populate_array(&context.coarse_chans);
let (timesteps_ptr, timesteps_len) =
timestep::ffi::TimeStep::populate_array(&context.timesteps);
let out_metadata = {
let CorrelatorContext {
metafits_context: _, mwa_version,
num_timesteps: _,
timesteps: _, num_coarse_chans: _,
coarse_chans: _, common_timestep_indices: _,
num_common_timesteps: _,
common_coarse_chan_indices: _,
num_common_coarse_chans: _,
common_start_unix_time_ms,
common_end_unix_time_ms,
common_start_gps_time_ms,
common_end_gps_time_ms,
common_duration_ms,
common_bandwidth_hz,
common_good_timestep_indices: _,
num_common_good_timesteps: _,
common_good_coarse_chan_indices: _,
num_common_good_coarse_chans: _,
common_good_start_unix_time_ms,
common_good_end_unix_time_ms,
common_good_start_gps_time_ms,
common_good_end_gps_time_ms,
common_good_duration_ms,
common_good_bandwidth_hz,
provided_timestep_indices: _,
num_provided_timesteps: _,
provided_coarse_chan_indices: _,
num_provided_coarse_chans: _,
num_timestep_coarse_chan_bytes,
num_timestep_coarse_chan_floats,
num_timestep_coarse_chan_weight_floats,
num_gpubox_files,
gpubox_batches: _, gpubox_time_map: _, legacy_conversion_table: _, bscale,
} = context;
let (common_timestep_indices_ptr, common_timestep_indices_len) =
ffi_create_c_array(context.common_timestep_indices.clone());
let (common_good_timestep_indices_ptr, common_good_timestep_indices_len) =
ffi_create_c_array(context.common_good_timestep_indices.clone());
let (provided_timestep_indices_ptr, provided_timestep_indices_len) =
ffi_create_c_array(context.provided_timestep_indices.clone());
let (common_coarse_chan_indices_ptr, common_coarse_chan_indices_len) =
ffi_create_c_array(context.common_coarse_chan_indices.clone());
let (common_good_coarse_chan_indices_ptr, common_good_coarse_chan_indices_len) =
ffi_create_c_array(context.common_good_coarse_chan_indices.clone());
let (provided_coarse_chan_indices_ptr, provided_coarse_chan_indices_len) =
ffi_create_c_array(context.provided_coarse_chan_indices.clone());
CorrelatorMetadata {
mwa_version: *mwa_version,
num_timesteps: timesteps_len,
timesteps: timesteps_ptr,
num_coarse_chans: coarse_channels_len,
coarse_chans: coarse_channels_ptr,
num_common_timesteps: common_timestep_indices_len,
common_timestep_indices: common_timestep_indices_ptr,
num_common_coarse_chans: common_coarse_chan_indices_len,
common_coarse_chan_indices: common_coarse_chan_indices_ptr,
common_start_unix_time_ms: *common_start_unix_time_ms,
common_end_unix_time_ms: *common_end_unix_time_ms,
common_start_gps_time_ms: *common_start_gps_time_ms,
common_end_gps_time_ms: *common_end_gps_time_ms,
common_duration_ms: *common_duration_ms,
common_bandwidth_hz: *common_bandwidth_hz,
num_common_good_timesteps: common_good_timestep_indices_len,
common_good_timestep_indices: common_good_timestep_indices_ptr,
num_common_good_coarse_chans: common_good_coarse_chan_indices_len,
common_good_coarse_chan_indices: common_good_coarse_chan_indices_ptr,
common_good_start_unix_time_ms: *common_good_start_unix_time_ms,
common_good_end_unix_time_ms: *common_good_end_unix_time_ms,
common_good_start_gps_time_ms: *common_good_start_gps_time_ms,
common_good_end_gps_time_ms: *common_good_end_gps_time_ms,
common_good_duration_ms: *common_good_duration_ms,
common_good_bandwidth_hz: *common_good_bandwidth_hz,
num_provided_timesteps: provided_timestep_indices_len,
provided_timestep_indices: provided_timestep_indices_ptr,
num_provided_coarse_chans: provided_coarse_chan_indices_len,
provided_coarse_chan_indices: provided_coarse_chan_indices_ptr,
num_timestep_coarse_chan_bytes: *num_timestep_coarse_chan_bytes,
num_timestep_coarse_chan_floats: *num_timestep_coarse_chan_floats,
num_timestep_coarse_chan_weight_floats: *num_timestep_coarse_chan_weight_floats,
num_gpubox_files: *num_gpubox_files,
bscale: *bscale,
}
};
if !out_correlator_metadata_ptr.is_null() {
*out_correlator_metadata_ptr = Box::into_raw(Box::new(out_metadata));
return MWALIB_SUCCESS;
} else {
set_c_string(
"mwalib_correlator_metadata_get() ERROR: out_correlator_metadata_ptr was NULL.",
error_message,
error_message_length,
);
return MWALIB_FAILURE;
}
}
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_metadata_free(c_ptr: *mut CorrelatorMetadata) -> i32 {
if c_ptr.is_null() {
return MWALIB_SUCCESS;
}
let boxed: Box<CorrelatorMetadata> = Box::from_raw(c_ptr);
coarse_channel::ffi::CoarseChannel::destroy_array(boxed.coarse_chans, boxed.num_coarse_chans);
timestep::ffi::TimeStep::destroy_array(boxed.timesteps, boxed.num_timesteps);
ffi_free_c_array(boxed.common_timestep_indices, boxed.num_common_timesteps);
ffi_free_c_array(
boxed.common_coarse_chan_indices,
boxed.num_common_coarse_chans,
);
ffi_free_c_array(
boxed.common_good_timestep_indices,
boxed.num_common_good_timesteps,
);
ffi_free_c_array(
boxed.common_good_coarse_chan_indices,
boxed.num_common_good_coarse_chans,
);
ffi_free_c_array(
boxed.provided_timestep_indices,
boxed.num_provided_timesteps,
);
ffi_free_c_array(
boxed.provided_coarse_chan_indices,
boxed.num_provided_coarse_chans,
);
drop(boxed);
MWALIB_SUCCESS
}
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_context_new(
metafits_filename: *const c_char,
gpubox_filenames: *mut *const c_char,
gpubox_count: size_t,
out_correlator_context_ptr: *mut *mut CorrelatorContext,
error_message: *mut c_char,
error_message_length: size_t,
) -> i32 {
let m = match CStr::from_ptr(metafits_filename).to_str() {
Ok(s) => s,
Err(_) => {
set_c_string(
"invalid UTF-8 in metafits_filename",
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
}
};
let gpubox_slice = slice::from_raw_parts(gpubox_filenames, gpubox_count);
let mut gpubox_files = Vec::with_capacity(gpubox_count);
for g in gpubox_slice {
let s = match CStr::from_ptr(*g).to_str() {
Ok(s) => s,
Err(_) => {
set_c_string(
"invalid UTF-8 in gpubox_filename",
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
}
};
gpubox_files.push(s.to_string())
}
let context = match CorrelatorContext::new(m, &gpubox_files) {
Ok(c) => c,
Err(e) => {
set_c_string(
&format!("{}", e),
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
}
};
*out_correlator_context_ptr = Box::into_raw(Box::new(context));
MWALIB_SUCCESS
}
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_context_display(
correlator_context_ptr: *const CorrelatorContext,
out_buffer_ptr: *mut c_char,
out_buffer_len: usize,
error_message: *mut c_char,
error_message_length: size_t,
) -> i32 {
if correlator_context_ptr.is_null() {
set_c_string(
"mwalib_correlator_context() ERROR: null pointer for correlator_context_ptr passed in",
error_message,
error_message_length,
);
return MWALIB_FAILURE;
}
let context = &*correlator_context_ptr;
let output = format!("{}", context);
set_c_string(&output, out_buffer_ptr, out_buffer_len);
MWALIB_SUCCESS
}
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_context_read_by_baseline(
correlator_context_ptr: *mut CorrelatorContext,
corr_timestep_index: size_t,
corr_coarse_chan_index: size_t,
buffer_ptr: *mut c_float,
buffer_len: size_t,
error_message: *mut c_char,
error_message_length: size_t,
) -> i32 {
let corr_context = if correlator_context_ptr.is_null() {
set_c_string(
"mwalib_correlator_context_read_by_baseline() ERROR: null pointer for correlator_context_ptr passed in",
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
} else {
&mut *correlator_context_ptr
};
if buffer_ptr.is_null() {
return MWALIB_FAILURE;
}
let output_slice = slice::from_raw_parts_mut(buffer_ptr, buffer_len);
match corr_context.read_by_baseline_into_buffer(
corr_timestep_index,
corr_coarse_chan_index,
output_slice,
) {
Ok(_) => MWALIB_SUCCESS,
Err(e) => match e {
GpuboxError::NoDataForTimeStepCoarseChannel {
timestep_index: _,
coarse_chan_index: _,
} => {
set_c_string(
&format!("{}", e),
error_message as *mut c_char,
error_message_length,
);
MWALIB_NO_DATA_FOR_TIMESTEP_COARSECHAN
}
_ => {
set_c_string(
&format!("{}", e),
error_message as *mut c_char,
error_message_length,
);
MWALIB_FAILURE
}
},
}
}
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_context_read_by_frequency(
correlator_context_ptr: *mut CorrelatorContext,
corr_timestep_index: size_t,
corr_coarse_chan_index: size_t,
buffer_ptr: *mut c_float,
buffer_len: size_t,
error_message: *mut c_char,
error_message_length: size_t,
) -> i32 {
let corr_context = if correlator_context_ptr.is_null() {
set_c_string(
"mwalib_correlator_context_read_by_frequency() ERROR: null pointer for correlator_context_ptr passed in",
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
} else {
&mut *correlator_context_ptr
};
if buffer_ptr.is_null() {
return MWALIB_FAILURE;
}
let output_slice = slice::from_raw_parts_mut(buffer_ptr, buffer_len);
match corr_context.read_by_frequency_into_buffer(
corr_timestep_index,
corr_coarse_chan_index,
output_slice,
) {
Ok(_) => MWALIB_SUCCESS,
Err(e) => match e {
GpuboxError::NoDataForTimeStepCoarseChannel {
timestep_index: _,
coarse_chan_index: _,
} => {
set_c_string(
&format!("{}", e),
error_message as *mut c_char,
error_message_length,
);
MWALIB_NO_DATA_FOR_TIMESTEP_COARSECHAN
}
_ => {
set_c_string(
&format!("{}", e),
error_message as *mut c_char,
error_message_length,
);
MWALIB_FAILURE
}
},
}
}
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_context_read_weights_by_baseline(
correlator_context_ptr: *mut CorrelatorContext,
corr_timestep_index: size_t,
corr_coarse_chan_index: size_t,
buffer_ptr: *mut c_float,
buffer_len: size_t,
error_message: *mut c_char,
error_message_length: size_t,
) -> i32 {
let corr_context = if correlator_context_ptr.is_null() {
set_c_string(
"mwalib_correlator_context_read_weights_by_baseline() ERROR: null pointer for correlator_context_ptr passed in",
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
} else {
&mut *correlator_context_ptr
};
if buffer_ptr.is_null() {
return MWALIB_FAILURE;
}
let output_slice = slice::from_raw_parts_mut(buffer_ptr, buffer_len);
match corr_context.read_weights_by_baseline_into_buffer(
corr_timestep_index,
corr_coarse_chan_index,
output_slice,
) {
Ok(_) => MWALIB_SUCCESS,
Err(e) => match e {
GpuboxError::NoDataForTimeStepCoarseChannel {
timestep_index: _,
coarse_chan_index: _,
} => {
set_c_string(
&format!("{}", e),
error_message as *mut c_char,
error_message_length,
);
MWALIB_NO_DATA_FOR_TIMESTEP_COARSECHAN
}
_ => {
set_c_string(
&format!("{}", e),
error_message as *mut c_char,
error_message_length,
);
MWALIB_FAILURE
}
},
}
}
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_context_get_fine_chan_freqs_hz_array(
correlator_context_ptr: *mut CorrelatorContext,
corr_coarse_chan_indices_array_ptr: *mut size_t,
corr_coarse_chan_indices_array_len: size_t,
out_fine_chan_freq_array_ptr: *mut c_double,
out_fine_chan_freq_array_len: size_t,
error_message: *mut c_char,
error_message_length: size_t,
) -> i32 {
let corr_context = if correlator_context_ptr.is_null() {
set_c_string(
"mwalib_correlator_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for correlator_context_ptr passed in",
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
} else {
&mut *correlator_context_ptr
};
if corr_coarse_chan_indices_array_ptr.is_null() {
set_c_string(
"mwalib_correlator_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for corr_coarse_chan_indices_array_ptr passed in",
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
}
let input_coarse_chan_indices = slice::from_raw_parts_mut(
corr_coarse_chan_indices_array_ptr,
corr_coarse_chan_indices_array_len,
);
if out_fine_chan_freq_array_ptr.is_null() {
set_c_string(
"mwalib_correlator_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for out_fine_chan_freq_array_ptr passed in",
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
}
let output_slice =
slice::from_raw_parts_mut(out_fine_chan_freq_array_ptr, out_fine_chan_freq_array_len);
let expected_output_len = corr_coarse_chan_indices_array_len
* corr_context.metafits_context.num_corr_fine_chans_per_coarse;
if output_slice.len() != expected_output_len {
set_c_string(
&format!("mwalib_correlator_context_get_fine_chan_freqs_hz_array() ERROR: number of elements in out_fine_chan_freq_array_ptr does not match expected value {}", expected_output_len),
error_message as *mut c_char,
error_message_length,
);
return MWALIB_FAILURE;
}
let fine_chans = corr_context.get_fine_chan_freqs_hz_array(input_coarse_chan_indices);
output_slice.clone_from_slice(&fine_chans);
MWALIB_SUCCESS
}
#[no_mangle]
#[allow(unused_must_use)]
pub unsafe extern "C" fn mwalib_correlator_context_free(
correlator_context_ptr: *mut CorrelatorContext,
) -> i32 {
if correlator_context_ptr.is_null() {
return MWALIB_SUCCESS;
}
drop(Box::from_raw(correlator_context_ptr));
MWALIB_SUCCESS
}