use self::atdf_record_field::*;
use crate::{stdf_error::StdfError, stdf_record_type::*, *};
use chrono::NaiveDateTime;
use std::collections::hash_map::HashMap;
macro_rules! ser_optional {
($struct_name:ident.$field:ident, $method:ident) => {
if let Some(ref $field) = $struct_name.$field {
$field.$method()
} else {
String::new()
}
};
(&$struct_name:ident.$field:ident, $method:ident()) => {
if let Some(ref $field) = $struct_name.$field {
$method(&$field)
} else {
String::new()
}
};
}
pub(crate) mod atdf_record_field {
pub(crate) const FAR_FIELD: [(&str, bool); 4] = [
("FileType", true),
("STDF_VER", true),
("ATDFVer", true),
("ScaleFlag", false),
];
pub(crate) const ATR_FIELD: [(&str, bool); 2] = [("MOD_TIM", false), ("CMD_LINE", false)];
pub(crate) const MIR_FIELD: [(&str, bool); 38] = [
("LOT_ID", true),
("PART_TYP", true),
("JOB_NAM", true),
("NODE_NAM", true),
("TSTR_TYP", true),
("SETUP_T", true),
("START_T", true),
("OPER_NAM", true),
("MODE_COD", true),
("STAT_NUM", true),
("SBLOT_ID", false),
("TEST_COD", false),
("RTST_COD", false),
("JOB_REV", false),
("EXEC_TYP", false),
("EXEC_VER", false),
("PROT_COD", false),
("CMOD_COD", false),
("BURN_TIM", false),
("TST_TEMP", false),
("USER_TXT", false),
("AUX_FILE", false),
("PKG_TYP", false),
("FAMLY_ID", false),
("DATE_COD", false),
("FACIL_ID", false),
("FLOOR_ID", false),
("PROC_ID", false),
("OPER_FRQ", false),
("SPEC_NAM", false),
("SPEC_VER", false),
("FLOW_ID", false),
("SETUP_ID", false),
("DSGN_REV", false),
("ENG_ID", false),
("ROM_COD", false),
("SERL_NUM", false),
("SUPR_NAM", false),
];
pub(crate) const MRR_FIELD: [(&str, bool); 4] = [
("FINISH_T", true),
("DISP_COD", false),
("USR_DESC", false),
("EXC_DESC", false),
];
pub(crate) const PCR_FIELD: [(&str, bool); 7] = [
("HEAD_NUM", true),
("SITE_NUM", true),
("PART_CNT", false),
("RTST_CNT", false),
("ABRT_CNT", false),
("GOOD_CNT", false),
("FUNC_CNT", false),
];
pub(crate) const HBR_FIELD: [(&str, bool); 6] = [
("HEAD_NUM", true),
("SITE_NUM", true),
("HBIN_NUM", true),
("HBIN_CNT", true),
("HBIN_PF", false),
("HBIN_NAM", false),
];
pub(crate) const SBR_FIELD: [(&str, bool); 6] = [
("HEAD_NUM", true),
("SITE_NUM", true),
("SBIN_NUM", true),
("SBIN_CNT", true),
("SBIN_PF", false),
("SBIN_NAM", false),
];
pub(crate) const PMR_FIELD: [(&str, bool); 7] = [
("PMR_INDX", true),
("CHAN_TYP", false),
("CHAN_NAM", false),
("PHY_NAM", false),
("LOG_NAM", false),
("HEAD_NUM", false),
("SITE_NUM", false),
];
pub(crate) const PGR_FIELD: [(&str, bool); 3] =
[("GRP_INDX", true), ("GRP_NAM", false), ("PMR_INDX", false)];
pub(crate) const PLR_FIELD: [(&str, bool); 5] = [
("GRP_INDX", true),
("GRP_MODE", false),
("GRP_RADX", false),
("PGM_CHAL,PGM_CHAR", false),
("RTN_CHAL,RTN_CHAR", false),
];
pub(crate) const RDR_FIELD: [(&str, bool); 1] = [("RTST_BIN", false)];
pub(crate) const SDR_FIELD: [(&str, bool); 19] = [
("HEAD_NUM", true),
("SITE_GRP", true),
("SITE_NUM", true),
("HAND_TYP", false),
("HAND_ID", false),
("CARD_TYP", false),
("CARD_ID", false),
("LOAD_TYP", false),
("LOAD_ID", false),
("DIB_TYP", false),
("DIB_ID", false),
("CABL_TYP", false),
("CABL_ID", false),
("CONT_TYP", false),
("CONT_ID", false),
("LASR_TYP", false),
("LASR_ID", false),
("EXTR_TYP", false),
("EXTR_ID", false),
];
pub(crate) const WIR_FIELD: [(&str, bool); 4] = [
("HEAD_NUM", true),
("START_T", true),
("SITE_GRP", false),
("WAFER_ID", false),
];
pub(crate) const WRR_FIELD: [(&str, bool); 14] = [
("HEAD_NUM", true),
("FINISH_T", true),
("PART_CNT", true),
("WAFER_ID", false),
("SITE_GRP", false),
("RTST_CNT", false),
("ABRT_CNT", false),
("GOOD_CNT", false),
("FUNC_CNT", false),
("FABWF_ID", false),
("FRAME_ID", false),
("MASK_ID", false),
("USR_DESC", false),
("EXC_DESC", false),
];
pub(crate) const WCR_FIELD: [(&str, bool); 9] = [
("WF_FLAT", false),
("POS_X", false),
("POS_Y", false),
("WAFR_SIZ", false),
("DIE_HT", false),
("DIE_WID", false),
("WF_UNITS", false),
("CENTER_X", false),
("CENTER_Y", false),
];
pub(crate) const PIR_FIELD: [(&str, bool); 2] = [("HEAD_NUM", true), ("SITE_NUM", true)];
pub(crate) const PRR_FIELD: [(&str, bool); 14] = [
("HEAD_NUM", true),
("SITE_NUM", true),
("PART_ID", true),
("NUM_TEST", true),
("Pass/Fail", true),
("HARD_BIN", true),
("SOFT_BIN", false),
("X_COORD", false),
("Y_COORD", false),
("RetestCode", false),
("AbortCode", false),
("TEST_T", false),
("PART_TXT", false),
("PART_FIX", false),
];
pub(crate) const TSR_FIELD: [(&str, bool); 15] = [
("HEAD_NUM", true),
("SITE_NUM", true),
("TEST_NUM", true),
("TEST_NAM", false),
("TEST_TYP", false),
("EXEC_CNT", false),
("FAIL_CNT", false),
("ALRM_CNT", false),
("SEQ_NAME", false),
("TEST_LBL", false),
("TEST_TIM", false),
("TEST_MIN", false),
("TEST_MAX", false),
("TST_SUMS", false),
("TST_SQRS", false),
];
pub(crate) const PTR_FIELD: [(&str, bool); 20] = [
("TEST_NUM", true),
("HEAD_NUM", true),
("SITE_NUM", true),
("RESULT", false),
("Pass/Fail", false),
("AlarmFlags", false),
("TEST_TXT", false),
("ALARM_ID", false),
("LimitCompare", false),
("UNITS", false),
("LO_LIMIT", false),
("HI_LIMIT", false),
("C_RESFMT", false),
("C_LLMFMT", false),
("C_HLMFMT", false),
("LO_SPEC", false),
("HI_SPEC", false),
("RES_SCAL", false),
("LLM_SCAL", false),
("HLM_SCAL", false),
];
pub(crate) const MPR_FIELD: [(&str, bool); 25] = [
("TEST_NUM", true),
("HEAD_NUM", true),
("SITE_NUM", true),
("RTN_STAT", false),
("RTN_RSLT", false),
("Pass/Fail", false),
("AlarmFlags", false),
("TEST_TXT", false),
("ALARM_ID", false),
("LimitCompare", false),
("UNITS", false),
("LO_LIMIT", false),
("HI_LIMIT", false),
("START_IN", false),
("INCR_IN", false),
("UNITS_IN", false),
("RTN_INDX", false),
("C_RESFMT", false),
("C_LLMFMT", false),
("C_HLMFMT", false),
("LO_SPEC", false),
("HI_SPEC", false),
("RES_SCAL", false),
("LLM_SCAL", false),
("HLM_SCAL", false),
];
pub(crate) const FTR_FIELD: [(&str, bool); 26] = [
("TEST_NUM", true),
("HEAD_NUM", true),
("SITE_NUM", true),
("Pass/Fail", true),
("AlarmFlags", false),
("VECT_NAM", false),
("TIME_SET", false),
("CYCL_CNT", false),
("REL_VADR", false),
("REPT_CNT", false),
("NUM_FAIL", false),
("XFAIL_AD", false),
("YFAIL_AD", false),
("VECT_OFF", false),
("RTN_INDX", false),
("RTN_STAT", false),
("PGM_INDX", false),
("PGM_STAT", false),
("FAIL_PIN", false),
("OP_CODE", false),
("TEST_TXT", false),
("ALARM_ID", false),
("PROG_TXT", false),
("RSLT_TXT", false),
("PATG_NUM", false),
("SPIN_MAP", false),
];
pub(crate) const BPS_FIELD: [(&str, bool); 1] = [("SEQ_NAME", false)];
pub(crate) const EPS_FIELD: [(&str, bool); 0] = [];
pub(crate) const GDR_FIELD: [(&str, bool); 0] = [];
pub(crate) const DTR_FIELD: [(&str, bool); 1] = [("TEST_DAT", false)];
pub(crate) const INVALID_FIELD: [(&str, bool); 0] = [];
}
#[derive(Debug)]
pub struct AtdfRecord {
rec_name: String,
type_code: u64,
scale_flag: bool, data_map: HashMap<String, String>,
}
impl From<&AtdfRecord> for StdfRecord {
#[inline(always)]
fn from(atdf_rec: &AtdfRecord) -> Self {
if atdf_rec.scale_flag {}
StdfRecord::new(atdf_rec.type_code)
}
}
impl AtdfRecord {
#[inline(always)]
pub fn from_atdf_string(
atdf_str: &str,
delim: char,
scale_flag: bool,
) -> Result<Self, StdfError> {
let (rec_name, rec_data) = atdf_str.split_once(':').unwrap_or(("", atdf_str));
let type_code = get_code_from_rec_name(rec_name);
if type_code == REC_INVALID {
return Err(StdfError {
code: 2,
msg: format!(
"Unrecognized record name {}, remaining data {}",
rec_name, rec_data
),
});
}
let field_data: Vec<&str> = rec_data.split(delim).collect();
let field_name = get_atdf_fields(type_code);
if field_data.len() < count_reqired(field_name) {
return Err(StdfError {
code: 2,
msg: format!(
"{} record has {} required fields, only {} found in {:?}",
rec_name,
count_reqired(field_name),
field_data.len(),
field_data
),
});
}
let data_map = if type_code == REC_GDR {
(0..field_data.len())
.zip(field_data)
.map(|(i, d)| (i.to_string(), d.to_string()))
.collect()
} else {
field_name
.iter()
.enumerate()
.map(|(i, &(fname, _))| {
(
fname.to_string(),
field_data.get(i).unwrap_or(&"").to_string(),
)
})
.collect()
};
Ok(AtdfRecord {
rec_name: rec_name.to_string(),
type_code,
scale_flag,
data_map,
})
}
#[inline(always)]
pub fn to_atdf_string(&self) -> String {
let field_name = get_atdf_fields(self.type_code);
let rec_data = if self.type_code == REC_GDR {
(0..self.data_map.len())
.map(|num| num.to_string())
.map(|num_str| {
self.data_map
.get(&num_str)
.unwrap_or(&String::from(""))
.clone()
})
.collect::<Vec<String>>()
.join("|")
} else {
field_name
.iter()
.map(|&(nam, _b)| self.data_map.get(nam).unwrap_or(&String::from("")).clone())
.collect::<Vec<String>>()
.join("|")
};
format!("{}:{}", self.rec_name, rec_data)
}
}
impl From<&StdfRecord> for AtdfRecord {
#[inline(always)]
fn from(stdf_rec: &StdfRecord) -> Self {
let type_code;
let rec_name;
let atdf_fields: &[(&str, bool)];
let data_list;
match stdf_rec {
StdfRecord::PTR(rec) => {
type_code = REC_PTR;
rec_name = "PTR".to_string();
atdf_fields = &PTR_FIELD;
data_list = atdf_data_from_ptr(rec);
}
StdfRecord::MPR(rec) => {
type_code = REC_MPR;
rec_name = "MPR".to_string();
atdf_fields = &MPR_FIELD;
data_list = atdf_data_from_mpr(rec);
}
StdfRecord::FTR(rec) => {
type_code = REC_FTR;
rec_name = "FTR".to_string();
atdf_fields = &FTR_FIELD;
data_list = atdf_data_from_ftr(rec);
}
StdfRecord::PIR(rec) => {
type_code = REC_PIR;
rec_name = "PIR".to_string();
atdf_fields = &PIR_FIELD;
data_list = atdf_data_from_pir(rec);
}
StdfRecord::PRR(rec) => {
type_code = REC_PRR;
rec_name = "PRR".to_string();
atdf_fields = &PRR_FIELD;
data_list = atdf_data_from_prr(rec);
}
StdfRecord::WIR(rec) => {
type_code = REC_WIR;
rec_name = "WIR".to_string();
atdf_fields = &WIR_FIELD;
data_list = atdf_data_from_wir(rec);
}
StdfRecord::WRR(rec) => {
type_code = REC_WRR;
rec_name = "WRR".to_string();
atdf_fields = &WRR_FIELD;
data_list = atdf_data_from_wrr(rec);
}
StdfRecord::WCR(rec) => {
type_code = REC_WCR;
rec_name = "WCR".to_string();
atdf_fields = &WCR_FIELD;
data_list = atdf_data_from_wcr(rec);
}
StdfRecord::GDR(rec) => {
type_code = REC_GDR;
rec_name = "GDR".to_string();
atdf_fields = &GDR_FIELD;
data_list = atdf_data_from_gdr(rec);
}
StdfRecord::DTR(rec) => {
type_code = REC_DTR;
rec_name = "DTR".to_string();
atdf_fields = &DTR_FIELD;
data_list = atdf_data_from_dtr(rec);
}
StdfRecord::TSR(rec) => {
type_code = REC_TSR;
rec_name = "TSR".to_string();
atdf_fields = &TSR_FIELD;
data_list = atdf_data_from_tsr(rec);
}
StdfRecord::MIR(rec) => {
type_code = REC_MIR;
rec_name = "MIR".to_string();
atdf_fields = &MIR_FIELD;
data_list = atdf_data_from_mir(rec);
}
StdfRecord::MRR(rec) => {
type_code = REC_MRR;
rec_name = "MRR".to_string();
atdf_fields = &MRR_FIELD;
data_list = atdf_data_from_mrr(rec);
}
StdfRecord::PCR(rec) => {
type_code = REC_PCR;
rec_name = "PCR".to_string();
atdf_fields = &PCR_FIELD;
data_list = atdf_data_from_pcr(rec);
}
StdfRecord::HBR(rec) => {
type_code = REC_HBR;
rec_name = "HBR".to_string();
atdf_fields = &HBR_FIELD;
data_list = atdf_data_from_hbr(rec);
}
StdfRecord::SBR(rec) => {
type_code = REC_SBR;
rec_name = "SBR".to_string();
atdf_fields = &SBR_FIELD;
data_list = atdf_data_from_sbr(rec);
}
StdfRecord::PMR(rec) => {
type_code = REC_PMR;
rec_name = "PMR".to_string();
atdf_fields = &PMR_FIELD;
data_list = atdf_data_from_pmr(rec);
}
StdfRecord::PGR(rec) => {
type_code = REC_PGR;
rec_name = "PGR".to_string();
atdf_fields = &PGR_FIELD;
data_list = atdf_data_from_pgr(rec);
}
StdfRecord::PLR(rec) => {
type_code = REC_PLR;
rec_name = "PLR".to_string();
atdf_fields = &PLR_FIELD;
data_list = atdf_data_from_plr(rec);
}
StdfRecord::RDR(rec) => {
type_code = REC_RDR;
rec_name = "RDR".to_string();
atdf_fields = &RDR_FIELD;
data_list = atdf_data_from_rdr(rec);
}
StdfRecord::SDR(rec) => {
type_code = REC_SDR;
rec_name = "SDR".to_string();
atdf_fields = &SDR_FIELD;
data_list = atdf_data_from_sdr(rec);
}
StdfRecord::FAR(rec) => {
type_code = REC_FAR;
rec_name = "FAR".to_string();
atdf_fields = &FAR_FIELD;
data_list = atdf_data_from_far(rec);
}
StdfRecord::ATR(rec) => {
type_code = REC_ATR;
rec_name = "ATR".to_string();
atdf_fields = &ATR_FIELD;
data_list = atdf_data_from_atr(rec);
}
StdfRecord::BPS(rec) => {
type_code = REC_BPS;
rec_name = "BPS".to_string();
atdf_fields = &BPS_FIELD;
data_list = atdf_data_from_bps(rec);
}
StdfRecord::EPS(rec) => {
type_code = REC_EPS;
rec_name = "EPS".to_string();
atdf_fields = &EPS_FIELD;
data_list = atdf_data_from_eps(rec);
}
_ => {
type_code = REC_INVALID;
rec_name = "INVALID".to_string();
atdf_fields = &INVALID_FIELD;
data_list = vec![];
}
};
AtdfRecord {
rec_name,
type_code,
scale_flag: false, data_map: if type_code == REC_GDR {
create_atdf_gdr_map(data_list)
} else {
create_atdf_map_from_fields_and_data(atdf_fields, data_list)
},
}
}
}
#[inline(always)]
pub(crate) fn get_atdf_fields(rec_type: u64) -> &'static [(&'static str, bool)] {
match rec_type {
REC_FAR => &FAR_FIELD,
REC_ATR => &ATR_FIELD,
REC_MIR => &MIR_FIELD,
REC_MRR => &MRR_FIELD,
REC_PCR => &PCR_FIELD,
REC_HBR => &HBR_FIELD,
REC_SBR => &SBR_FIELD,
REC_PMR => &PMR_FIELD,
REC_PGR => &PGR_FIELD,
REC_PLR => &PLR_FIELD,
REC_RDR => &RDR_FIELD,
REC_SDR => &SDR_FIELD,
REC_WIR => &WIR_FIELD,
REC_WRR => &WRR_FIELD,
REC_WCR => &WCR_FIELD,
REC_PIR => &PIR_FIELD,
REC_PRR => &PRR_FIELD,
REC_TSR => &TSR_FIELD,
REC_PTR => &PTR_FIELD,
REC_MPR => &MPR_FIELD,
REC_FTR => &FTR_FIELD,
REC_BPS => &BPS_FIELD,
REC_EPS => &EPS_FIELD,
REC_GDR => &GDR_FIELD,
REC_DTR => &DTR_FIELD,
_ => &INVALID_FIELD,
}
}
#[inline(always)]
pub(crate) fn count_reqired(p_arr: &[(&str, bool)]) -> usize {
p_arr
.iter()
.fold(0, |cnt: usize, (_, b)| cnt + (*b as usize))
}
#[inline(always)]
pub(crate) fn atdf_data_from_ptr(rec: &PTR) -> Vec<String> {
let test_bits = flag_to_array(&rec.test_flg);
let parm_bits = flag_to_array(&rec.parm_flg);
let mut alarm_flags = "".to_string();
if test_bits[0] == 1 {
alarm_flags.push('A')
}
if test_bits[2] == 1 {
alarm_flags.push('U')
}
if test_bits[3] == 1 {
alarm_flags.push('T')
}
if test_bits[4] == 1 {
alarm_flags.push('N')
}
if test_bits[5] == 1 {
alarm_flags.push('X')
}
if parm_bits[0] == 1 {
alarm_flags.push('S')
}
if parm_bits[1] == 1 {
alarm_flags.push('D')
}
if parm_bits[2] == 1 {
alarm_flags.push('O')
}
if parm_bits[3] == 1 {
alarm_flags.push('H')
}
if parm_bits[4] == 1 {
alarm_flags.push('L')
}
vec![
rec.test_num.to_string(), rec.head_num.to_string(), rec.site_num.to_string(), rec.result.to_string(), if parm_bits[5] == 1 {
"A".to_string()
} else if test_bits[6] | test_bits[7] == 0 {
"P".to_string()
} else if test_bits[6] == 1 {
"".to_string()
} else {
"F".to_string()
},
alarm_flags, rec.test_txt.clone(), rec.alarm_id.clone(), if parm_bits[6] | parm_bits[7] == 0 {
"".to_string()
} else if parm_bits[6] == 1 {
">=".to_string()
} else {
"<=".to_string()
},
ser_optional!(rec.units, clone), ser_optional!(rec.lo_limit, to_string), ser_optional!(rec.hi_limit, to_string), ser_optional!(rec.c_resfmt, clone), ser_optional!(rec.c_llmfmt, clone), ser_optional!(rec.c_hlmfmt, clone), ser_optional!(rec.lo_spec, to_string), ser_optional!(rec.hi_spec, to_string), ser_optional!(rec.res_scal, to_string), ser_optional!(rec.llm_scal, to_string), ser_optional!(rec.hlm_scal, to_string), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_mpr(rec: &MPR) -> Vec<String> {
let test_bits = flag_to_array(&rec.test_flg);
let parm_bits = flag_to_array(&rec.parm_flg);
let mut alarm_flags = "".to_string();
if test_bits[0] == 1 {
alarm_flags.push('A')
}
if test_bits[2] == 1 {
alarm_flags.push('U')
}
if test_bits[3] == 1 {
alarm_flags.push('T')
}
if test_bits[4] == 1 {
alarm_flags.push('N')
}
if test_bits[5] == 1 {
alarm_flags.push('X')
}
if parm_bits[0] == 1 {
alarm_flags.push('S')
}
if parm_bits[1] == 1 {
alarm_flags.push('D')
}
if parm_bits[2] == 1 {
alarm_flags.push('O')
}
if parm_bits[3] == 1 {
alarm_flags.push('H')
}
if parm_bits[4] == 1 {
alarm_flags.push('L')
}
vec![
rec.test_num.to_string(), rec.head_num.to_string(), rec.site_num.to_string(), ser_kx_digit_hex(&rec.rtn_stat), ser_stdf_kx_data(&rec.rtn_rslt), if parm_bits[5] == 1 {
"A".to_string()
} else if test_bits[6] | test_bits[7] == 0 {
"P".to_string()
} else if test_bits[6] == 1 {
"".to_string()
} else {
"F".to_string()
},
alarm_flags, rec.test_txt.clone(), rec.alarm_id.clone(), if parm_bits[6] | parm_bits[7] == 0 {
"".to_string()
} else if parm_bits[6] == 1 {
">=".to_string()
} else {
"<=".to_string()
},
ser_optional!(rec.units, clone), ser_optional!(rec.lo_limit, to_string), ser_optional!(rec.hi_limit, to_string), ser_optional!(rec.start_in, to_string), ser_optional!(rec.incr_in, to_string), ser_optional!(rec.units_in, clone), ser_optional!(&rec.rtn_indx, ser_stdf_kx_data()), ser_optional!(rec.c_resfmt, clone), ser_optional!(rec.c_llmfmt, clone), ser_optional!(rec.c_hlmfmt, clone), ser_optional!(rec.lo_spec, to_string), ser_optional!(rec.hi_spec, to_string), ser_optional!(rec.res_scal, to_string), ser_optional!(rec.llm_scal, to_string), ser_optional!(rec.hlm_scal, to_string), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_ftr(rec: &FTR) -> Vec<String> {
let test_bits = flag_to_array(&rec.test_flg);
let mut alarm_flags = "".to_string();
if test_bits[0] == 1 {
alarm_flags.push('A')
}
if test_bits[2] == 1 {
alarm_flags.push('N')
}
if test_bits[3] == 1 {
alarm_flags.push('T')
}
if test_bits[4] == 1 {
alarm_flags.push('U')
}
if test_bits[5] == 1 {
alarm_flags.push('X')
}
vec![
rec.test_num.to_string(), rec.head_num.to_string(), rec.site_num.to_string(), if test_bits[6] | test_bits[7] == 0 {
"P".to_string()
} else if test_bits[6] == 1 {
"".to_string()
} else {
"F".to_string()
},
alarm_flags, rec.vect_nam.clone(), rec.time_set.clone(), rec.cycl_cnt.to_string(), rec.rel_vadr.to_string(), rec.rept_cnt.to_string(), rec.num_fail.to_string(), rec.xfail_ad.to_string(), rec.yfail_ad.to_string(), rec.vect_off.to_string(), ser_stdf_kx_data(&rec.rtn_indx), ser_kx_digit_hex(&rec.rtn_stat), ser_stdf_kx_data(&rec.pgm_indx), ser_kx_digit_hex(&rec.pgm_stat), ser_stdf_kx_data(&rec.fail_pin), rec.op_code.clone(), rec.test_txt.clone(), rec.alarm_id.clone(), rec.prog_txt.clone(), rec.rslt_txt.clone(), rec.patg_num.to_string(), ser_stdf_kx_data(&rec.spin_map), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_pir(rec: &PIR) -> Vec<String> {
vec![
rec.head_num.to_string(), rec.site_num.to_string(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_prr(rec: &PRR) -> Vec<String> {
let flg_bits = flag_to_array(&rec.part_flg);
vec![
rec.head_num.to_string(), rec.site_num.to_string(), rec.part_id.clone(), rec.num_test.to_string(), if flg_bits[3] | flg_bits[4] == 0 {
"P".to_string()
} else {
"F".to_string()
},
rec.hard_bin.to_string(), rec.soft_bin.to_string(), rec.x_coord.to_string(), rec.y_coord.to_string(), if flg_bits[0] | flg_bits[1] != 0 {
if flg_bits[0] != 0 {
"I".to_string()
} else {
"C".to_string()
}
} else {
"".to_string()
},
if flg_bits[2] == 0 {
"".to_string()
} else {
"Y".to_string()
},
rec.test_t.to_string(), rec.part_txt.clone(), ser_bn_dn(&rec.part_fix), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_wir(rec: &WIR) -> Vec<String> {
vec![
rec.head_num.to_string(), rec.start_t.to_string(), rec.site_grp.to_string(), rec.wafer_id.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_wrr(rec: &WRR) -> Vec<String> {
vec![
rec.head_num.to_string(), rec.finish_t.to_string(), rec.part_cnt.to_string(), rec.wafer_id.clone(), rec.site_grp.to_string(), rec.rtst_cnt.to_string(), rec.abrt_cnt.to_string(), rec.good_cnt.to_string(), rec.func_cnt.to_string(), rec.fabwf_id.clone(), rec.frame_id.clone(), rec.mask_id.clone(), rec.usr_desc.clone(), rec.exc_desc.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_wcr(rec: &WCR) -> Vec<String> {
vec![
rec.wf_flat.to_string(), rec.pos_x.to_string(), rec.pos_y.to_string(), rec.wafr_siz.to_string(), rec.die_ht.to_string(), rec.die_wid.to_string(), rec.wf_units.to_string(), rec.center_x.to_string(), rec.center_y.to_string(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_gdr(rec: &GDR) -> Vec<String> {
let mut gen_data_list = vec![];
for v1_data in &rec.gen_data {
match v1_data {
V1::U1(u1) => gen_data_list.push(format!("U{}", u1)),
V1::U2(u2) => gen_data_list.push(format!("M{}", u2)),
V1::U4(u4) => gen_data_list.push(format!("B{}", u4)),
V1::I1(i1) => gen_data_list.push(format!("I{}", i1)),
V1::I2(i2) => gen_data_list.push(format!("S{}", i2)),
V1::I4(i4) => gen_data_list.push(format!("L{}", i4)),
V1::R4(r4) => gen_data_list.push(format!("F{}", r4)),
V1::R8(r8) => gen_data_list.push(format!("D{}", r8)),
V1::Cn(cn) => gen_data_list.push(format!("T{}", cn)),
V1::Bn(bn) => gen_data_list.push(format!("X{}", ser_bn_dn(bn))),
V1::Dn(dn) => gen_data_list.push(format!("Y{}", ser_bn_dn(dn))),
V1::N1(n1) => gen_data_list.push(format!("N{}", n1)),
_ => {
continue;
}
}
}
gen_data_list
}
#[inline(always)]
pub(crate) fn atdf_data_from_dtr(rec: &DTR) -> Vec<String> {
vec![
rec.text_dat.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_tsr(rec: &TSR) -> Vec<String> {
vec![
if rec.head_num == 255 {
"".to_string()
} else {
rec.head_num.to_string()
},
if rec.site_num == 255 {
"".to_string()
} else {
rec.site_num.to_string()
},
rec.test_num.to_string(), rec.test_nam.clone(), rec.test_typ.to_string(), rec.exec_cnt.to_string(), rec.fail_cnt.to_string(), rec.alrm_cnt.to_string(), rec.seq_name.clone(), rec.test_lbl.clone(), rec.test_tim.to_string(), rec.test_min.to_string(), rec.test_max.to_string(), rec.tst_sums.to_string(), rec.tst_sqrs.to_string(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_mir(rec: &MIR) -> Vec<String> {
vec![
rec.lot_id.clone(), rec.part_typ.clone(), rec.job_nam.clone(), rec.node_nam.clone(), rec.tstr_typ.clone(), NaiveDateTime::from_timestamp_opt(rec.setup_t as i64, 0)
.expect("invalid or out-of-range datetime")
.format("%H:%M:%S %d-%b-%Y")
.to_string(), NaiveDateTime::from_timestamp_opt(rec.start_t as i64, 0)
.expect("invalid or out-of-range datetime")
.format("%H:%M:%S %d-%b-%Y")
.to_string(), rec.oper_nam.clone(), rec.mode_cod.to_string(), rec.stat_num.to_string(), rec.sblot_id.clone(), rec.test_cod.clone(), rec.rtst_cod.to_string(), rec.job_rev.clone(), rec.exec_typ.clone(), rec.exec_ver.clone(), rec.prot_cod.to_string(), rec.cmod_cod.to_string(), rec.burn_tim.to_string(), rec.tst_temp.clone(), rec.user_txt.clone(), rec.aux_file.clone(), rec.pkg_typ.clone(), rec.famly_id.clone(), rec.date_cod.clone(), rec.facil_id.clone(), rec.floor_id.clone(), rec.proc_id.clone(), rec.oper_frq.clone(), rec.spec_nam.clone(), rec.spec_ver.clone(), rec.flow_id.clone(), rec.setup_id.clone(), rec.dsgn_rev.clone(), rec.eng_id.clone(), rec.rom_cod.clone(), rec.serl_num.clone(), rec.supr_nam.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_mrr(rec: &MRR) -> Vec<String> {
vec![
NaiveDateTime::from_timestamp_opt(rec.finish_t as i64, 0)
.expect("invalid or out-of-range datetime")
.format("%H:%M:%S %d-%b-%Y")
.to_string(), rec.disp_cod.to_string(), rec.usr_desc.clone(), rec.exc_desc.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_pcr(rec: &PCR) -> Vec<String> {
vec![
if rec.head_num == 255 {
"".to_string()
} else {
rec.head_num.to_string()
}, if rec.site_num == 255 {
"".to_string()
} else {
rec.site_num.to_string()
}, rec.part_cnt.to_string(), rec.rtst_cnt.to_string(), rec.abrt_cnt.to_string(), rec.good_cnt.to_string(), rec.func_cnt.to_string(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_hbr(rec: &HBR) -> Vec<String> {
vec![
if rec.head_num == 255 {
"".to_string()
} else {
rec.head_num.to_string()
}, if rec.site_num == 255 {
"".to_string()
} else {
rec.site_num.to_string()
}, rec.hbin_num.to_string(), rec.hbin_cnt.to_string(), rec.hbin_pf.to_string(), rec.hbin_nam.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_sbr(rec: &SBR) -> Vec<String> {
vec![
if rec.head_num == 255 {
"".to_string()
} else {
rec.head_num.to_string()
}, if rec.site_num == 255 {
"".to_string()
} else {
rec.site_num.to_string()
}, rec.sbin_num.to_string(), rec.sbin_cnt.to_string(), rec.sbin_pf.to_string(), rec.sbin_nam.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_pmr(rec: &PMR) -> Vec<String> {
vec![
rec.pmr_indx.to_string(), rec.chan_typ.to_string(), rec.chan_nam.clone(), rec.phy_nam.clone(), rec.log_nam.clone(), rec.head_num.to_string(), rec.site_num.to_string(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_pgr(rec: &PGR) -> Vec<String> {
vec![
rec.grp_indx.to_string(), rec.grp_nam.clone(), ser_stdf_kx_data(&rec.pmr_indx), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_plr(rec: &PLR) -> Vec<String> {
let radx_func = |x: u8| match x {
2 => "B",
8 => "O",
10 => "D",
16 => "H",
20 => "S",
_ => "",
};
let grp_mode = rec
.grp_mode
.iter()
.map(|&x| format!("{:X}", x))
.collect::<Vec<String>>()
.join(",");
let grp_radx = rec
.grp_radx
.iter()
.map(|&x| radx_func(x).to_string())
.collect::<Vec<String>>()
.join(",");
fn not_empty(v: &[String]) -> bool {
v.iter().map(|s| s.len()).fold(0, std::cmp::max) > 0
}
fn combine_l_r(cha_l: &[String], cha_r: &[String]) -> String {
let chal_not_empty = not_empty(cha_l);
let char_not_empty = not_empty(cha_r);
if chal_not_empty | char_not_empty {
let mut state_list = vec![];
if chal_not_empty {
for (string_l, string_r) in cha_l.iter().zip(cha_r.iter()) {
let mut tmp_pin_state = "".to_string();
for (ind, (c_l, c_r)) in string_l.chars().zip(string_r.chars()).enumerate() {
if ind != 0 {
tmp_pin_state.push(',');
}
tmp_pin_state.push(c_l);
tmp_pin_state.push(c_r);
}
state_list.push(tmp_pin_state);
}
} else {
cha_r
.iter()
.map(|s| {
s.chars()
.map(|c| c.to_string())
.collect::<Vec<String>>()
.join(",")
})
.map(|pin_state| state_list.push(pin_state))
.count();
}
state_list.join("/")
} else {
"".to_string()
}
}
vec![
ser_stdf_kx_data(&rec.grp_indx), grp_mode, grp_radx, combine_l_r(&rec.pgm_chal, &rec.pgm_char), combine_l_r(&rec.rtn_chal, &rec.rtn_char), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_rdr(rec: &RDR) -> Vec<String> {
vec![
ser_stdf_kx_data(&rec.rtst_bin), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_sdr(rec: &SDR) -> Vec<String> {
vec![
rec.head_num.to_string(), rec.site_grp.to_string(), ser_stdf_kx_data(&rec.site_num), rec.hand_typ.clone(), rec.hand_id.clone(), rec.card_typ.clone(), rec.card_id.clone(), rec.load_typ.clone(), rec.load_id.clone(), rec.dib_typ.clone(), rec.dib_id.clone(), rec.cabl_typ.clone(), rec.cabl_id.clone(), rec.cont_typ.clone(), rec.cont_id.clone(), rec.lasr_typ.clone(), rec.lasr_id.clone(), rec.extr_typ.clone(), rec.extr_id.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_far(rec: &FAR) -> Vec<String> {
vec![
"A".to_string(), rec.stdf_ver.to_string(), "2".to_string(), "U".to_string(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_atr(rec: &ATR) -> Vec<String> {
vec![
NaiveDateTime::from_timestamp_opt(rec.mod_tim as i64, 0)
.expect("invalid or out-of-range datetime")
.format("%H:%M:%S %d-%b-%Y")
.to_string(), rec.cmd_line.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_bps(rec: &BPS) -> Vec<String> {
vec![
rec.seq_name.clone(), ]
}
#[inline(always)]
pub(crate) fn atdf_data_from_eps(_rec: &EPS) -> Vec<String> {
vec![]
}
#[inline(always)]
fn create_atdf_map_from_fields_and_data(
fields: &[(&str, bool)],
data_list: Vec<String>,
) -> HashMap<String, String> {
fields
.iter()
.zip(data_list)
.map(|(&(fname, _), d)| (fname.to_string(), d))
.collect::<HashMap<String, String>>()
}
#[inline(always)]
fn create_atdf_gdr_map(data_list: Vec<String>) -> HashMap<String, String> {
(0..data_list.len())
.zip(data_list)
.map(|(num, d)| (num.to_string(), d))
.collect::<HashMap<String, String>>()
}
#[inline(always)]
fn ser_stdf_kx_data<T: ToString>(kx: &[T]) -> String {
kx.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join(",")
}
#[inline(always)]
fn ser_kx_digit_hex(kx: &[u8]) -> String {
kx.iter()
.map(|&x| format!("{:X}", x))
.collect::<Vec<String>>()
.join(",")
}
#[inline(always)]
fn flag_to_array(flag: &[u8; 1]) -> Vec<u8> {
let mut flag = flag[0];
let mut bits = Vec::with_capacity(8);
for _ in 0..8 {
bits.push(flag & 1u8);
flag >>= 1;
}
bits
}
#[inline(always)]
fn ser_bn_dn(d: &[u8]) -> String {
hex::encode_upper(d)
}