`
lovnet
  • 浏览: 6690433 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

EAGLE CAD转换到protel pcb文件的方法

 
阅读更多

网上有出现过很多中方法,这里提供一种直接通过ulp文件转换的方法,包含安装文件下载链接:http://download.csdn.net/detail/fzxy002763/4169994

主要就是一个转换pcb.ulp文件,文件具体内容如后文

#usage	"<b>Export PCB project to Protel .PCBDOC (ASCII)</b>"
        "<p>"
        "This ULP script tries to export PCB file which can be opened by Protel. "
        "It is probably not bug-free as well as it seems to be impossible to export "
        "with 100% accuracy so use at your own risk and check the results carefully."
        "<p>"
        "<b>Bugs</b>"
        "<p>"
        "Units are always English for now.<br>"
        "Polygons are not exported.<br>"
        "Vias are always exported round. Protel does not have other via shapes.<br>"
        "Board outline is lost and must be restored from Mechanical 1 (Protel DXP only).<br>"
        "Not all layers exported correctly.<br>"
        "<p>"
        "<b>Important Notice</b>\n"
        "<p>"
        "This script is NOT designed to replace Protel. "
        "As Protel file format is proprietary, "
        "use of this script for purposes other than migrating from Eagle to Protel "
        "may be illegal due to copyright laws. The author will not be liable for any illegal "
        "use of this script."
        "<p>"
        "<version>Version: 0.1</version>"
        "<p>"
	"<author>Author: Alex Galakhov avg6f4@umkc.edu</author>"


// Global variables

string fileName;

string netn [];
string layer [];

int x0, y0;

// Units

int usedunits;
string units [] = { "mil", "mm" };

// PCB record handling functions

string record (string name) 
  {
    return "|RECORD=" + name;
  }

string endr ()
  {
    return "\r\n";
  }

string r_b (string name, int val)
  {
    return "|" + name + "=" + (val ? "TRUE" : "FALSE");
  }

string r_l (string name, int val, int v0)
  {
    real value;
    value = (usedunits == 0 ? u2mil (val - v0) : u2mm (val - v0));
    string s;
    sprintf (s, "|%s=%g%s", name, value, units [usedunits]);
    return s;
  }

string r_i (string name, int val)
  {
    string s;
    sprintf (s, "|%s=%d", name, val);
    return s;
  }

string r_f (string name, real val)
  {
    string s;
    sprintf (s, "|%s=%g", name, val);
    return s;
  }

string r_s (string name, string val)
  {
    return "|" + name + "=" + val;
  }

string r_layer (string name, int lay)
  {
    return "|" + name + "=" + layer [lay];
  }

string ra_net (int n)
  {
    if (n == -1) return "";
    return r_i ("NET", n);
  }

string ra_comp (int c)
  {
    if (c == -1) return "";
    return r_i ("COMPONENT", c);
  }

int fixwidth (int w)
  {
    return ((w == 0) ? 2540 : w);
  }


// PCB data storage

string arcs = "";
string comps = "";
string fills = "";
string header = "";
string nets = "";
string pads = "";
string texts = "";
string tracks = "";
string vias = "";

int arcs_c = 0;
int comps_c = 0;
int fills_c = 0;
int nets_c = 0;
int pads_c = 0;
int texts_c = 0;
int tracks_c = 0;
int vias_c = 0;

int netbyname (string netname)
  {
    int i;
    for (i = 0; (i < nets_c) && (netname != netn [i]); i++) { }
    if (netn [i] != netname) i = -1; // we should never get it unless there's a bug
    return i;
  }

// PCB writing functions

void out_arc (UL_ARC a, int n, int c)
  {                
    arcs += record ("Arc") + ra_net (n) + ra_comp (c)
           + r_i ("INDEXFORSAVE", arcs_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", a.layer)
           + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) 
           + r_l ("LOCATION.X", a.xc, x0) + r_l ("LOCATION.Y", a.yc, y0) + r_l ("RADIUS", a.radius, 0)
           + r_f ("STARTANGLE", a.angle1) + r_f ("ENDANGLE", a.angle2) + r_l ("WIDTH", fixwidth (a.width), 0)
           + r_i ("SUBPOLYINDEX", 0)
         + endr ();
    arcs_c ++;
  }

void out_circle (UL_CIRCLE a, int c)
  {
    arcs += record ("Arc") + ra_comp (c)
           + r_i ("INDEXFORSAVE", arcs_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", a.layer)
           + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) 
           + r_l ("LOCATION.X", a.x, x0) + r_l ("LOCATION.Y", a.y, y0) + r_l ("RADIUS", a.radius, 0)
           + r_f ("STARTANGLE", 0) + r_f ("ENDANGLE", 360) + r_l ("WIDTH", fixwidth (a.width), 0)
           + r_i ("SUBPOLYINDEX", 0)
         + endr ();
    arcs_c ++;
  }

void out_track (UL_WIRE w, int n, int c)
  {
    if (w.arc)
      {
        out_arc (w.arc, n, c);
        return;
      }
    tracks += record ("Track") + ra_net (n) + ra_comp (c)
             + r_i ("INDEXFORSAVE", tracks_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", w.layer)
             + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1)
             + r_l ("X1", w.x1, x0) + r_l ("Y1", w.y1, y0) + r_l ("X2", w.x2, x0) + r_l ("Y2", w.y2, y0) 
             + r_l ("WIDTH", fixwidth (w.width), 0) + r_i ("SUBPOLYINDEX", 0)
           + endr ();
    tracks_c ++;
  }

void out_via (UL_VIA v, int n, int c)
  {
    vias += record ("Via") + ra_net (n) + ra_comp (c)
           + r_i ("INDEXFORSAVE", vias_c) + r_b ("SELECTION", 0) + r_s ("LAYER", "MULTILAYER")
           + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + r_l ("X", v.x, x0) + r_l ("Y", v.y, y0)
           + r_l ("DIAMETER", max (v.diameter [v.start], v.diameter [v.end]), 0)
           + r_l ("HOLESIZE", v.drill, 0) + r_layer ("STARTLAYER", v.start) + r_layer ("ENDLAYER", v.end)
        // + r_i ("CCSV", 1) + r_i ("CPLV", 1) + r_i ("CCWV", 1) + r_i ("CAGV", 1) + r_i ("CPEV", 0)
        // + r_i ("CSEV", 0) + r_i ("CPCV", 1) + r_i ("CPRV", 1) + r_s ("CCS", "Relief") + r_s ("CPL", 0)
        // + r_l ("CCW", 10mil) + r_i ("CEN", 4) + r_l ("CAG", 10mil) + r_l ("CSE", 4mil) 
        // + r_l ("CPC", 20mil) + r_l ("CPR", 20mil)
        // I don't know what it menas so I don't use them
         + endr ();
    vias_c ++;
  }

void out_pad (UL_PAD p, int n, int c)
  {
    string psh [];
      psh [PAD_SHAPE_SQUARE]  = "RECTANGLE";
      psh [PAD_SHAPE_ROUND]   = "ROUND";
      psh [PAD_SHAPE_OCTAGON] = "OCTAGONAL";
      psh [PAD_SHAPE_LONG]    = "OCTAGONAL";
      psh [PAD_SHAPE_OFFSET]  = "bug"; //!
      psh [PAD_SHAPE_ANNULUS] = "bug"; //!
      psh [PAD_SHAPE_THERMAL] = "bug"; //!
    pads += record ("Pad") + ra_net (n) + ra_comp (c)
           + r_i ("INDEXFORSAVE", pads_c)
           + r_s ("LAYER", "MULTILAYER") + r_b ("LOCKED", 0) + r_b ("USERROUTED", 1) + r_s ("NAME", p.name)
           + r_l ("X", p.x, x0) + r_l ("Y", p.y, y0)
           + r_l ("XSIZE", p.diameter [LAYER_BOTTOM] * (1 + p.elongation / 100), 0) + r_l ("YSIZE", p.diameter [LAYER_BOTTOM], 0)
           + r_s ("SHAPE", psh [p.shape [LAYER_BOTTOM]]) + r_l ("HOLESIZE", p.drill, 0) + r_f ("ROTATION", p.angle)
           + r_b ("PLATED", 1)
        // + r_s ("DAISYCHAIN", "Load")
        // + ... ... ...
         + endr ();
    pads_c ++;
  }

void out_smd (UL_SMD s, int n, int c)
  {
    pads += record ("Pad") + ra_net (n) + ra_comp (c)
           + r_i ("INDEXFORSAVE", pads_c)
           + r_layer ("LAYER", s.layer) + r_b ("LOCKED", 0) + r_b ("USERROUTED", 1) + r_s ("NAME", s.name)
           + r_l ("X", s.x, x0) + r_l ("Y", s.y, y0)
           + r_l ("XSIZE", s.dx, 0) + r_l ("YSIZE", s.dy, 0)
           + r_s ("SHAPE", "RECTANGLE") + r_l ("HOLESIZE", 0, 0) + r_f ("ROTATION", s.angle)
           + r_b ("PLATED", 0)
        // + r_s ("DAISYCHAIN", "Load")
        // + ... ... ...
         + endr ();
    pads_c ++;
  }

void out_text (UL_TEXT t, int c, int isDes, int isComm)
  {
    texts += record ("Text") + ra_comp (c)
            + r_i ("INDEXFORSAVE", texts_c) + r_b ("SELECTION", 0) 
            + r_layer ("LAYER", t.layer) + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1)
         // + r_l ("X1", ???) ... ... what they mean ?
            + r_l ("X", t.x, x0) + r_l ("Y", t.y, y0) + r_f ("ROTATION", t.angle) + r_l ("HEIGHT", t.size, 0)
            + r_s ("TEXT", t.value) 
            + (isDes ? r_s ("DESIGNATOR", "True") : "")
            + (isComm ? r_s ("COMMENT", "True") : "")
          + endr ();
    texts_c ++;
  }

void out_fill (UL_RECTANGLE r, int c)
  {    
    fills += record ("Fill") + ra_comp (c)
             + r_i ("INDEXFORSAVE", tracks_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", r.layer)
             + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1)
             + r_l ("X1", r.x1, x0) + r_l ("Y1", r.y1, y0) + r_l ("X2", r.x2, x0) + r_l ("Y2", r.y2, y0) 
             + r_f ("ROTATION", r.angle)
          + endr ();
    fills_c ++;
  }

void out_hole (UL_HOLE h, int c)
  {
    pads += record ("Pad") + ra_comp (c)
           + r_i ("INDEXFORSAVE", pads_c)
           + r_layer ("LAYER", LAYER_TOP /*incorrect*/) + r_b ("LOCKED", 0) + r_b ("USERROUTED", 0)
           + r_s ("NAME", "") + r_l ("X", h.x, x0) + r_l ("Y", h.y, y0)
           + r_l ("XSIZE", h.drill, 0) + r_l ("YSIZE", h.drill, 0)
           + r_s ("SHAPE", "ROUND") + r_l ("HOLESIZE", h.drill, 0) + r_f ("ROTATION", 0)
           + r_b ("PLATED", 0)
        // + r_s ("DAISYCHAIN", "Load")
        // + ... ... ...
         + endr ();
    pads_c ++;
  }

void out_net (UL_SIGNAL s)
  {
    netn [nets_c] = s.name;
    nets += record ("Net")
           + r_i ("ID", nets_c) + r_i ("INDEXFORSAVE", nets_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", LAYER_BOTTOM /*incorrect*/)
           + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + r_b ("PRIMITIVELOCK", 0)
           + r_s ("NAME", s.name) + r_b ("VISIBLE", 0) + r_i ("COLOR", 770986 /*incorrect*/)
         + endr ();
    nets_c ++;
  }

void out_component (UL_ELEMENT e, int hasDes, int hasComm)
  {
    comps += record ("Component") 
            + r_i ("ID", comps_c) + r_i ("INDEXFORSAVE", comps_c) + r_b ("SELECTION", 0) 
            + r_layer ("LAYER", (e.mirror ? LAYER_BOTTOM : LAYER_TOP))
            + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + r_b ("PRIMITIVELOCK", 1)
            + r_l ("X", e.x, x0) + r_l ("Y", e.y, y0) + r_s ("PATTERN", e.package.name) + r_b ("NAMEON", hasDes)
            + r_b ("COMMENTON", hasComm) + r_i ("GROUPNUM", 0) + r_i ("COUNT", 0) + r_f ("ROTATION", e.angle) 
            + r_i ("COMMENTAUTOPOSITION", 0) + r_i ("CHANNELOFFSET", 0) + r_s ("SOURCEDESIGNATOR", e.name) 
            + r_s ("SOURCEUNIQUEID", e.name) + r_s ("SOURCESEARCHPATH", ".") 
          + endr ();
    comps_c ++;
  }

// main

board (B)
  {
    fileName = dlgFileSave ("Export to Protel PCB", filesetext (B.name, ".pcb"), "*.pcb");
    if (fileName == "") exit (0);

    usedunits = 0; // FIXME

    // Protel doesn't like negative values.

    x0 = B.area.x1;
    y0 = B.area.y1;

    // Layers Naming
    B.layers (L) layer [L.number] = L.name;

    layer [LAYER_TOP]       = "TOP";  
    layer [LAYER_BOTTOM]    = "BOTTOM";
    layer [LAYER_PADS]      = "MULTILAYER"; //?
    layer [LAYER_VIAS]      = "MULTILAYER"; //?
    layer [LAYER_UNROUTED]  = "bug"; //!
    layer [LAYER_DIMENSION] = "KEEPOUT";
    layer [LAYER_TPLACE]    = "TOPOVERLAY";
    layer [LAYER_BPLACE]    = "BOTTOMOVERLAY";
    layer [LAYER_TORIGINS]  = "TOPOVERLAY";
    layer [LAYER_BORIGINS]  = "BOTTOMOVERLAY";
    layer [LAYER_TNAMES]    = "TOPOVERLAY";
    layer [LAYER_BNAMES]    = "BOTTOMOVERLAY";
    layer [LAYER_TVALUES]   = "TOPOVERLAY";
    layer [LAYER_BVALUES]   = "BOTTOMOVERLAY";
    layer [LAYER_TSTOP]     = "";
    layer [LAYER_BSTOP]     = "";
    layer [LAYER_TCREAM]    = "";
    layer [LAYER_BCREAM]    = "";
    layer [LAYER_TFINISH]   = "";
    layer [LAYER_BFINISH]   = "";
    layer [LAYER_TGLUE]     = "";
    layer [LAYER_BGLUE]     = ""; 
    layer [LAYER_TTEST]     = "TOP";    //?
    layer [LAYER_BTEST]     = "BOTTOM"; //?
    layer [LAYER_TKEEPOUT]  = "";
    layer [LAYER_BKEEPOUT]  = "";
    layer [LAYER_TRESTRICT] = "";
    layer [LAYER_BRESTRICT] = "";
    layer [LAYER_VRESTRICT] = "";
    layer [LAYER_DRILLS]    = "MULTILAYER";
    layer [LAYER_HOLES]     = "MULTILAYER";
    layer [LAYER_MILLING]   = "MECHANICAL1"; 
    layer [LAYER_MEASURES]  = "MECHANICAL2"; //?
    layer [LAYER_DOCUMENT]  = "MECHANICAL2"; //?
    layer [LAYER_REFERENCE] = "MECHANICAL2"; //?
    layer [LAYER_TDOCU]     = "TOPOVERLAY";
    layer [LAYER_BDOCU]     = "BOTTOMOVERLAY";
  
    // Signals Loop

    B.signals (S)
      { 
     // S.polygons (P) out_polygon (P, nets_c, -1);                     
        S.wires (W) out_track (W, nets_c, -1);
        S.vias (V) out_via (V, nets_c, -1);
        out_net (S);
      }

    // Components Loop

    B.elements (E)
      {
        UL_PACKAGE P = E.package;
        P.contacts (C)
          {
            if (C.pad) out_pad (C.pad, netbyname (C.signal), comps_c);
            if (C.smd) out_smd (C.smd, netbyname (C.signal), comps_c);
          }
        P.wires (W) out_track (W, -1, comps_c);
        P.circles (C) out_circle (C, comps_c);
        P.rectangles (R) out_fill (R, comps_c);
     // P.polygons (PO) out_polygon (PO, -1, comps_c);  
        P.holes (H) out_hole (H, comps_c);
        
        int hasDesignator = 0;
        int hasComment = 0;
        E.texts (T)
          {
            int isDes = 0; if ((T.value == E.name) && (! hasDesignator)) hasDesignator = isDes = 1;
            int isComm = 0; if ((T.value == E.value) && (! hasComment)) hasComment = isComm = 1;
            out_text (T, comps_c, isDes, isComm);
          }        
        P.texts (T)
          {
            int isDes = 0; if ((T.value == E.name) && (! hasDesignator)) hasDesignator = isDes = 1;
            int isComm = 0; if ((T.value == E.value) && (! hasComment)) hasComment = isComm = 1;
            out_text (T, comps_c, isDes, isComm);
          }
        out_component (E, hasDesignator, hasComment);
      }

    // Free elements

    B.circles (C) out_circle (C, -1);
    B.holes (H) out_hole (H, -1);
 // B.polygons (P) out_polygon (P, -1, -1);
    B.rectangles (R) out_fill (R, -1);
    B.texts (T) out_text (T, -1, 0, 0);
    B.wires (W) out_track (W, -1, -1);

    // Header
    header += record ("Board") 
             + r_b ("SELECTION", 0) + r_s ("LAYER", "UNKNOWN") + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0)
             + r_b ("USERROUTED", 1) 
             + r_s ("FILENAME", filename (fileName)) + r_s ("KIND", "Protel_Advanced_PCB") + r_s ("VERSION", "5.0")
          // + r_s ("DATE", ...) + r_s ("TIME", ...)
             + r_l ("ORIGINX", 0, 0) + r_l ("ORIGINY", 0, 0)
          // + ... ... ...
           + endr ();

    // Now, save to file

    output (fileName)
      {
        printf (header);
        printf (nets);
        printf (comps);
        printf (arcs);
        printf (pads);
        printf (vias);
        printf (tracks);
        printf (texts);
        printf (fills);
      }
    dlgMessageBox (fileName + "exported.");
  }

这里使用的方法很简单,如下,绘制好pcb文件后



点击这个ulp按钮

进去选择安装文件包中的,转换pcb.ulp


最后选择转换出了保存地址就行了


这样转换就完成了,eagle cad的protel封装库可以说是非常全的,好多都能找到,比protel要好很多,所以比较推荐这样使用。


分享到:
评论

相关推荐

    eagle 转protel PCB文件

    eagle 转protel PCB文件,只能转2层板,四层板转换失败

    EAGLE转protel PCB文件

    EAGLE转protel PCB文件,只能转2层板,四层测试失败

    Eagle转换SCH和PCB对应AD的插件

    转换步骤:1) 安装Eagle软件,将eagle2ad_sch.ulp文件和export-protelpcb.ulp存到eagle/ulp目录下。2)打开要转换的原理图和PCB文件,点击【文件】菜单下的【运行 ULP】,选择保存位置即可。3) 在跳出窗口中选择所...

    eagle文件转protel文件

    eagle转protel protel eagle

    EAGLE PCB转AD PCB文件.rar

     EAGLE 转AD 转换用ULP文件用于将EAGLE的PCB文件 转AD 使用的PCB文件。 使用方法: 1.将文件放到Eagle安装目录下的ULP文件夹下 2.打开要转换的PCB文件,以Picoboard传感器扩展板为例3.点击命令工具栏的ULP...

    Eagle转Protel-Altium PCB和原理图

    将2个下载文件复制到Eagle安装文件夹的ulp目录下,用Eagle打开PCB文件或原理图,运行ulp语言程序——分别打开2个下载文件,保存即可。也可以进一步生成PCB库、原理图库、集成库。

    eagle转protel pcb工具

    讲文件存到eagle ulp目录下,打开brd文件,运行ulp语言程序选择保存目录即可

    eagle brd 转pcb文件

    将文件夹中的export-protelpcb.ulp复制到eagle根目录下的ULP文件夹中 ,然后打开要转换的brd文件,点击文件下拉菜单栏中的运行ulp,选中export-protelpcb.ulp点打开,然后输入你要保持的xxxx.pcb大功告成。...

    eagle-export-protelpcb.ulp 一个输出protel pcb的脚本

    eagle-export-protelpcb.ulp 一个输出protel pcb的脚本,eagle-export-protelpcb.ulp 一个输出protel pcb的脚本

    eagle的brd文件转protel的tool

    分享一个eagle的brd文件转protel的tool 1. copy 压缩包内的Eagle4-1.ulp到eagle的安装目录内,如:C:\Program Files\EAGLE-4.16r1\...4. 运行eag2pro,打开txt文件,保存protel的pcb文件,并为其添加.pcb扩展名。 ...

    eagle文件转Altium Designer文件的两个脚本

    Eagle如何导出到protel/AD格式的原理图与PCB文件,以下两个脚本汇总: (1)eagle-export-protelpcb.ulp 一个输出protel/AD pcb的脚本 (2)eagle2ad_sch.ulp 输出 AD 原理图的脚本

    EAGLE 转AD 转换用ULP文件

    EAGLE 转AD 转换用ULP文件 用于 将EAGLE的PCB文件 转AD 使用的PCB文件

    eagle pcb导出gerber文件的cam文件

    用于eagle pcb导出gerber文件的cam作业文件SparkFun_sfe-gerb274x.cam; 仅支持双层板;

    最新版CadSoft Eagle PCB 6.2.0 破解文件,可打开Arduino的PCB源文件

    1.Eagle PCB的介绍请百度"Eagle PCB"; 2.Eagle 6.2的安装程序在官网下载 http://www.cadsoftusa.com/download-eagle/?language=en 3.网上能搜到的Eagle通常为5.X版本; 4.Arduino的PCB要用6.0以上版本打开; 5.亲测...

    Eagle转Altium designer的PCB及原理图.rar

    转换步骤:1) 安装Eagle软件,将eagle2ad_sch.ulp文件和export-protelpcb.ulp存到eagle/ulp目录下。2)打开要转换的原理图和PCB文件,点击【文件】菜单下的【运行 ULP】,选择保存位置即可。3) 在跳出窗口中选择所...

    Eagle PCB 学习资料

    Eagle PCB 学习资料

    EAGLE PCB电路板设计软件v7.2中文破解版.rar

    软件介绍: ...安装步骤:安装后将“覆盖到安装目录”文件夹内的eagle.exe文件复制到C:\EAGLE-7.2.0\bin目录下面,覆盖原文件。安装之后打开EAGLE,当出现许可时,点击“作为免费软件运行”后即是专业版。

    svgtoeagle:在线SVG到Eagle CAD转换器

    从Inkscape到Eagle CAD的简单SVG文件的在线转换器。 这与其他转换器不同,因为它: 实际将多边形输出为多边形(它不会预填充或转换为位图),从而防止电路板文件变大 它可以处理带Kong的多边形 处理填充和未填充...

    SparkFun-Eagle-Libraries, 使用 Eagle 6.0 实现 SparkFun Eagle PCB足迹的public.zip

    SparkFun-Eagle-Libraries, 使用 Eagle 6.0 实现 SparkFun Eagle PCB足迹的public SparkFun电子Eagle图书馆SparkFun电子使用 Eagle v6.0或者更高版本的首选脚打印。 我们花费了大量的时间来创建和检查这些足迹和零件...

    EagleCAD2Protel99

    将著名的Layout软件Eagle CAD所绘制的PCB版图文件转换至Protel99se格式的小工具,大体功能完好,只是对敷铜处理转换还有待完善。

Global site tag (gtag.js) - Google Analytics