=head NAME: TL_READIN_check_org_linewidth_spacing DESCRIPTION: 检查钻孔Pad大小. PARAMETER: {items => [ { name=>'check_list', label=>'CheckList名称', type=>'string', remark=>'CheckList名称', must_field=>1, }, { name=>'drill_summary_nact', label=>'Drill Summary CheckList编号', type=>'integer', remark=>'Drill Summary CheckList编号', must_field=>1, }, ]} VERSION_HISTORY: V1.00 2011-05-27 Tony Guo 1.新版本 V1.01 2016-09-26 mast 添加rill summary分析出错原因 V1.02 2016-10-18 John 更新INCAM和Genesis取分析结果错误的不同点。 V1.03 2017-02-22 Ferre Fixed Bug for Same Hole size with Both Via & PTH. V1.04 2018-09-10 Ferre Add SymmetricalDrill Check on Laser/Mech Type Define. V1.05 2019-04-20 mast 优化 2038 Echk tool PE定义drill infos=》 CAM根据PE信息,更改echk料号孔径 V1.06 2019-05-13 mast 优化 2051 在Read in item 33: Update drill info to database 1,程序判断出有laser drill on or close mechanical,邮件中带上如下信息,发自动邮件给PE CAM. (There is FV2 stack up which is forbidden in SHA plant.) 2,并推送EQ条目和建议。 V1.07 2019-05-20 mast 系统优化:2089 Checked with Spring Follow the same rule to identy the drill type on QEC stage the old rule : Hole size >=7mil , Type = mechanical hole Hole size <7mil , Type =laser hole The Revision: hole size >= 150um ,Type = mechanical hole hole size <150um ,Type = laser hole V1.08 2019-09-05 mast 系统优化:2293 分割孔带中的component_via属性,再上传原稿drill信息时,额外开一条记录,并且在数据库中勾选上laser_on_component 传PE 孔层时,按照ho12层合并到laser层中,如laser2-2,和合并到laser2-3 (4层板) V1.09 2020-04-02 john 优化 2749 存在非FV3结构,请联系Cassiel/8127设计新版本TCT及Efid coupon! V1.09 2020-06-08 john 优化 2843 存在FV2结构,暂停,让人工在判断一次! V1.10 2020-09-25 mast 优化 3224 show_form 窗口不输入值的时候可以继续运行 HELP:

功能简介

检查原稿最小线宽线距.


参数配置

● CheckList名称

设置CheckList名称.

● Drill Summary CheckList编号

设置Drill Summary CheckList编号.


=cut #use strict; #my ($JOB,$GEN,$GUI,$DB,$JOB_ID,$PAR,$APP,$MW); use utf8; use Encode; use Data::Dump 'dump'; my $Return = 'Done'; my $Job = $JOB.'_chk'; my $incam = 'no'; if ($GEN->{GEN_TYPE} =~/incam/i) { $incam = 'yes'; } my $max_drill=150/25.4; my @selstep; use_module('Top::MailSender'); my $customer = $ARGS{CUSTOMER}; try { if (!defined $Job or $Job =~ /^\s*$/){ $GUI->msgbox(-icon=>'error',-text=>'未定义料号名'); return 'Error'; } my $layercount = $GEN->getLayerCount(job=>$Job); my $half_layercount = $layercount/2 + 0.5; my $arrayhash = $DB->select_arrayhash(-table=>'job_org_layer', -field=>['drl_connect_to','drl_connect_point','tl_name'],-where=>{job_id=>$JOB_ID,type=>'drill'}); my @fv2_error; my @fv2_mail; my (@num_count,$Core_mark); foreach my $hash (@$arrayhash) { if ($hash->{tl_name} =~/^laser/) { if ($hash->{drl_connect_to} =~/^(ftdrill\d+\-\d+)$/) { if ($hash->{drl_connect_point}> 0){ push @fv2_error,$hash->{drl_connect_point}; push @fv2_mail, $hash->{drl_connect_to}.' touch '.$hash->{tl_name}." count $hash->{drl_connect_point}"; } } my ($tmp_START,$tmp_END) = $hash->{tl_name} =~/^laser(\d+)\-(\d+)/i; if ($tmp_START < $half_layercount and $tmp_END >$half_layercount) { $Core_mark = "yes"; } foreach my $tmp($tmp_START..$tmp_END){ push @num_count,$tmp if (!grep/^$tmp$/,@num_count); } } } if ( $customer eq '1352' and ($Core_mark ne "yes" or @num_count != $layercount)) { #$GUI->msgbox(-icon=>'info',-text=>"存在非FV3结构,请联系Cassiel/8127设计新版本TCT及Efid coupon!"); my $ans = $GUI->confirm("存在非FV3结构,请联系Cassiel/8127设计新版本TCT及Efid coupon,是否发送邮件?"); if ($ans eq "yes") { my $username =$GEN->getUserName(); my $subject = "$Job is not ncn strucutre , please contact with Cassiel design TCT and Efid Coupon"; my $body = "$Job is not ncn strucutre , please contact with Cassiel design TCT and Efid Coupon"; Top::MailSender->send_mail( subject => $subject, #to => 'john.sun@cn.ats.net,cassiel.zhang@cn.ats.net', # cc_user=>join(',',Top::MailSender->get_mail_list($PAR->{mail_group},'cc')), cc_user=>[$username], group => "1352_ncn_inform", # to =>'test1', body=>[$body], ); } } if (@fv2_error) { my $confirm = $GUI->msgbox(-title=>'Confirm',-text=>"判断是FV2,请确认是否OK。",-buttons=>['No'=>'no','Yes'=>'yes',"查看"=>'close']); if ($confirm eq "close") { while (1) { my $result = $GEN->PAUSE("Check Netlist"); if ($result eq "OK") { $confirm = $GUI->msgbox(-title=>'Confirm',-text=>"判断是FV2,请确认是否OK。",-buttons=>['No'=>'no','Yes'=>'yes',"查看"=>'close']); last if ($confirm ne "close"); }else{ last; } } } mail_sand_task(jobname=>$JOB, title=>'FV2_mail', subject=>"[$JOB]There is FV2 stack up which is forbidden in SHA plant", body=>join("
",@fv2_mail), sand_mode=>'always', ) if ($confirm eq "yes"); } # #@fv2_error=''; my $check_eq=$DB->get_job_engchk(-jobid=>$JOB_ID,-engchkitemid=>2180); #$GUI->debug("@fv2_error"); #$GUI->debug(dump \$check_eq); my $ENUM_ENGCHK_STATUS = $APP->{DB}->get_enum_hash(-category=>'enum_engchk_status'); my $eq_version = $DB->get_job_engchk_version(-jobid=>$JOB_ID); my ($exist_eq,$check_by_pe); my $mark_cam; my $item_max_version = $check_eq->{version}; foreach my $f (@{$check_eq->{problems}}){ if ($f->{selected}==1 and $item_max_version == $f->{version}){ #Replied #Check_Finish if ($ENUM_ENGCHK_STATUS->{$f->{enum_engchk_status}}{flow_order} >= $ENUM_ENGCHK_STATUS->{'Replied'}{flow_order}){ $check_by_pe ='yes'; } if ($ENUM_ENGCHK_STATUS->{$f->{enum_engchk_status}}{flow_order} >= $ENUM_ENGCHK_STATUS->{'Check_Finish'}{flow_order} and ($f->{enum_engchk_problem_type} =~/ok/i or $f->{enum_engchk_problem_type} =~/na/i)){ $check_by_pe ='yes'; } $exist_eq ='yes'; } } my $now = $APP->{DB}->get_now(); my $log = dump({who=>$APP->{USER_NAME},type=>'info',action=>'System update',date_time=>$now,remark=>'Create EQ'}).','; ####如果有问题,并且状态在cam这里,将直接删除后更新。 #$GUI->debug("$check_by_pe"); if (!$check_by_pe and $fv2_error[0]>0) { my $questions; $questions->{'question1'}{'value'}={quantity=>join(";",@fv2_error)}; if ($exist_eq eq 'yes') { if ($GUI->confirm("EQ:[$check_eq->{display_name}]\n已经存在,是否更新?") eq 'yes'){ foreach my $f (@{$check_eq->{problems}}){ #if ($f->{selected}==1 and ($f->{enum_engchk_problem_type} =~/ok/i or $f->{enum_engchk_problem_type} =~/na/i)){ save_job_engchk_question(-jobid=>$JOB_ID,-engchkitem=>'EQM_if_laser_drill_on_mechanical_hole',-log=>$log,-questions=>\%$questions,-delete=>'yes',-version=>$check_eq->{version}); $mark_cam='yes'; #next; #} } } } else{ save_job_engchk_question(-jobid=>$JOB_ID,-engchkitem=>'EQM_if_laser_drill_on_mechanical_hole',-log=>$log,-questions=>\%$questions,-delete=>'yes'); } } elsif ($check_by_pe eq 'yes'){ #$GUI->debug(dump \@{$check_eq->{problems}}); foreach my $f (@{$check_eq->{problems}}){ if (($f->{selected}==1 and ($f->{enum_engchk_problem_type} =~/ok/i or $f->{enum_engchk_problem_type} =~/na/i)) or @fv2_error){ #or ($f->{name} eq 'question1' and !$f->{selected}) my $questions; $questions->{'question1'}{'value'}={quantity=>join(";",@fv2_error)}; if ($ENUM_ENGCHK_STATUS->{$f->{enum_engchk_status}}{display_name}) { if ($GUI->confirm("EQ:[$check_eq->{display_name}]\n条目:$f->{display_name}\n并且为[$f->{enum_engchk_problem_type}]项目\n此EQ已经Follow PE EQ状态:[$ENUM_ENGCHK_STATUS->{$f->{enum_engchk_status}}{display_name}]\n是否升级更新?") eq 'yes'){ if ($eq_version >= $f->{version}){ my $eq_version1=$eq_version+1; save_job_engchk_question(-jobid=>$JOB_ID,-engchkitem=>'EQM_if_laser_drill_on_mechanical_hole',-version=>$eq_version1,-questions=>\%$questions); $mark_cam='yes'; } } } } } } elsif(!$exist_eq){ my $ok; $ok->{'na'}= 'ok'; save_job_engchk_question(-jobid=>$JOB_ID,-engchkitem=>'EQM_if_laser_drill_on_mechanical_hole',-log=>$log,-questions=>\%$ok); } if ($mark_cam) { $GUI->msgbox(-icon=>'info',-text=>"[$check_eq->{display_name}]有升级或刷新,请到[EQ-3 Drill check]workflow再次检查后follow EQ"); } #判断料号是否存在; unless ($GEN->isJobExists(job=>$Job)){ $GUI->msgbox(-icon=>'error',-text=>"料号[$Job]不存在!"); return 'Error'; } $GEN->openJob(job=>$Job); my @steps = $GEN->getStepList(job=>$Job); if (@steps != 1){ @selstep = $GUI->select_step(-title=>'请选择包含钻孔信息的Step',-steplist=>\@steps,-selectmode=>'multiple'); return 'Cancel' unless @selstep; } else{ @selstep = @steps; } $GEN->openStep(job=>$Job,name=>$selstep[0]); my @form_items; foreach my $item (@selstep){ my $tmp = { name=>$item, label=>$item, type=>'enum', must_field=>1, property=>{ tl_field=>['name'=>'scalar',display_name=>'text'], tl_value_field=>'name', tl_data=>[ {name=>'card',display_name=>'Card'}, {name=>'array',display_name=>'Array'}, #{name=>'coupon',display_name=>'Coupon'}, ] } }; push @form_items,$tmp; } my $stepinfo = $GUI->show_form(-title=>'请定义Step类型',-items=>\@form_items,-defaultsize=>[300,300],-showcheck => 1,-gen => $GEN,); return 'Cancel' unless $stepinfo; my $check_list = $PAR->{check_list}; my $matrix = $GEN->getMatrix(job=>$Job); my (@drill_layers,@signal_layers); foreach my $item (sort{$a->{row} <=> $b->{row}} values %$matrix){ if ($item->{context} eq 'board' and $item->{layer_type} eq 'drill'){ push @drill_layers,$item; } elsif ($item->{context} eq 'board' and $item->{layer_type} =~ /^(signal|power_ground|mixed)$/){ push @signal_layers,$item; } } my $num; foreach my $drill (@drill_layers){ $num++; $GEN->renameLayer(job=>$Job,layer=>$drill->{name},new_name=>$num.'_drill'); } $matrix = $GEN->getMatrix(job=>$Job); foreach my $layer (sort {$matrix->{$a}{row} <=> $matrix->{$b}{row}} keys %$matrix) { if ($layer =~/comp_\+_top|comp_\+_bot/i ){ $GEN->COM('delete_comp'); last; } } $matrix = $GEN->getMatrix(job=>$Job); @drill_layers=(); @signal_layers=(); foreach my $item (sort{$a->{row} <=> $b->{row}} values %$matrix){ if ($item->{context} eq 'board' and $item->{layer_type} eq 'drill'){ push @drill_layers,$item; } elsif ($item->{context} eq 'board' and $item->{layer_type} =~ /^(signal|power_ground|mixed)$/){ push @signal_layers,$item; } } ### Update check if Drill layer is only 1-2/2-3/... and Symetrical Type , like 1-10,2-9,3-8 ... (10 Layer for example) ### If YES $isSymmetricalDrill = 1, Else take is 0 ### SymmetricalDrill Means 1-10, 2-9 , should be Mech Hole, Even the hole size is < 7 mil my $isSymmetricalDrill = 1; foreach my $item (@drill_layers){ if (abs($item->{drl_start_num} - $item->{drl_end_num}) != 1 and $item->{drl_start_num} + $item->{drl_end_num} != $layercount + 1) { $isSymmetricalDrill = 0; last; } } foreach my $item (@drill_layers){ my $type = check_drill_hole_size($item->{name}); if ($item->{drl_start_num}<$half_layercount and $item->{drl_end_num} < $half_layercount and $type eq 'laser'){ $item->{tl_name} = 'laser'.$item->{drl_start_num}.'-'.$item->{drl_end_num}; $item->{tl_type} = 'laser_drill'; my @c_drls; foreach my $drl (@drill_layers){ if ($drl->{drl_start_num} == $item->{drl_end_num}){ push @c_drls,$drl, } } if (@c_drls){ my @tl_data = ({name=>'',tl_name=>''}); foreach my $it (@c_drls){ push @tl_data,{name=>$it->{name},tl_name=>$it->{tl_name}}; } my $tmp = { name=>$item->{name}, label=>$item->{name}, type=>'enum', property=>{ tl_field=>['name'=>'text',tl_name=>'scalar'], tl_value_field=>'tl_name', tl_data=>\@tl_data, } }; } } elsif($item->{drl_start_num}>$half_layercount and $item->{drl_end_num} > $half_layercount and $type eq 'laser'){ $item->{tl_name} = 'laser'.$item->{drl_start_num}.'-'.$item->{drl_end_num}; $item->{tl_type} = 'laser_drill'; my @c_drls; foreach my $drl (@drill_layers){ if ($drl->{drl_end_num} == $item->{drl_start_num}){ push @c_drls,$drl, } } if (@c_drls){ my @tl_data = ({name=>'',tl_name=>''}); foreach my $it (@c_drls){ push @tl_data,{name=>$it->{name},tl_name=>$it->{tl_name}}; } my $tmp = { name=>$item->{name}, label=>$item->{name}, type=>'enum', property=>{ tl_field=>['name'=>'text',tl_name=>'scalar'], tl_value_field=>'tl_name', tl_data=>\@tl_data, } }; } } else{ if ($item->{drl_start_num} == 1 and $item->{drl_end_num} == $layercount){ if ($isSymmetricalDrill) { $item->{tl_name} = 'drill'; $item->{tl_type} = 'main_drill'; }else { if ($type eq 'laser'){ $item->{tl_name} = 'laser'.$item->{drl_start_num}.'-'.$item->{drl_end_num}; $item->{tl_type} = 'laser_drill'; } elsif ($type eq 'mech'){ $item->{tl_name} = 'drill'; $item->{tl_type} = 'main_drill'; } else{ $item->{tl_name} = 'drill'; $item->{tl_type} = 'main_drill'; } } } else{ if ($isSymmetricalDrill and abs($item->{drl_start_num} - $item->{drl_end_num}) != 1) { $item->{tl_name} = 'drill'.$item->{drl_start_num}.'-'.$item->{drl_end_num}; $item->{tl_type} = 'bury_drill'; }else { my $singleType = check_hole_size($item->{name}); if ($singleType eq 'laser'){ $item->{tl_name} = 'laser'.$item->{drl_start_num}.'-'.$item->{drl_end_num}; $item->{tl_type} = 'laser_drill'; } else{ $item->{tl_name} = 'drill'.$item->{drl_start_num}.'-'.$item->{drl_end_num}; $item->{tl_type} = 'bury_drill'; } } } } } #$GUI->debug(dump \@drill_layers); # exit; $DB->delete(-table=>'job_org_layer_drillinfo',-where=>{job_id=>$JOB_ID}); foreach my $step (keys %$stepinfo){ $GEN->openStep(job=>$Job,name=>$step); return unless ($GEN->PAUSE("Please check the profile which used as check area!")); $GEN->openStep(job=>$Job,name=>$step); $GEN->units(type=>'inch'); my @check_list = $GEN->getChecklist(job=>$Job,step=>$step); if (! grep(/^\Q$check_list\E$/,@check_list)){ $GEN->chklistFromLib(chklist=>$check_list); } $GEN->chklistShow(chklist=>$check_list); $GEN->chklistRun(chklist=>$check_list,nact=>$PAR->{drill_summary_nact}); # return unless ($GEN->PAUSE("FERRE MANUAL Check REPORT!")); my @chkresult = $GEN->getCheckMeas(job=>$Job,step=>$step,chklist=>$check_list,nact=>$PAR->{drill_summary_nact}); my %error; if ($incam eq "no") { %error = $GEN->INFO(entity_type => 'check', entity_path => "$Job/$step/$check_list", data_type => 'STATUS', options => "action=$PAR->{drill_summary_nact}", ); }else{ %error = $GEN->INFO(entity_type => 'check', angle_direction=>'ccw', entity_path => "$Job/$step/$check_list", data_type => 'STATUS', options => "action=$PAR->{drill_summary_nact}", ); } if ($GEN->{doinfo}{gSTATUS} eq 'ERROR'){ $GUI->msgbox(-icon=>'error',-text=>"Drill summary分析出错,请检查Surface Analyzer,可能是surface问题造成"); exit; } my %pad_size; foreach my $item (@chkresult){ my @tmp = split(/ /,$item); next unless ($tmp[0] =~ /_(inner|outer)__(VIA|PTH)_(.*)_AR/); my ($drillname) = $tmp[0] =~ /^(.*)_(?:inner|outer)/; my $h_size = $tmp[4]; $h_size =~ s/r//i; my $p_size = $tmp[2]*2+$h_size; my $sig_layer = $tmp[1]; my $key = $drillname.':'.$h_size.':'.$sig_layer; my $exist_size = $pad_size{$key}{min_pad_size}; ## Fixed Bug for Same Hole size with Both Via & PTH, Ferre. 2017-02-22 if (! $exist_size or $exist_size > $p_size) { $pad_size{$key}{drill_name} = $drillname; $pad_size{$key}{hole_size} = $h_size; $pad_size{$key}{signal_layer} = $sig_layer; $pad_size{$key}{min_pad_size} = $p_size; $pad_size{$key}{px} = $tmp[6]; $pad_size{$key}{py} = $tmp[7]; } #unless ($pad_size{$key}{min_pad_size}){ # $pad_size{$key}{drill_name} = $drillname; # $pad_size{$key}{hole_size} = $h_size; # $pad_size{$key}{signal_layer} = $sig_layer; # $pad_size{$key}{min_pad_size} = $p_size; # $pad_size{$key}{px} = $tmp[6]; # $pad_size{$key}{py} = $tmp[7]; #} } #$GUI->debug(dump(\%pad_size)); # return unless ($GEN->PAUSE("FERRE check area!")); foreach my $sig_layer (@signal_layers){ $GEN->workLayer(name=>$sig_layer->{name},clear_before=>'yes'); foreach my $item (values %pad_size){ if ($item->{signal_layer} eq $sig_layer->{name}){ $GEN->selClearFeature(); $GEN->selectByFilter(feat_types=>'pad',intersect_area=>'yes',area_rect=>{x1=>$item->{px}-0.003,y1=>$item->{py}-0.003,x2=>$item->{px}+0.003,y2=>$item->{py}+0.003}); my @feats = $GEN->getFeatures(job=>$Job,step=>$step,layer=>$sig_layer->{name},options=>'select'); my @rpad; foreach my $feat (@feats){ if ($feat->{type} eq 'pad' and $feat->{symbol} =~ /^r(\d+(\.\d+)?)$/){ my ($s) = $feat->{symbol} =~ /^r(.*)$/; push @rpad,$s; } } foreach my $size (sort {$a<=>$b} @rpad) { if (abs ($size - $item->{min_pad_size}) <= 0.002 or $size > $item->{min_pad_size}) { $item->{min_pad_size} = $size; last; } } } } } my %drl_tools; my %num_plus; foreach my $drl (@drill_layers){ $GEN->openStep(job=>$Job,name=>$step); $GEN->units(type=>'inch'); $GEN->COM('tools_tab_reset'); $GEN->COM('tools_merge_ex',layer=>$drl->{name},mode=>'merge'); $GEN->COM('tools_set',layer=>$drl->{name},thickness=>0,user_params=>'',slots=>'by_length'); $GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$drl->{name},clear_before=>'yes'); $GEN->selectByFilter(attribute=>['component_via']); my $component_via_tmp = $drl->{tl_name}.'_ic_via'; _deleteLayer(step=>$step,layer=>[$component_via_tmp]); if ( $GEN->getSelectCount() > 0 ){ #$GEN->PAUSE("111111111111111"); $GEN->selMoveOther(target_layer=>$component_via_tmp,invert=>'no'); $GEN->matrixLayerAttr(job=>$Job,layer=>$component_via_tmp,type=>'drill'); my $tool_via_tmps = $GEN->getTool(job=>$Job,step=>$step,layer=>$component_via_tmp); my @drilled_layers; foreach my $sig_layer (@signal_layers){ if ($sig_layer->{tl_num} >= $drl->{drl_start_num} and $sig_layer->{tl_num} <= $drl->{drl_end_num}){ push @drilled_layers,$sig_layer->{name}; } } $num_plus{$drl->{tl_name}} = 0 unless ($num_plus{$drl->{tl_name}}); my $tmp=0; foreach my $tool (values %$tool_via_tmps){ if ($tool->{type} ne 'non_plated'){ foreach my $item (values %pad_size){ my $sig = $item->{signal_layer}; if ($item->{drill_name} eq $drl->{name} and abs($item->{hole_size} - $tool->{drill_size}) < 0.001) { $tool->{min_pad_size}{$matrix->{$item->{signal_layer}}{tl_name}} = $item->{min_pad_size}; } } } $tmp=$tool->{num} if ($tmp<$tool->{num}); my $slot=0; $slot = $tool->{slot_len} + $tool->{drill_size} if ($tool->{slot_len} !=0); $DB->insert(-table=>'job_org_layer_drillinfo', -data=>{ job_id => $JOB_ID, drill_tl_name => $drl->{tl_name}, step_type=>$stepinfo->{$step}, tool_num=>$tool->{num}+$num_plus{$drl->{tl_name}}, count => $tool->{count}, shape => $tool->{shape}, type => $tool->{type}, drill_size => $tool->{drill_size}, finish_size => $tool->{finish_size}==0?$tool->{drill_size}:$tool->{finish_size}, slot_length => $slot, min_pad_size => dump($tool->{min_pad_size}), max_drill_tol => $tool->{max_tol}, min_drill_tol => $tool->{min_tol}, laser_on_component=>'1', }, ); #$GEN->PAUSE("222222222 $drl->{tl_name}"); } $num_plus{$drl->{tl_name}}+=$tmp; _deleteLayer(step=>$step,layer=>[$component_via_tmp]); $GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$drl->{name},clear_before=>'yes'); $GEN->selectByFilter(); next if ( !$GEN->getSelectCount()); } $GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$drl->{name},clear_before=>'yes'); my $tools = $GEN->getTool(job=>$Job,step=>$step,layer=>$drl->{name}); my @drilled_layers; foreach my $sig_layer (@signal_layers){ if ($sig_layer->{tl_num} >= $drl->{drl_start_num} and $sig_layer->{tl_num} <= $drl->{drl_end_num}){ push @drilled_layers,$sig_layer->{name}; } } $num_plus{$drl->{tl_name}} = 0 unless ($num_plus{$drl->{tl_name}}); my $tmp=0; foreach my $tool (values %$tools){ if ($tool->{type} ne 'non_plated'){ foreach my $item (values %pad_size){ my $sig = $item->{signal_layer}; if ($item->{drill_name} eq $drl->{name} and abs($item->{hole_size} - $tool->{drill_size}) < 0.001) { $tool->{min_pad_size}{$matrix->{$item->{signal_layer}}{tl_name}} = $item->{min_pad_size}; } } } $tmp=$tool->{num} if ($tmp<$tool->{num}); my $slot=0; $slot = $tool->{slot_len} + $tool->{drill_size} if ($tool->{slot_len} !=0); $DB->insert(-table=>'job_org_layer_drillinfo', -data=>{ job_id => $JOB_ID, drill_tl_name => $drl->{tl_name}, step_type=>$stepinfo->{$step}, tool_num=>$tool->{num}+$num_plus{$drl->{tl_name}}, count => $tool->{count}, shape => $tool->{shape}, type => $tool->{type}, drill_size => $tool->{drill_size}, finish_size => $tool->{finish_size}==0?$tool->{drill_size}:$tool->{finish_size}, slot_length => $slot, min_pad_size => dump($tool->{min_pad_size}), max_drill_tol => $tool->{max_tol}, min_drill_tol => $tool->{min_tol}, }, ); #$GEN->PAUSE("111111111111111"); } $num_plus{$drl->{tl_name}}+=$tmp; if ($GEN->isLayerExists(job=>$Job,layer=>$component_via_tmp)){ $GEN->copyLayer(source_job=>$Job,source_step=>$step,source_layer=>$component_via_tmp,dest_layer=>$drl->{name},mode=>'append'); _deleteLayer(step=>$step,layer=>[$component_via_tmp]); } } $GEN->clearLayers(); $GEN->affectedLayer(mode=>'all',affected=>'no'); #$GEN->closeStep(); } my $jobpath = $GEN->getJobPath(job=>$Job); `chmod -R 777 $jobpath` if (-d $jobpath); $GEN->closeJob(job=>$Job); $GEN->openJob(job=>$Job); my $drill_info = $DB->get_jobinfo(-jobid=>$JOB_ID, -jobcategory=>'work', -jobinfo=>'pe_check_drill_info', #-jobinfo=>'mast1', ); $drill_info=eval($drill_info); my %drill_info; foreach my $ref (@$drill_info){ push @{$drill_info{$ref->{layer}}},{org_size=>$ref->{org_size},size=>$ref->{size}}; } if (keys %drill_info) { my $via_hole_um =500; my $v_tmp; my $layer_info = $DB->select_arrayhash( -table => 'job_org_layer_drillinfo', -where => "job_id = $JOB_ID ", -field=>['drill_tl_name','drill_size','type','shape'], ); my %laser; foreach my $ref (@$layer_info){ #next if ($ref->{drill_tl_name} eq 'drill'); if ($ref->{drill_tl_name} eq 'drill') { if ($ref->{type} ne 'non_plated' and $ref->{shape} ne 'slot' ) { my $r = $ref->{drill_size}*25.4; push @{$laser{$ref->{drill_tl_name}}},$r if (!grep /^$r$/,@{$laser{$ref->{drill_tl_name}}}); } } elsif ($ref->{drill_tl_name} =~/drill/ ){ my $r = $ref->{drill_size}*25.4; push @{$laser{$ref->{drill_tl_name}}},$r if (!grep /^$r$/,@{$laser{$ref->{drill_tl_name}}}); } else{ if ($ref->{drill_tl_name} =~/(\d+)\-(\d+)/) { #next if ($max_drill < $ref->{drill_size}); my $s=$1; my $e=$2; my $r = $ref->{drill_size}*25.4; if ($e==$s+1){ push @{$laser{$ref->{drill_tl_name}}},$r if (!grep /^$r$/,@{$laser{$ref->{drill_tl_name}}}); } else{ for my $n ($s..$e){ last if ($n == $e); my $n1=$n+1; my $tl_name ='laser'.$n.'-'.$n1; push @{$laser{$tl_name}},$r if (!grep /^$r$/,@{$laser{$tl_name}}); } } } } } #$GUI->debug(dump \%laser); my %sortdrill; foreach my $layer (keys %laser){ if ($layer eq 'drill'){ push @{$sortdrill{0}},$layer; } elsif ($layer=~/(\d+)/) { push @{$sortdrill{$1}},$layer; } } foreach my $n (sort {$a<=>$b} keys %sortdrill){ my @layers =@{$sortdrill{$n}}; foreach my $layer (@layers){ if ($layer eq 'drill' ){ foreach my $size (@{$laser{$layer}}) { if ($size > $via_hole_um) { my $new_size =$size +100; $new_size = sprintf("%.0f",$new_size); push @$v_tmp,{layer=>$layer,org_size=>$size,color=>'purple',size=>$new_size}; } else{ push @$v_tmp,{layer=>$layer,org_size=>$size,color=>'blue'}; } } } elsif ($layer =~/drill/ ){ foreach my $size (@{$laser{$layer}}) { push @$v_tmp,{layer=>$layer,org_size=>$size,color=>'red'}; } } else{ foreach my $size (@{$laser{$layer}}) { push @$v_tmp,{layer=>$layer,org_size=>$size,color=>'black'}; } } } } my %get_database_drill; foreach my $ref (@$v_tmp){ push @{$get_database_drill{$ref->{layer}}},{org_size=>$ref->{org_size},size=>$ref->{size}}; } # #$GUI->debug(dump \%drill_info); #$GUI->debug(dump \%get_database_drill); my @error; foreach my $tl_name (keys %get_database_drill){ if (@{$drill_info{$tl_name}}) { my @drill1s; foreach my $ref (@{$get_database_drill{$tl_name}}){ push @drill1s,$ref->{org_size}; } my @drill2s; foreach my $ref1 (@{$drill_info{$tl_name}}){ push @drill2s,$ref1->{org_size}; } my %seen=(); foreach (@drill1s){ $seen{$_}=1; } my @same=grep($seen{$_},@drill2s); my @diff=grep(!$seen{$_},@drill2s); if (@diff) { push @error,"$tl_name [@diff]和PE之前load的Drill Org信息不一样"; } } else{ push @error,"原稿孔层[$tl_name]和PE定义的Drill层名对不上"; } } #$GUI->msgbox(-icon=>'error',-text=>join("\n",@error)); if (@error) { my $sent_mail = join('
',@error)."
QEC孔层有更新,请再次检查PE预审信息中drill表"; mail_sand_task(jobname=>$JOB, title=>'pe_eq_info_update_drill', subject=>"Pls Update [$JOB] EQM Drill List in PE EQM PRE Info", body=>$sent_mail, sand_mode=>'always', ); } } unless ($GEN->{STATUS}){ return $Return; } else{ $GUI->msgbox(-icon=>'error',-text=>join("\n",@{$GEN->{STATUS}})); addFlowNotes(-notes=>" Genesis Error:\n ".join("\n ",@{$GEN->{STATUS}})); return 'Error'; } } catch Error::Simple with { my $error = encode("utf8",shift); $GUI->msgbox(-icon=>'error',-text=>$error); return 'Error'; } finally{ }; sub check_hole_size{ my $layer = shift; my @steps = $GEN->getStepList(job=>$Job); my $drill_type = 'mech'; foreach my $step (@selstep){ $GEN->COM('tools_tab_reset'); $GEN->COM('tools_merge_ex',layer=>$layer,mode=>'merge'); $GEN->COM('tools_set',layer=>$layer,thickness=>0,user_params=>'',slots=>'by_length'); my $tools = $GEN->getTool(job=>$Job,step=>$step,layer=>$layer); next unless (%$tools); foreach my $tool (values %$tools){ next if ($tool->{drill_size} ==0); if ($tool->{drill_size} < $max_drill){ $drill_type = 'laser'; last; } } last if $drill_type eq 'mech'; } return $drill_type; } sub check_drill_hole_size{ my $layer = shift; my @steps = $GEN->getStepList(job=>$Job); my $drill_type; foreach my $step (@selstep){ $GEN->COM('tools_tab_reset'); $GEN->COM('tools_set',layer=>$layer,thickness=>0,user_params=>'',slots=>'by_length'); my $tools = $GEN->getTool(job=>$Job,step=>$step,layer=>$layer); next unless (%$tools); foreach my $tool (values %$tools){ next if ($tool->{drill_size} ==0); if ($tool->{drill_size} < $max_drill and $drill_type !~/laser/){ $drill_type.= 'laser'; } elsif ($tool->{drill_size} >= $max_drill and $drill_type !~/mech/){ $drill_type.='mech'; } } } return $drill_type; } sub mail_sand_task { my %par = @_; ## subject ##body ## title my $mailinfo=$DB->select_hash(-table=>'ats_mail_sand_task',-where=>{mail_title=>$par{title}}); if ($mailinfo->{status} eq 'Start'){ my $mail_to=$mailinfo->{mail_to}; my $mail_cc=$mailinfo->{mail_cc}; if ($mail_to=~/^sub/){ $mail_to=eval($mail_to); $mail_to= $mail_to->(job_id=>$job_id); } else{ $mail_to=eval($mail_to) if ($mail_to=~/^\$/); } if ($mail_cc=~/^sub/){ $mail_cc=eval($mail_cc); $mail_cc= $mail_cc->(job_id=>$job_id); } else{ $mail_cc=eval($mail_cc) if ($mail_cc=~/^\$/); } my @to = split(/\;|\:|\,|\n/,$mail_to); foreach my $it (@to){ $it =~ s/(^\s+|\s+$)//g; } $par{-to} = \@to; #$data{cc} =~ s/\s+//g; my @cc = split(/\;|\:|\,|\n/,$mail_cc); foreach my $it (@cc){ $it =~ s/(^\s+|\s+$)//g; } $par{-cc} = \@cc; $par{cc_user}=''; $par{group}=''; #$GUI->debug("@to m @cc "); my $subject=$par{subject}; my $body = $par{body}; my $mail_version = $DB->select_value( -table=>'ats_auto_mail_record', -field=>'max(mail_version)', -where=>"job_id = $JOB_ID and mail_title = '$par{title}'", ); $mail_version = 0 unless ($mail_version); $mail_version++; my $resart_mail= 'yes'; if ($mail_version > 1 and $par{sand_mode} ne 'always' ){ my $tmp_v=$mail_version-1; my $mail_subject = $DB->select_value( -table=>'ats_auto_mail_record', -field=>'mail_subject', -where=>"job_id = $JOB_ID and mail_title = '$par{title}' and mail_version = $tmp_v", ); my $mail_body = $DB->select_value( -table=>'ats_auto_mail_record', -field=>'mail_content', -where=>"job_id = $JOB_ID and mail_title = '$par{title}' and mail_version = $tmp_v", ); if ($mail_subject eq $subject){ $resart_mail='no'; if ($mail_body ne $body){ $resart_mail='yes'; } } elsif ($mail_body ne $body){ $resart_mail='yes'; } } #$GUI->debug(dump\%par); #exit; if ($resart_mail eq 'yes'){ Top::MailSender->send_mail(%par); my ($content,$att); if (ref $par{body} eq 'ARRAY') { ($content,$att) = @{$par{body}}; } else { $content = $par{body}; } if ($att) { my @att = @{$att}; if (@att) { $att = join(',',@att); $att = '' unless ($att); }else { $att = ''; } } else { $att = ''; } $DB->insert( -table=>'ats_auto_mail_record', -data=>{ job_id => $JOB_ID, mail_from=>$APP->{USER_NAME}, mail_to=>$mail_to, mail_cc=>$mail_cc, mail_subject=>$par{subject}, mail_title=>$par{title}, mail_content=>$content, mail_attachment=>$att, mail_version=>$mail_version, } ); } } } sub save_job_engchk_question{ my %par = @_; $par{-version} = $DB->get_job_engchk_version(-jobid=>$par{-jobid}) unless $par{-version}; my $chkitem_id = $DB->select_value(-table=>'engchk_chkitem',-field=>'id',-where=>{name=>$par{-engchkitem}}); return unless $chkitem_id; my $prob_ids = $DB->select_fieldarray(-table=>'engchk_problem',-field=>'id',-where=>{engchk_chkitem_id=>$chkitem_id}); my $prob_hash = $DB->select_hashhash(-table=>'engchk_problem',-field=>'*',-hashkey=>'name',-where=>{engchk_chkitem_id=>$chkitem_id}); my $err; my $now = $DB->get_now(); $DB->begin(); $DB->delete(-table=>'job_engchk',-where=>{job_id=>$par{-jobid},version=>$par{-version},engchk_problem_id=>$prob_ids}) if ($par{-delete}); foreach my $prob_name (keys %{$par{-questions}}){ #$GUI->debug("$prob_name"); my $tmp = { job_id=>$par{-jobid}, engchk_problem_id=>$prob_hash->{$prob_name}{id}, version=>$par{-version}, enum_engchk_status=>$par{-questions}->{$prob_name}{enum_engchk_status}||'New', enum_engchk_problem_type=>$prob_hash->{$prob_name}{enum_engchk_problem_type}, enum_engchk_affected_tooling =>$prob_hash->{$prob_name}{enum_engchk_affected_tooling}, enum_engchk_problem_report_to =>$prob_hash->{$prob_name}{enum_engchk_problem_report_to}, log=>$par{-log}, }; $par{-questions}->{$prob_name}{text} = $prob_hash->{$prob_name}{problem_detail} unless defined $par{-questions}->{$prob_name}{text}; $par{-questions}->{$prob_name}{language} = $prob_hash->{$prob_name}{enum_display_name_language} unless defined $par{-questions}->{$prob_name}{language}; $par{-questions}->{$prob_name}{editable} = $prob_hash->{$prob_name}{editable} unless defined $par{-questions}->{$prob_name}{editable}; #$tmp->{question} = dump($par{-questions}->{$prob_name}); $tmp->{question_text} = (defined $par{-questions}->{$prob_name}{text})?$par{-questions}->{$prob_name}{text}:$prob_hash->{$prob_name}{problem_detail}; $tmp->{question_value} = $par{-questions}->{$prob_name}{value}?dump($par{-questions}->{$prob_name}{value}):undef; $tmp->{question_attachment} = $par{-questions}->{$prob_name}{attachment}?dump($par{-questions}->{$prob_name}{attachment}):undef; $tmp->{question_user} = $par{-questions}->{$prob_name}{user} || $APP->{USER_FULL_NAME}; $tmp->{question_timestamp} = $par{-questions}->{$prob_name}{timestamp} || $now; #$GUI->debug(dump \$tmp); $DB->update_with_insert(-table=>'job_engchk',-data=>$tmp,-where=>['job_id','engchk_problem_id','version']); #save_job_engchk_question $err = $DB->err; last if $err; } if ($err){ $DB->rollback; return $err; } else{ $DB->commit; return 0; } } sub _deleteLayer{ my %par = @_; foreach my $layer(@{$par{layer}}){ $GEN->deleteLayer(layer=>$layer) if ($GEN->isLayerExists(job=>$Job,layer=>$layer)); } $GEN->openStep(job=>$Job,name=>$par{step}) if ($par{step}); }