#![allow(non_snake_case)]
#![allow(dead_code)]
pub mod astro;
pub mod environment;
#[cfg(feature = "python")]
mod bindings;
mod get_set_string;
pub mod obs;
pub mod satellite;
pub mod sensor;
pub mod sgp4;
#[cfg(test)]
pub(crate) mod test_lock;
pub mod time;
pub mod tle;
use ctor::ctor;
pub use get_set_string::GetSetString;
#[cfg(feature = "python")]
use pyo3::prelude::*;
use std::os::raw::c_char;
use std::path::PathBuf;
unsafe extern "C" {
pub fn DllMainGetInfo(infoStr: *const c_char);
pub fn DllMainLoadFile(dllMainFile: *const c_char) -> i32;
pub fn GetLastErrMsg(lastErrMsg: *const c_char);
pub fn GetLastInfoMsg(lastInfoMsg: *const c_char);
pub fn SetElsetKeyMode(elset_keyMode: i32) -> i32;
pub fn GetElsetKeyMode() -> i32;
pub fn SetAllKeyMode(all_keyMode: i32) -> i32;
pub fn GetAllKeyMode() -> i32;
pub fn ResetAllKeyMode();
pub fn SetDupKeyMode(dupKeyMode: i32) -> i32;
pub fn GetDupKeyMode() -> i32;
}
pub const LOGMSGLEN: i32 = 128;
pub const FILEPATHLEN: i32 = 512;
pub const GETSETSTRLEN: usize = 512;
pub const INFOSTRLEN: i32 = 128;
pub const INPUTCARDLEN: i32 = 512;
pub const ELTTYPE_TLE_SGP: isize = 1;
pub const ELTTYPE_TLE_SGP4: isize = 2;
pub const ELTTYPE_TLE_SP: isize = 3;
pub const ELTTYPE_SPVEC_B1P: isize = 4;
pub const ELTTYPE_VCM: isize = 5;
pub const ELTTYPE_EXTEPH: isize = 6;
pub const ELTTYPE_TLE_XP: isize = 7;
pub const PROPTYPE_GP: i32 = 1;
pub const PROPTYPE_SP: i32 = 2;
pub const PROPTYPE_X: i32 = 3;
pub const PROPTYPE_UK: i32 = 4;
pub const BADSATKEY: i32 = -1;
pub const DUPSATKEY: i32 = 0;
pub const BADKEY: i32 = -1;
pub const DUPKEY: i32 = 0;
pub const ALL_KEYMODE_NODUP: i32 = 0;
pub const ALL_KEYMODE_DMA: i32 = 1;
pub const ELSET_KEYMODE_NODUP: i32 = 0;
pub const ELSET_KEYMODE_DMA: i32 = 1;
pub const DUPKEY_ZERO: i32 = 0;
pub const DUPKEY_ACTUAL: i32 = 1;
pub const TIME_IS_MSE: i32 = 1;
pub const TIME_IS_TAI: i32 = 2;
pub const TIME_IS_UTC: i32 = 3;
pub const MAX_ALPHA_5_SAT_ID: i32 = 339999;
pub const DEFAULT_NORAD_ID: i32 = 99999;
pub const DEFAULT_SENSOR_NUMBER: i32 = 999;
pub const IDX_ORDER_ASC: i32 = 0;
pub const IDX_ORDER_DES: i32 = 1;
pub const IDX_ORDER_READ: i32 = 2;
pub const IDX_ORDER_QUICK: i32 = 9;
pub const DLL_VERSION: &str = env!("SAAL_MANIFEST_VERSION");
pub fn get_last_error_message() -> String {
let mut msg = GetSetString::new();
unsafe { GetLastErrMsg(msg.pointer()) };
msg.value()
}
pub fn get_key_mode() -> Result<i32, String> {
let key_mode = unsafe { GetAllKeyMode() };
match key_mode {
ALL_KEYMODE_DMA => Ok(key_mode),
ALL_KEYMODE_NODUP => Ok(key_mode),
_ => Err(get_last_error_message()),
}
}
pub fn set_key_mode(key_mode: i32) -> Result<(), String> {
let result = unsafe { SetAllKeyMode(key_mode) };
match result {
0 => Ok(()),
_ => Err(get_last_error_message()),
}
}
pub fn reset_key_mode() {
unsafe { ResetAllKeyMode() };
}
pub fn get_last_info_message() -> String {
let mut msg = GetSetString::new();
unsafe { GetLastInfoMsg(msg.pointer()) };
msg.value()
}
pub fn get_dll_info() -> String {
let mut info = GetSetString::new();
unsafe { DllMainGetInfo(info.pointer()) };
info.value()
}
pub fn load_from_file(file_path: &str) -> Result<(), String> {
let mut dll_path: GetSetString = file_path.into();
let result = unsafe { DllMainLoadFile(dll_path.pointer()) };
match result {
0 => Ok(()),
_ => Err(get_last_error_message()),
}
}
pub fn set_elset_key_mode(elset_key_mode: i32) -> Result<(), String> {
let result = unsafe { SetElsetKeyMode(elset_key_mode) };
match result {
0 => Ok(()),
_ => Err(get_last_error_message()),
}
}
pub fn get_elset_key_mode() -> Result<i32, String> {
let elset_key_mode = unsafe { GetElsetKeyMode() };
match elset_key_mode {
ELSET_KEYMODE_DMA => Ok(elset_key_mode),
ELSET_KEYMODE_NODUP => Ok(elset_key_mode),
_ => Err(get_last_error_message()),
}
}
pub fn set_duplicate_key_mode(dup_key_mode: i32) -> Result<(), String> {
let result = unsafe { SetDupKeyMode(dup_key_mode) };
match result {
0 => Ok(()),
_ => Err(get_last_error_message()),
}
}
pub fn get_duplicate_key_mode() -> Result<i32, String> {
let dup_key_mode = unsafe { GetDupKeyMode() };
match dup_key_mode {
DUPKEY_ZERO => Ok(dup_key_mode),
DUPKEY_ACTUAL => Ok(dup_key_mode),
_ => Err(get_last_error_message()),
}
}
#[ctor]
fn initialize() {
set_key_mode(ALL_KEYMODE_DMA).unwrap();
if let Some(path) = get_time_constants_path() {
time::load_constants(path.to_str().unwrap()).unwrap();
}
if let Some(path) = get_jpl_file_path() {
astro::set_jpl_ephemeris_file_path(path.to_str().unwrap());
}
if let Some(asset_dir) = get_asset_directory() {
sgp4::set_license_directory(asset_dir.to_str().unwrap());
}
}
fn asset_directory_override() -> Option<PathBuf> {
std::env::var("SAAL_ASSET_DIRECTORY").ok().map(PathBuf::from)
}
fn build_asset_directory() -> Option<PathBuf> {
option_env!("SAAL_BUILD_ASSET_DIR")
.map(PathBuf::from)
.filter(|path| path.exists())
}
fn get_asset_directory() -> Option<PathBuf> {
if let Some(path) = asset_directory_override()
&& path.exists()
{
return Some(path);
}
Some(std::env::current_exe().ok()?.parent()?.to_path_buf())
}
fn get_time_constants_path() -> Option<PathBuf> {
let asset_dir = get_asset_directory()?;
let time_constants_path = asset_dir.join("time_constants.dat");
if time_constants_path.exists() {
return Some(time_constants_path);
}
None
}
fn get_jpl_file_path() -> Option<PathBuf> {
let asset_dir = get_asset_directory()?;
let jpl_path = asset_dir.join("JPLcon_1950_2050.405");
if jpl_path.exists() {
return Some(jpl_path);
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_lock::TEST_LOCK;
#[test]
fn test_get_dll_info_contains_version() {
let _lock = TEST_LOCK.lock().unwrap();
let info = get_dll_info();
assert!(info.contains(DLL_VERSION));
}
#[test]
fn test_get_key_mode_default() {
let _lock = TEST_LOCK.lock().unwrap();
let mode = get_key_mode().unwrap() as i32;
assert_eq!(mode, 1);
}
#[test]
fn test_set_duplicate_key_mode_return_key() {
let _lock = TEST_LOCK.lock().unwrap();
set_duplicate_key_mode(DUPKEY_ACTUAL).unwrap();
let mode = get_duplicate_key_mode().unwrap();
assert_eq!(mode, DUPKEY_ACTUAL);
}
#[test]
fn test_get_duplicate_key_mode_return_zero() {
let _lock = TEST_LOCK.lock().unwrap();
set_duplicate_key_mode(DUPKEY_ZERO).unwrap();
let mode = get_duplicate_key_mode().unwrap();
assert_eq!(mode, DUPKEY_ZERO);
}
#[test]
fn test_load_from_file_missing() {
let _lock = TEST_LOCK.lock().unwrap();
let path = std::env::temp_dir().join("saal_missing_input.txt");
let _ = std::fs::remove_file(&path);
let result = load_from_file(path.to_str().unwrap());
assert!(result.is_err());
}
}
#[cfg(feature = "python")]
#[pymodule]
fn _pysaal(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
bindings::register_bindings(parent_module)?;
Ok(())
}