#![allow(non_snake_case)]
#![allow(dead_code)]
use crate::{GetSetString, get_last_error_message};
use std::os::raw::c_char;
unsafe extern "C" {
pub fn TimeFuncGetInfo(infoStr: *const c_char);
pub fn TConLoadFile(tconFile: *const c_char) -> i32;
pub fn TimeFuncLoadFile(tconFile: *const c_char) -> i32;
pub fn IsTConFileLoaded() -> i32;
pub fn TConSaveFile(tconFile: *const c_char, saveMode: i32, saveForm: i32) -> i32;
pub fn TConAddARec(
refDs50UTC: f64,
leapDs50UTC: f64,
taiMinusUTC: f64,
ut1MinusUTC: f64,
ut1Rate: f64,
polarX: f64,
polarY: f64,
) -> i32;
pub fn TConAddOne(
refDs50UTC: f64,
taiMinusUTC: f64,
ut1MinusUTC: f64,
ut1Rate: f64,
polarX: f64,
polarY: f64,
) -> i32;
pub fn UTCToTConRec(
ds50UTC: f64,
taiMinusUTC: *mut f64,
ut1MinusUTC: *mut f64,
ut1Rate: *mut f64,
polarX: *mut f64,
polarY: *mut f64,
);
pub fn TConRemoveAll() -> i32;
pub fn UTCToDTG20(ds50UTC: f64, dtg20: *const c_char);
pub fn UTCToDTG19(ds50UTC: f64, dtg19: *const c_char);
pub fn UTCToDTG17(ds50UTC: f64, dtg17: *const c_char);
pub fn UTCToDTG15(ds50UTC: f64, dtg15: *const c_char);
pub fn DTGToUTC(dtg: *const c_char) -> f64;
pub fn UTCToTAI(ds50UTC: f64) -> f64;
pub fn UTCToUT1(ds50UTC: f64) -> f64;
pub fn UTCToET(ds50UTC: f64) -> f64;
pub fn TAIToUTC(ds50TAI: f64) -> f64;
pub fn TAIToUT1(ds50TAI: f64) -> f64;
pub fn YrDaysToUTC(year: i32, dayOfYear: f64) -> f64;
pub fn UTCToYrDays(ds50UTC: f64, year: *mut i32, dayOfYear: *mut f64);
pub fn TimeComps1ToUTC(year: i32, dayOfYear: i32, hh: i32, mm: i32, sss: f64) -> f64;
pub fn UTCToTimeComps1(
ds50UTC: f64,
year: *mut i32,
dayOfYear: *mut i32,
hh: *mut i32,
mm: *mut i32,
sss: *mut f64,
);
pub fn TimeComps2ToUTC(year: i32, mon: i32, dayOfMonth: i32, hh: i32, mm: i32, sss: f64) -> f64;
pub fn UTCToTimeComps2(
ds50UTC: f64,
year: *mut i32,
month: *mut i32,
dayOfMonth: *mut i32,
hh: *mut i32,
mm: *mut i32,
sss: *mut f64,
);
pub fn ThetaGrnwch(ds50UT1: f64, lenvFk: i64) -> f64;
pub fn ThetaGrnwchFK4(ds50UT1: f64) -> f64;
pub fn ThetaGrnwchFK5(ds50UT1: f64) -> f64;
pub fn TimeConvFrTo(funcIdx: i32, frArr: *const f64, toArr: *mut f64);
pub fn Get6P(
startFrEpoch: *mut i32,
stopFrEpoch: *mut i32,
startTime: *mut f64,
stopTime: *mut f64,
interval: *mut f64,
);
pub fn Set6P(startFrEpoch: i32, stopFrEpoch: i32, startTime: f64, stopTime: f64, interval: f64);
pub fn Get6PCardLine(card6PLine: *const c_char);
pub fn TConTimeSpan(numOfRecs: *mut i32, frTimeDs50UTC: *mut f64, toTimeDs50UTC: *mut f64);
}
pub fn get_dll_info() -> String {
let mut info_str = GetSetString::new();
unsafe {
TimeFuncGetInfo(info_str.pointer());
}
info_str.value()
}
pub fn ymd_components_to_ds50(year: i32, month: i32, day: i32, hour: i32, minute: i32, second: f64) -> f64 {
unsafe { TimeComps2ToUTC(year, month, day, hour, minute, second) }
}
pub fn ds50_to_ymd_components(ds50: f64) -> (i32, i32, i32, i32, i32, f64) {
let mut year = 0;
let mut month = 0;
let mut day = 0;
let mut hour = 0;
let mut minute = 0;
let mut second = 0.0;
unsafe {
UTCToTimeComps2(
ds50,
&mut year,
&mut month,
&mut day,
&mut hour,
&mut minute,
&mut second,
)
};
(year, month, day, hour, minute, second)
}
pub fn dtg_to_ds50(dtg: &str) -> f64 {
let mut inout: GetSetString = dtg.into();
unsafe { DTGToUTC(inout.pointer()) }
}
pub fn ds50_to_dtg20(ds50: f64) -> String {
let mut inout = GetSetString::new();
unsafe { UTCToDTG20(ds50, inout.pointer()) };
inout.value()
}
pub fn ds50_to_dtg19(ds50: f64) -> String {
let mut inout = GetSetString::new();
unsafe { UTCToDTG19(ds50, inout.pointer()) };
inout.value()
}
pub fn ds50_to_dtg17(ds50: f64) -> String {
let mut inout = GetSetString::new();
unsafe { UTCToDTG17(ds50, inout.pointer()) };
inout.value()
}
pub fn ds50_to_dtg15(ds50: f64) -> String {
let mut inout = GetSetString::new();
unsafe { UTCToDTG15(ds50, inout.pointer()) };
inout.value()
}
pub fn year_doy_to_ds50(year: i32, doy: f64) -> f64 {
unsafe { YrDaysToUTC(year, doy) }
}
pub fn ds50_to_year_doy(ds50: f64) -> (i32, f64) {
let mut year = 0;
let mut doy = 0.0;
unsafe { UTCToYrDays(ds50, &mut year, &mut doy) };
(year, doy)
}
pub fn tai_to_utc(ds50_tai: f64) -> f64 {
unsafe { TAIToUTC(ds50_tai) }
}
pub fn utc_to_tai(ds50_utc: f64) -> f64 {
unsafe { UTCToTAI(ds50_utc) }
}
pub fn utc_to_ut1(ds50_utc: f64) -> f64 {
unsafe { UTCToUT1(ds50_utc) }
}
pub fn utc_to_tt(ds50_utc: f64) -> f64 {
unsafe { UTCToET(ds50_utc) }
}
pub fn tai_to_ut1(ds50_tai: f64) -> f64 {
unsafe { TAIToUT1(ds50_tai) }
}
pub fn load_constants(path: &str) -> Result<(), String> {
let path = std::ffi::CString::new(path).unwrap();
let err_code = unsafe { TConLoadFile(path.as_ptr()) };
if err_code == 0 {
Ok(())
} else {
Err(get_last_error_message())
}
}
pub fn get_fk4_greenwich_angle(ds50_ut1: f64) -> f64 {
unsafe { ThetaGrnwchFK4(ds50_ut1) }
}
pub fn get_fk5_greenwich_angle(ds50_ut1: f64) -> f64 {
unsafe { ThetaGrnwchFK5(ds50_ut1) }
}
pub fn constants_loaded() -> bool {
unsafe { IsTConFileLoaded() != 0 }
}
pub fn clear_constants() -> Result<(), String> {
let err_code = unsafe { TConRemoveAll() };
match err_code {
0 => Ok(()),
_ => Err(get_last_error_message()),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::DLL_VERSION;
use crate::test_lock::TEST_LOCK;
use approx::assert_abs_diff_eq;
#[test]
fn test_get_dll_info() {
let _lock = TEST_LOCK.lock().unwrap();
let info = get_dll_info();
assert!(info.contains(DLL_VERSION));
}
#[test]
fn test_ymd_components_to_ds50() {
let _lock = TEST_LOCK.lock().unwrap();
let ds50 = ymd_components_to_ds50(1956, 1, 1, 0, 0, 0.0);
assert_eq!(ds50, 2192.0);
}
#[test]
fn test_ds50_to_ymd_components() {
let _lock = TEST_LOCK.lock().unwrap();
let (year, month, day, hour, minute, second) = ds50_to_ymd_components(2192.0);
assert_eq!((year, month, day, hour, minute, second), (1956, 1, 1, 0, 0, 0.0));
}
#[test]
fn test_dtg_to_ds50() {
let _lock = TEST_LOCK.lock().unwrap();
let ds50 = dtg_to_ds50("1956/001 0000 00.000");
assert_eq!(ds50, 2192.0);
}
#[test]
fn test_ds50_to_dtg_formats() {
let _lock = TEST_LOCK.lock().unwrap();
assert_eq!(ds50_to_dtg20(2192.0), "1956/001 0000 00.000");
assert_eq!(ds50_to_dtg19(2192.0), "1956Jan01000000.000");
assert_eq!(ds50_to_dtg17(2192.0), "1956/001.00000000");
assert_eq!(ds50_to_dtg15(2192.0), "56001000000.000");
}
#[test]
fn test_year_doy_conversions() {
let _lock = TEST_LOCK.lock().unwrap();
let ds50 = year_doy_to_ds50(1956, 1.0);
assert_eq!(ds50, 2192.0);
let (year, doy) = ds50_to_year_doy(2192.0);
assert_eq!((year, doy), (1956, 1.0));
}
#[test]
fn test_constants_loaded() {
let _lock = TEST_LOCK.lock().unwrap();
assert!(constants_loaded());
}
#[test]
fn test_conversions() {
let _lock = TEST_LOCK.lock().unwrap();
let utc = ymd_components_to_ds50(1973, 1, 30, 0, 0, 0.0);
let tai = 8431.000138888889;
let ut1 = 8431.00000830081;
let tt = 8431.00051138889;
assert_abs_diff_eq!(utc_to_tai(utc), tai, epsilon = 1.0e-10);
assert_abs_diff_eq!(tai_to_utc(tai), utc, epsilon = 1.0e-10);
assert_abs_diff_eq!(utc_to_ut1(utc), ut1, epsilon = 1.0e-10);
assert_abs_diff_eq!(utc_to_tt(utc), tt, epsilon = 1.0e-10);
assert_abs_diff_eq!(tai_to_ut1(tai), ut1, epsilon = 1.0e-10);
}
#[test]
fn test_greenwich_angles() {
let _lock = TEST_LOCK.lock().unwrap();
let utc = ymd_components_to_ds50(1973, 1, 2, 0, 0, 0.0);
let ut1 = utc_to_ut1(utc);
let fk4 = get_fk4_greenwich_angle(ut1);
let fk5 = get_fk5_greenwich_angle(ut1);
assert_abs_diff_eq!(fk4, 1.7712987335192203, epsilon = 1.0e-7);
assert_abs_diff_eq!(fk5, 1.7713027012394775, epsilon = 1.0e-7);
}
}