#![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 ObsInit(apAddr: i64) -> i32;
pub fn ObsGetInfo(infoStr: *const c_char);
pub fn ObsSetTTYYear(ttyYear: i32);
pub fn ObsLoadFile(obsFile: *const c_char) -> i32;
pub fn ObsSaveFile(obsFile: *const c_char, saveMode: i32, obsForm: i32) -> i32;
pub fn ObsRemove(obsKey: i64) -> i32;
pub fn ObsRemoveAll() -> i32;
pub fn ObsGetCount() -> i32;
pub fn ObsGetLoaded(order: i32, obsKeys: *mut i64);
pub fn ObsLoadCard(card: *const c_char) -> i32;
pub fn ObsLoadTwoCards(card1: *const c_char, card2: *const c_char) -> i32;
pub fn ObsAddFrB3Card(card: *const c_char) -> i64;
pub fn ObsAddFrB3CardML(card: *const c_char, obsKey: *mut i64);
pub fn ObsB3ToCsv(card: *const c_char, csvLine: *const c_char) -> i32;
pub fn ObsCsvToB3(csvLine: *const c_char, newSatno: i32, card: *const c_char) -> i32;
pub fn ObsAddFrTTYCards(card1: *const c_char, card2: *const c_char) -> i64;
pub fn ObsAddFrTTYCardsML(card1: *const c_char, card2: *const c_char, obsKey: *mut i64);
pub fn ObsTTYToCsv(card1: *const c_char, card2: *const c_char, csvLine: *const c_char) -> i32;
pub fn ObsCsvToTTY(csvLine: *const c_char, newSatno: i32, card1: *const c_char, card2: *const c_char) -> i32;
pub fn ObsAddFrCsv(csvLine: *const c_char) -> i64;
pub fn ObsAddFrCsvML(csvLine: *const c_char, obsKey: *mut i64);
pub fn ObsAddFrFields(
secClass: c_char,
satNum: i32,
senNum: i32,
obsTimeDs50utc: f64,
elOrDec: f64,
azOrRA: f64,
slantRange: f64,
rangeRate: f64,
elRate: f64,
azRate: f64,
rangeAccel: f64,
obsType: c_char,
trackInd: i32,
astat: i32,
siteTag: i32,
spadocTag: i32,
pos: *const [f64; 3],
vel: *const [f64; 3],
extArr: *const [f64; 128],
) -> i64;
pub fn ObsAddFrFieldsML(
secClass: c_char,
satNum: i32,
senNum: i32,
obsTimeDs50utc: f64,
elOrDec: f64,
azOrRA: f64,
slantRange: f64,
rangeRate: f64,
elRate: f64,
azRate: f64,
rangeAccel: f64,
obsType: c_char,
trackInd: i32,
astat: i32,
siteTag: i32,
spadocTag: i32,
pos: *const [f64; 3],
vel: *const [f64; 3],
extArr: *const [f64; 128],
obsKey: *mut i64,
);
pub fn ObsAddFrArray(xa_obs: *const [f64; 64]) -> i64;
pub fn ObsAddFrArrayML(xa_obs: *const [f64; 64], obsKey: *mut i64);
pub fn ObsGetAllFields(
obsKey: i64,
secClass: *const c_char,
satNum: *mut i32,
senNum: *mut i32,
obsTimeDs50utc: *mut f64,
elOrDec: *mut f64,
azOrRA: *mut f64,
slantRange: *mut f64,
rangeRate: *mut f64,
elRate: *mut f64,
azRate: *mut f64,
rangeAccel: *mut f64,
obsType: *const c_char,
trackInd: *mut i32,
astat: *mut i32,
siteTag: *mut i32,
spadocTag: *mut i32,
pos: *mut [f64; 3],
vel: *mut [f64; 3],
extArr: *mut [f64; 128],
) -> i32;
pub fn ObsDataToArray(obsKey: i64, xa_obs: *mut [f64; 64]) -> i32;
pub fn ObsUpdateFrFields(
obsKey: i64,
secClass: c_char,
elOrDec: f64,
azOrRA: f64,
slantRange: f64,
rangeRate: f64,
elRate: f64,
azRate: f64,
rangeAccel: f64,
obsType: c_char,
trackInd: i32,
astat: i32,
siteTag: i32,
spadocTag: i32,
pos: *const [f64; 3],
vel: *const [f64; 3],
extArr: *const [f64; 128],
) -> i32;
pub fn ObsGetField(obsKey: i64, xf_Obs: i32, strValue: *const c_char) -> i32;
pub fn ObsSetField(obsKey: i64, xf_Obs: i32, strValue: *const c_char) -> i32;
pub fn ObsGetB3Card(obsKey: i64, b3Card: *const c_char) -> i32;
pub fn ObsGetTTYCard(obsKey: i64, ttyCard1: *const c_char, ttyCard2: *const c_char) -> i32;
pub fn ObsGetCsv(obsKey: i64, csvline: *const c_char) -> i32;
pub fn ObsFieldsToB3Card(
secClass: c_char,
satNum: i32,
senNum: i32,
obsTimeDs50utc: f64,
elOrDec: f64,
azOrRA: f64,
slantRange: f64,
rangeRate: f64,
elRate: f64,
azRate: f64,
rangeAccel: f64,
obsType: c_char,
trackInd: i32,
astat: i32,
siteTag: i32,
spadocTag: i32,
pos: *const [f64; 3],
b3Card: *const c_char,
);
pub fn ObsFieldsToCsv(
secClass: c_char,
satNum: i32,
senNum: i32,
obsTimeDs50utc: f64,
elOrDec: f64,
azOrRA: f64,
slantRange: f64,
rangeRate: f64,
elRate: f64,
azRate: f64,
rangeAccel: f64,
obsType: c_char,
trackInd: i32,
astat: i32,
siteTag: i32,
spadocTag: i32,
pos: *const [f64; 3],
csvLine: *const c_char,
);
pub fn ObsFieldsToTTYCard(
secClass: c_char,
satNum: i32,
senNum: i32,
obsTimeDs50utc: f64,
elOrDec: f64,
azOrRA: f64,
slantRange: f64,
rangeRate: f64,
elRate: f64,
azRate: f64,
rangeAccel: f64,
obsType: c_char,
pos: *const [f64; 3],
ttyCard1: *const c_char,
ttyCard2: *const c_char,
);
pub fn ObsFieldsToObsKey(satNum: i32, senNum: i32, obsTimeDs50utc: f64) -> i64;
pub fn ObsFieldsToObsKeyML(satNum: i32, senNum: i32, obsTimeDs50utc: f64, obsKey: *mut i64);
pub fn ObsB3Parse(
b3ObsCard: *const c_char,
secClass: *const c_char,
satNum: *mut i32,
senNum: *mut i32,
obsTimeDs50utc: *mut f64,
elOrDec: *mut f64,
azOrRA: *mut f64,
slantRange: *mut f64,
rangeRate: *mut f64,
elRate: *mut f64,
azRate: *mut f64,
rangeAccel: *mut f64,
obsType: *const c_char,
trackInd: *mut i32,
astat: *mut i32,
siteTag: *mut i32,
spadocTag: *mut i32,
pos: *mut [f64; 3],
) -> i32;
pub fn ObsParse(line1: *const c_char, line2: *const c_char, xa_obs: *mut [f64; 64]) -> i32;
pub fn ObsLoadFileGID(obsFile: *const c_char, gid: i32) -> i32;
pub fn ObsSaveFileGID(obsFile: *const c_char, gid: i32, saveMode: i32, obsForm: i32) -> i32;
pub fn ObsRemoveGID(gid: i32) -> i32;
pub fn ObsGetCountGID(gid: i32) -> i32;
pub fn ObsGetLoadedGID(gid: i32, order: i32, obsKeys: *mut i64);
pub fn ObsTypeCToI(obsTypeChar: c_char) -> i32;
pub fn ObsTypeIToC(obsTypeInt: i32) -> c_char;
pub fn ObsResetSelObs();
pub fn ObsGetStates(obsKey: i64, range_km: f64, xa_obState: *mut [f64; 64]) -> i32;
pub fn ObsDataToStates(xa_obs: *const [f64; 64], xa_obState: *mut [f64; 64]) -> i32;
pub fn ObsArrToLines(xa_obs: *const [f64; 64], obsForm: i32, line1: *const c_char, line2: *const c_char) -> i32;
pub fn SetObsKeyMode(obs_keyMode: i32) -> i32;
pub fn GetObsKeyMode() -> i32;
pub fn SatNumFrObsKey(obsKey: i64) -> i32;
pub fn SenNumFrObsKey(obsKey: i64) -> i32;
pub fn ObsGetSelected(xa_selob: *const [f64; 128], order: i32, numMatchedObss: *mut i32, obsKeys: *mut i64);
}
pub fn get_dll_info() -> String {
let mut c_info = GetSetString::new();
unsafe { ObsGetInfo(c_info.pointer()) };
c_info.value()
}
pub const EQUINOX_OBSTIME: i32 = 0;
pub const EQUINOX_OBSYEAR: i32 = 1;
pub const EQUINOX_J2K: i32 = 2;
pub const EQUINOX_B1950: i32 = 3;
pub static SORT_TIMESENTYPEEL: i32 = 1;
pub static SORT_TIMEEL: i32 = 2;
pub static SORT_TIMESENTYPEELSAT: i32 = 3;
pub static SORT_SENSATTIMEEL: i32 = 4;
pub static SORT_SENTIMEEL: i32 = 5;
pub static SORT_SENSATTYPETIMEEL: i32 = 6;
pub static SORT_SATTIMESENTYPEEL: i32 = 7;
pub static SORT_ORDERASREAD: i32 = 8;
pub static SORT_SATSENTIME: i32 = 10;
pub static OBSFORM_B3: i32 = 0;
pub static OBSFORM_TTY: i32 = 1;
pub static OBSFORM_CSV: i32 = 2;
pub static OBSFORM_RF: i32 = 3;
pub static BADOBSKEY: i32 = -1;
pub static DUPOBSKEY: i32 = 0;
pub static OBS_KEYMODE_NODUP: i32 = 0;
pub static OBS_KEYMODE_DMA: i32 = 1;
pub static CSVSIGMATYPE: i32 = 7;
pub static XF_OBS_SECCLASS: i32 = 1;
pub static XF_OBS_SATNUM: i32 = 2;
pub static XF_OBS_SENNUM: i32 = 3;
pub static XF_OBS_DS50UTC: i32 = 4;
pub static XF_OBS_ELEVATION: i32 = 5;
pub static XF_OBS_DECLINATION: i32 = 6;
pub static XF_OBS_AZIMUTH: i32 = 7;
pub static XF_OBS_RA: i32 = 8;
pub static XF_OBS_RANGE: i32 = 9;
pub static XF_OBS_RANGERATE: i32 = 10;
pub static XF_OBS_ELRATE: i32 = 11;
pub static XF_OBS_AZRATE: i32 = 12;
pub static XF_OBS_RANGEACCEL: i32 = 13;
pub static XF_OBS_OBSTYPE: i32 = 14;
pub static XF_OBS_TRACKIND: i32 = 15;
pub static XF_OBS_ASTAT: i32 = 16;
pub static XF_OBS_SITETAG: i32 = 17;
pub static XF_OBS_SPADOCTAG: i32 = 18;
pub static XF_OBS_POSE: i32 = 19;
pub static XF_OBS_POSF: i32 = 20;
pub static XF_OBS_POSG: i32 = 21;
pub static XF_OBS_POSX: i32 = 22;
pub static XF_OBS_POSY: i32 = 23;
pub static XF_OBS_POSZ: i32 = 24;
pub static XF_OBS_RCS_PP: i32 = 25;
pub static XF_OBS_RCS_OP: i32 = 26;
pub static XF_OBS_RCS_PPS: i32 = 27;
pub static XF_OBS_RCS_OPS: i32 = 28;
pub static XF_OBS_SNR: i32 = 29;
pub static XF_OBS_BORE_AZ: i32 = 30;
pub static XF_OBS_BORE_EL: i32 = 31;
pub static XF_OBS_VISMAG: i32 = 32;
pub static XF_OBS_VISMAG_NORM: i32 = 33;
pub static XF_OBS_SOL_PHASE: i32 = 34;
pub static XF_OBS_FRAME: i32 = 35;
pub static XF_OBS_ABERRATION: i32 = 36;
pub static XF_OBS_ASTAT_METHOD: i32 = 37;
pub const XA_OBS_SECCLASS: usize = 0;
pub const XA_OBS_SATNUM: usize = 1;
pub const XA_OBS_SENNUM: usize = 2;
pub const XA_OBS_DS50UTC: usize = 3;
pub const XA_OBS_OBSTYPE: usize = 11;
pub const XA_OBS_ELORDEC: usize = 4;
pub const XA_OBS_AZORRA: usize = 5;
pub const XA_OBS_RANGE: usize = 6;
pub const XA_OBS_RANGERATE: usize = 7;
pub const XA_OBS_ELRATE: usize = 8;
pub const XA_OBS_AZRATE: usize = 9;
pub const XA_OBS_RANGEACCEL: usize = 10;
pub const XA_OBS_TRACKIND: usize = 12;
pub const XA_OBS_ASTAT: usize = 13;
pub const XA_OBS_SITETAG: usize = 14;
pub const XA_OBS_SPADOCTAG: usize = 15;
pub const XA_OBS_POSX: usize = 16;
pub const XA_OBS_POSY: usize = 17;
pub const XA_OBS_POSZ: usize = 18;
pub const XA_OBS_VELX: usize = 19;
pub const XA_OBS_VELY: usize = 20;
pub const XA_OBS_VELZ: usize = 21;
pub const XA_OBS_YROFEQNX: usize = 22;
pub const XA_OBS_ABERRATION: usize = 23;
pub const XA_OBS_AZORRABIAS: usize = 33;
pub const XA_OBS_ELORDECBIAS: usize = 34;
pub const XA_OBS_RGBIAS: usize = 35;
pub const XA_OBS_RRBIAS: usize = 36;
pub const XA_OBS_TIMEBIAS: usize = 37;
pub const XA_OBS_RAZORRABIAS: usize = 38;
pub const XA_OBS_RELORDECBIAS: usize = 39;
pub const XA_OBS_SIGMATYPE: usize = 40;
pub const XA_OBS_SIGMAEL1: usize = 41;
pub const XA_OBS_SIGMAEL2: usize = 42;
pub const XA_OBS_SIGMAEL3: usize = 43;
pub const XA_OBS_SIGMAEL4: usize = 44;
pub const XA_OBS_SIGMAEL5: usize = 45;
pub const XA_OBS_SIGMAEL6: usize = 46;
pub const XA_OBS_SIGMAEL7: usize = 47;
pub const XA_OBS_SIGMAEL8: usize = 48;
pub const XA_OBS_SIGMAEL9: usize = 49;
pub const XA_OBS_SIGMAEL10: usize = 50;
pub const XA_OBS_SIGMAEL11: usize = 51;
pub const XA_OBS_SIGMAEL12: usize = 52;
pub const XA_OBS_SIGMAEL13: usize = 53;
pub const XA_OBS_SIGMAEL14: usize = 54;
pub const XA_OBS_SIGMAEL15: usize = 55;
pub const XA_OBS_SIGMAEL16: usize = 56;
pub const XA_OBS_SIGMAEL17: usize = 57;
pub const XA_OBS_SIGMAEL18: usize = 58;
pub const XA_OBS_SIGMAEL19: usize = 59;
pub const XA_OBS_SIGMAEL20: usize = 60;
pub const XA_OBS_SIGMAEL21: usize = 61;
pub const XA_OBS_SIZE: usize = 64;
pub static XA_OTCSV_SECCLASS: i32 = 0;
pub static XA_OTCSV_SATNUM: i32 = 1;
pub static XA_OTCSV_SENNUM: i32 = 2;
pub static XA_OTCSV_DS50UTC: i32 = 3;
pub static XA_OTCSV_ELORDEC: i32 = 4;
pub static XA_OTCSV_AZORRA: i32 = 5;
pub static XA_OTCSV_RANGE: i32 = 6;
pub static XA_OTCSV_RANGERATE: i32 = 7;
pub static XA_OTCSV_ELRATE: i32 = 8;
pub static XA_OTCSV_AZRATE: i32 = 9;
pub static XA_OTCSV_RANGEACCEL: i32 = 10;
pub static XA_OTCSV_OBSTYPE: i32 = 11;
pub static XA_OTCSV_TRACKIND: i32 = 12;
pub static XA_OTCSV_ASTAT: i32 = 13;
pub static XA_OTCSV_SITETAG: i32 = 14;
pub static XA_OTCSV_SPADOCTAG: i32 = 15;
pub static XA_OTCSV_POSX: i32 = 16;
pub static XA_OTCSV_POSY: i32 = 17;
pub static XA_OTCSV_POSZ: i32 = 18;
pub static XA_OTCSV_VELX: i32 = 19;
pub static XA_OTCSV_VELY: i32 = 20;
pub static XA_OTCSV_VELZ: i32 = 21;
pub static XA_OTCSV_YROFEQNX: i32 = 22;
pub static XA_OTCSV_RCS_PP: i32 = 23;
pub static XA_OTCSV_RCS_OP: i32 = 24;
pub static XA_OTCSV_RCS_PPS: i32 = 25;
pub static XA_OTCSV_RCS_OPS: i32 = 26;
pub static XA_OTCSV_SNR: i32 = 27;
pub static XA_OTCSV_BORE_AZ: i32 = 28;
pub static XA_OTCSV_BORE_EL: i32 = 29;
pub static XA_OTCSV_VISMAG: i32 = 30;
pub static XA_OTCSV_VISMAG_NORM: i32 = 31;
pub static XA_OTCSV_SOL_PHASE: i32 = 32;
pub static XA_OTCSV_FRAME: i32 = 33;
pub static XA_OTCSV_ABERRATION: i32 = 34;
pub static XA_OTCSV_ASTAT_METHOD: i32 = 35;
pub static XA_OTCSV_SIGMATYPE: i32 = 40;
pub static XA_OTCSV_SIGMAEL1: i32 = 41;
pub static XA_OTCSV_SIGMAEL2: i32 = 42;
pub static XA_OTCSV_SIGMAEL3: i32 = 43;
pub static XA_OTCSV_SIGMAEL4: i32 = 44;
pub static XA_OTCSV_SIGMAEL5: i32 = 45;
pub static XA_OTCSV_SIGMAEL6: i32 = 46;
pub static XA_OTCSV_SIGMAEL7: i32 = 47;
pub static XA_OTCSV_BIAS1: i32 = 48;
pub static XA_OTCSV_BIAS2: i32 = 49;
pub static XA_OTCSV_BIAS3: i32 = 50;
pub static XA_OTCSV_BIAS4: i32 = 51;
pub static XA_OTCSV_BIAS5: i32 = 52;
pub static XA_OTCSV_SIZE: i32 = 64;
pub static XA_OBSTATE_SATNUM: i32 = 0;
pub static XA_OBSTATE_SENNUM: i32 = 1;
pub static XA_OBSTATE_DS50UTC: i32 = 2;
pub static XA_OBSTATE_POSX: i32 = 10;
pub static XA_OBSTATE_POSY: i32 = 11;
pub static XA_OBSTATE_POSZ: i32 = 12;
pub static XA_OBSTATE_VELX: i32 = 13;
pub static XA_OBSTATE_VELY: i32 = 14;
pub static XA_OBSTATE_VELZ: i32 = 15;
pub static XA_OBSTATE_LAT: i32 = 16;
pub static XA_OBSTATE_LON: i32 = 17;
pub static XA_OBSTATE_HGHT: i32 = 18;
pub static XA_OBSTATE_POSE: i32 = 19;
pub static XA_OBSTATE_POSF: i32 = 20;
pub static XA_OBSTATE_POSG: i32 = 21;
pub static XA_OBSTATE_SIZE: i32 = 64;
pub static XA_OT0_RANGERATE: i32 = 7;
pub static XA_OT1_ELEVATION: i32 = 4;
pub static XA_OT1_AZIMUTH: i32 = 5;
pub static XA_OT2_ELEVATION: i32 = 4;
pub static XA_OT2_AZIMUTH: i32 = 5;
pub static XA_OT2_RANGE: i32 = 6;
pub static XA_OT3_ELEVATION: i32 = 4;
pub static XA_OT3_AZIMUTH: i32 = 5;
pub static XA_OT3_RANGE: i32 = 6;
pub static XA_OT3_RANGERATE: i32 = 7;
pub static XA_OT4_ELEVATION: i32 = 4;
pub static XA_OT4_AZIMUTH: i32 = 5;
pub static XA_OT4_RANGE: i32 = 6;
pub static XA_OT4_RANGERATE: i32 = 7;
pub static XA_OT4_ELRATE: i32 = 8;
pub static XA_OT4_AZRATE: i32 = 9;
pub static XA_OT4_RANGEACCEL: i32 = 10;
pub static XA_OT5_DECL: i32 = 4;
pub static XA_OT5_RIGHTASC: i32 = 5;
pub static XA_OT5_YROFEQNX: i32 = 22;
pub static XA_OT5_ABERRATION: i32 = 23;
pub static XA_OT6_RANGE: i32 = 6;
pub static XA_OT8_ELEVATION: i32 = 4;
pub static XA_OT8_AZIMUTH: i32 = 5;
pub static XA_OT8_RANGE: i32 = 6;
pub static XA_OT8_POSE: i32 = 16;
pub static XA_OT8_POSF: i32 = 17;
pub static XA_OT8_POSG: i32 = 18;
pub static XA_OT9_DECL: i32 = 4;
pub static XA_OT9_RIGHTASC: i32 = 5;
pub static XA_OT9_RANGE: i32 = 6;
pub static XA_OT9_POSE: i32 = 16;
pub static XA_OT9_POSF: i32 = 17;
pub static XA_OT9_POSG: i32 = 18;
pub static XA_OT9_YROFEQNX: i32 = 22;
pub static XA_OT9_ABERRATION: i32 = 23;
pub static XA_OTP_POSX: i32 = 16;
pub static XA_OTP_POSY: i32 = 17;
pub static XA_OTP_POSZ: i32 = 18;
pub static XA_OTV_POSX: i32 = 16;
pub static XA_OTV_POSY: i32 = 17;
pub static XA_OTV_POSZ: i32 = 18;
pub static XA_OTV_VELX: i32 = 19;
pub static XA_OTV_VELY: i32 = 20;
pub static XA_OTV_VELZ: i32 = 21;
pub static XA_OT_SIZE: i32 = 64;
pub static XA_SELOB_MODE: i32 = 0;
pub static XA_SELOB_FRTIME: i32 = 1;
pub static XA_SELOB_TOTIME: i32 = 2;
pub static XA_SELOB_FRIDX: i32 = 3;
pub static XA_SELOB_TOIDX: i32 = 4;
pub static XA_SELOB_SAT1: i32 = 11;
pub static XA_SELOB_SAT2: i32 = 12;
pub static XA_SELOB_SAT3: i32 = 13;
pub static XA_SELOB_SAT4: i32 = 14;
pub static XA_SELOB_SAT5: i32 = 15;
pub static XA_SELOB_SAT6: i32 = 16;
pub static XA_SELOB_SAT7: i32 = 17;
pub static XA_SELOB_SAT8: i32 = 18;
pub static XA_SELOB_SAT9: i32 = 19;
pub static XA_SELOB_SAT10: i32 = 20;
pub static XA_SELOB_SEN1: i32 = 21;
pub static XA_SELOB_SEN2: i32 = 22;
pub static XA_SELOB_SEN3: i32 = 23;
pub static XA_SELOB_SEN4: i32 = 24;
pub static XA_SELOB_SEN5: i32 = 25;
pub static XA_SELOB_SEN6: i32 = 26;
pub static XA_SELOB_SEN7: i32 = 27;
pub static XA_SELOB_SEN8: i32 = 28;
pub static XA_SELOB_SEN9: i32 = 29;
pub static XA_SELOB_SEN10: i32 = 30;
pub static XA_SELOB_OT1: i32 = 31;
pub static XA_SELOB_OT2: i32 = 32;
pub static XA_SELOB_OT3: i32 = 33;
pub static XA_SELOB_OT4: i32 = 34;
pub static XA_SELOB_OT5: i32 = 35;
pub static XA_SELOB_OT6: i32 = 36;
pub static XA_SELOB_OT7: i32 = 37;
pub static XA_SELOB_OT8: i32 = 38;
pub static XA_SELOB_OT9: i32 = 39;
pub static XA_SELOB_OT10: i32 = 40;
pub static XA_SELOB_FRAZ: i32 = 41;
pub static XA_SELOB_TOAZ: i32 = 42;
pub static XA_SELOB_FREL: i32 = 43;
pub static XA_SELOB_TOEL: i32 = 44;
pub static XA_SELOB_FRRA: i32 = 45;
pub static XA_SELOB_TORA: i32 = 46;
pub static XA_SELOB_FRDEC: i32 = 47;
pub static XA_SELOB_TODEC: i32 = 48;
pub static XA_SELOB_FRRNG: i32 = 49;
pub static XA_SELOB_TORNG: i32 = 50;
pub static XA_SELOB_FRRNGRT: i32 = 51;
pub static XA_SELOB_TORNGRT: i32 = 52;
pub static XA_SELOB_FRAZRT: i32 = 53;
pub static XA_SELOB_TOAZRT: i32 = 54;
pub static XA_SELOB_FRELRT: i32 = 55;
pub static XA_SELOB_TOELRT: i32 = 56;
pub static XA_SELOB_FRASTAT: i32 = 57;
pub static XA_SELOB_TOASTAT: i32 = 58;
pub static XA_SELOB_SIZE: i32 = 128;
pub struct ParsedB3 {
pub classification: String,
pub norad_id: i32,
pub sensor_number: i32,
pub epoch: f64,
pub elevation: Option<f64>,
pub declination: Option<f64>,
pub azimuth: Option<f64>,
pub right_ascension: Option<f64>,
pub range: Option<f64>,
pub range_rate: Option<f64>,
pub year_of_equinox: Option<i32>,
pub elevation_rate: Option<f64>,
pub azimuth_rate: Option<f64>,
pub range_acceleration: Option<f64>,
pub observation_type: i32,
pub track_position: i32,
pub association_status: i32,
pub site_tag: i32,
pub spadoc_tag: i32,
pub position: Option<[f64; 3]>,
}
impl Default for ParsedB3 {
fn default() -> Self {
ParsedB3 {
classification: String::from("U"),
norad_id: 99999,
sensor_number: 999,
epoch: 0.0,
elevation: None,
declination: Some(0.0),
azimuth: None,
right_ascension: Some(0.0),
range: None,
range_rate: None,
elevation_rate: None,
azimuth_rate: None,
range_acceleration: None,
observation_type: 9,
track_position: 3,
year_of_equinox: Some(EQUINOX_OBSTIME),
association_status: 4,
site_tag: 0,
spadoc_tag: 0,
position: None,
}
}
}
impl ParsedB3 {
fn _validate_fields(&self) -> Result<(), String> {
match self.observation_type {
0 => {
if self.range_rate.is_none() {
return Err(format!("Range rate is required for {:?}", self.observation_type));
}
}
1 => {
if self.elevation.is_none() {
return Err(format!("Elevation is required for {:?}", self.observation_type));
}
if self.azimuth.is_none() {
return Err(format!("Azimuth is required for {:?}", self.observation_type));
}
}
2 => {
if self.elevation.is_none() {
return Err(format!("Elevation is required for {:?}", self.observation_type));
}
if self.azimuth.is_none() {
return Err(format!("Azimuth is required for {:?}", self.observation_type));
}
if self.range.is_none() {
return Err(format!("Range is required for {:?}", self.observation_type));
}
}
3 => {
if self.elevation.is_none() {
return Err(format!("Elevation is required for {:?}", self.observation_type));
}
if self.azimuth.is_none() {
return Err(format!("Azimuth is required for {:?}", self.observation_type));
}
if self.range.is_none() {
return Err(format!("Range is required for {:?}", self.observation_type));
}
if self.range_rate.is_none() {
return Err(format!("Range rate is required for {:?}", self.observation_type));
}
}
4 => {
if self.elevation.is_none() {
return Err(format!("Elevation is required for {:?}", self.observation_type));
}
if self.azimuth.is_none() {
return Err(format!("Azimuth is required for {:?}", self.observation_type));
}
if self.range.is_none() {
return Err(format!("Range is required for {:?}", self.observation_type));
}
if self.range_rate.is_none() {
return Err(format!("Range rate is required for {:?}", self.observation_type));
}
if self.elevation_rate.is_none() {
return Err(format!("Elevation rate is required for {:?}", self.observation_type));
}
if self.azimuth_rate.is_none() {
return Err(format!("Azimuth rate is required for {:?}", self.observation_type));
}
if self.range_acceleration.is_none() {
return Err(format!(
"Range acceleration is required for {:?}",
self.observation_type
));
}
}
5 => {
if self.declination.is_none() {
return Err(format!("Declination is required for {:?}", self.observation_type));
}
if self.right_ascension.is_none() {
return Err(format!("Right ascension is required for {:?}", self.observation_type));
}
if self.year_of_equinox.is_none() {
return Err(format!("Year of equinox is required for {:?}", self.observation_type));
}
}
6 => {
if self.range.is_none() {
return Err(format!("Range is required for {:?}", self.observation_type));
}
}
8 => {
if self.elevation.is_none() {
return Err(format!("Elevation is required for {:?}", self.observation_type));
}
if self.azimuth.is_none() {
return Err(format!("Azimuth is required for {:?}", self.observation_type));
}
if self.position.is_none() {
return Err(format!(
"Sensor location position is required for {:?}",
self.observation_type
));
}
}
9 => {
if self.declination.is_none() {
return Err(format!("Declination is required for {:?}", self.observation_type));
}
if self.right_ascension.is_none() {
return Err(format!("Right ascension is required for {:?}", self.observation_type));
}
if self.position.is_none() {
return Err(format!(
"Sensor location position is required for {:?}",
self.observation_type
));
}
}
_ => {
return Err(format!("Unsupported observation type: {:?}", self.observation_type));
}
}
Ok(())
}
pub fn from_line(b3_string: &str) -> Result<Self, String> {
let mut input_str: GetSetString = b3_string.into();
let mut sec_char = GetSetString::new();
let mut sat_num: i32 = 0;
let mut sen_num: i32 = 0;
let mut obs_time_ds50utc: f64 = 0.0;
let mut el_or_dec: f64 = 0.0;
let mut az_or_ra: f64 = 0.0;
let mut slant_range: f64 = 0.0;
let mut range_rate_or_equinox: f64 = 0.0;
let mut el_rate: f64 = 0.0;
let mut az_rate: f64 = 0.0;
let mut range_accel: f64 = 0.0;
let mut obs_type = GetSetString::new();
let mut track_ind: i32 = 0;
let mut astat: i32 = 0;
let mut site_tag: i32 = 0;
let mut spadoc_tag: i32 = 0;
let mut pos: [f64; 3] = [0.0; 3];
let result = unsafe {
ObsB3Parse(
input_str.pointer(),
sec_char.pointer(),
&mut sat_num,
&mut sen_num,
&mut obs_time_ds50utc,
&mut el_or_dec,
&mut az_or_ra,
&mut slant_range,
&mut range_rate_or_equinox,
&mut el_rate,
&mut az_rate,
&mut range_accel,
obs_type.pointer(),
&mut track_ind,
&mut astat,
&mut site_tag,
&mut spadoc_tag,
&mut pos,
)
};
let obs_type_char: c_char = obs_type
.value()
.as_bytes()
.first()
.copied()
.unwrap_or(b'X') as c_char;
let b3_type = unsafe { ObsTypeCToI(obs_type_char) };
let mut azimuth: Option<f64> = None;
let mut right_ascension: Option<f64> = None;
let mut elevation: Option<f64> = None;
let mut declination: Option<f64> = None;
let mut year_of_equinox: Option<i32> = None;
let mut range_rate: Option<f64> = None;
let mut range: Option<f64> = None;
let mut elevation_rate: Option<f64> = None;
let mut azimuth_rate: Option<f64> = None;
let mut range_acceleration: Option<f64> = None;
let mut position: Option<[f64; 3]> = None;
match b3_type {
0 => {
range_rate = Some(range_rate_or_equinox);
}
1 => {
elevation = Some(el_or_dec);
azimuth = Some(az_or_ra);
}
2 => {
elevation = Some(el_or_dec);
azimuth = Some(az_or_ra);
range = Some(slant_range);
}
3 => {
elevation = Some(el_or_dec);
azimuth = Some(az_or_ra);
range = Some(slant_range);
range_rate = Some(range_rate_or_equinox);
}
4 => {
elevation = Some(el_or_dec);
azimuth = Some(az_or_ra);
range = Some(slant_range);
range_rate = Some(range_rate_or_equinox);
elevation_rate = Some(el_rate);
azimuth_rate = Some(az_rate);
range_acceleration = Some(range_accel);
}
5 => {
range = Some(slant_range);
declination = Some(el_or_dec);
right_ascension = Some(az_or_ra);
year_of_equinox = Some(range_rate_or_equinox as i32);
range_rate = None;
}
6 => {
range = Some(slant_range);
}
8 => {
elevation = Some(el_or_dec);
azimuth = Some(az_or_ra);
range = Some(slant_range);
position = Some(pos);
}
9 => {
declination = Some(el_or_dec);
right_ascension = Some(az_or_ra);
range = Some(slant_range);
year_of_equinox = Some(range_rate_or_equinox as i32);
position = Some(pos);
}
_ => {}
}
match result {
0 => Ok(ParsedB3 {
classification: sec_char.value().trim().to_string(),
norad_id: sat_num,
sensor_number: sen_num,
epoch: obs_time_ds50utc,
azimuth,
elevation,
declination,
right_ascension,
range,
range_rate,
elevation_rate,
azimuth_rate,
range_acceleration,
year_of_equinox,
observation_type: b3_type,
track_position: track_ind,
association_status: astat,
site_tag,
spadoc_tag,
position,
}),
_ => Err(get_last_error_message()),
}
}
fn get_az_or_ra(&self) -> f64 {
match self.observation_type {
1 | 2 | 3 | 4 | 8 => self.azimuth.unwrap(),
5 | 9 => self.right_ascension.unwrap(),
_ => 0.0,
}
}
fn get_el_or_dec(&self) -> f64 {
match self.observation_type {
1 | 2 | 3 | 4 | 8 => self.elevation.unwrap(),
5 | 9 => self.declination.unwrap(),
_ => 0.0,
}
}
fn get_range_rate_or_equinox(&self) -> f64 {
if self.observation_type == 5 || self.observation_type == 9 {
self.year_of_equinox.unwrap().into()
} else {
self.range_rate.unwrap_or(0.0)
}
}
pub fn get_line(&self) -> Result<String, String> {
self._validate_fields()?;
let mut output_str = GetSetString::new();
let ob_type: c_char = unsafe { ObsTypeIToC(self.observation_type) };
let sec_char: c_char = self
.classification
.as_bytes()
.first()
.copied()
.unwrap_or(b'U') as c_char;
unsafe {
ObsFieldsToB3Card(
sec_char,
self.norad_id,
self.sensor_number,
self.epoch,
self.get_el_or_dec(),
self.get_az_or_ra(),
self.range.unwrap_or(0.0),
self.get_range_rate_or_equinox(),
self.elevation_rate.unwrap_or(0.0),
self.azimuth_rate.unwrap_or(0.0),
self.range_acceleration.unwrap_or(0.0),
ob_type,
self.track_position,
self.association_status,
self.site_tag,
self.spadoc_tag,
&self.position.unwrap_or([0.0, 0.0, 0.0]),
output_str.pointer(),
)
};
Ok(output_str.value().trim().to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_lock::TEST_LOCK;
use approx::assert_abs_diff_eq;
fn base_parsed_b3(equinox: f64) -> ParsedB3 {
ParsedB3 {
classification: String::from("U"),
norad_id: 11111,
sensor_number: 500,
epoch: 25934.75,
declination: Some(-20.6075648583427),
right_ascension: Some(57.6850704027472),
range: Some(28002.6701345644),
range_rate: None,
azimuth: None,
elevation: None,
elevation_rate: None,
azimuth_rate: None,
year_of_equinox: Some(equinox as i32),
range_acceleration: None,
observation_type: 9,
track_position: 5,
association_status: 1,
site_tag: 11111,
spadoc_tag: 11111,
position: Some([0.0, 0.0, 0.0]),
}
}
#[test]
fn test_parsed_b3_get_line_year_of_equinox_indicator() {
let _lock = TEST_LOCK.lock().unwrap();
let cases = [
(
0.0,
"U1111150021001180000000K06076 0350444 9 5 11111111111",
),
(
1.0,
"U1111150021001180000000K06076 0350444 915 11111111111",
),
(
2.0,
"U1111150021001180000000K06076 0350444 925 11111111111",
),
(
3.0,
"U1111150021001180000000K06076 0350444 935 11111111111",
),
];
for (range_rate, expected) in cases {
let obs = base_parsed_b3(range_rate);
assert_eq!(obs.get_line().unwrap(), expected);
}
}
#[test]
fn test_parsed_b3_from_line_matches_fields() {
let _lock = TEST_LOCK.lock().unwrap();
let b3_card = "U0001151013352142520112J85202 2220398 -01207880+03706326+05814970 9 4 10001100011";
let parsed = ParsedB3::from_line(b3_card).unwrap();
let days = 352.0 + 14.0 / 24.0 + 25.0 / (60.0 * 24.0) + 20.112 / (60.0 * 60.0 * 24.0);
let right_ascen = (22.0 / 24.0 + 20.0 / (60.0 * 24.0) + 39.8 / (60.0 * 60.0 * 24.0)) * 360.0;
let obs_time = crate::time::year_doy_to_ds50(2013, days);
assert_eq!(parsed.classification, String::from("U"));
assert_eq!(parsed.norad_id, 11);
assert_eq!(parsed.sensor_number, 510);
assert_eq!(parsed.observation_type, 9);
assert_eq!(parsed.track_position, 4);
assert_eq!(parsed.association_status, 1);
assert_eq!(parsed.site_tag, 11);
assert_eq!(parsed.spadoc_tag, 11);
assert_abs_diff_eq!(parsed.epoch, obs_time, epsilon = 1.0e-7);
assert_abs_diff_eq!(parsed.declination.unwrap(), -18.5202, epsilon = 1.0e-7);
assert_abs_diff_eq!(parsed.right_ascension.unwrap(), right_ascen, epsilon = 1.0e-7);
assert_abs_diff_eq!(parsed.range.unwrap(), 0.0, epsilon = 1.0e-7);
assert_eq!(parsed.range_rate, None);
assert_eq!(parsed.elevation_rate, None);
assert_eq!(parsed.azimuth_rate, None);
assert_eq!(parsed.range_acceleration, None);
assert_abs_diff_eq!(parsed.position.unwrap()[0], -1207.88, epsilon = 1.0e-7);
assert_abs_diff_eq!(parsed.position.unwrap()[1], 3706.326, epsilon = 1.0e-7);
assert_abs_diff_eq!(parsed.position.unwrap()[2], 5814.97, epsilon = 1.0e-7);
}
}