Index: trunk/src_plugins/io_altium/altium_kw.sphash =================================================================== --- trunk/src_plugins/io_altium/altium_kw.sphash (revision 35526) +++ trunk/src_plugins/io_altium/altium_kw.sphash (revision 35527) @@ -71,6 +71,12 @@ manual none rule + _bin_mid_shape + _bin_bottom_shape + _bin_mid_xsize + _bin_mid_ysize + _bin_bottom_xsize + _bin_bottom_ysize layers top bottom Index: trunk/src_plugins/io_altium/pcbdoc.c =================================================================== --- trunk/src_plugins/io_altium/pcbdoc.c (revision 35526) +++ trunk/src_plugins/io_altium/pcbdoc.c (revision 35527) @@ -632,6 +632,57 @@ return 0; } +/* Decode expansion mode from text string or binary values and return a + field keyword (or -1) */ +static int get_expansion_mode(altium_field_t *field) +{ + switch(field->val_type) { + case ALTIUM_FT_STR: return altium_kw_sphash(field->val.str); + case ALTIUM_FT_LNG: + switch(field->val.lng) { + case 1: return altium_kw_field_rule; + case 2: return altium_kw_field_manual; + default: + rnd_message(RND_MSG_ERROR, "internal error: io_altium get_expansion_mode(): unknown binary mode %d\n", field->val.lng); + } + break; + default: + rnd_message(RND_MSG_ERROR, "internal error: io_altium get_expansion_mode(): invalid field type %d\n", field->val_type); + } + return -1; +} + +typedef enum { + ALTIUM_SHAPE_RECTANGLE, + ALTIUM_SHAPE_ROUND_RECTANGLE, + ALTIUM_SHAPE_ROUND +} altium_pad_shape_t; + +static altium_pad_shape_t get_shape(altium_field_t *field) +{ + switch(field->val_type) { + case ALTIUM_FT_STR: + if (rnd_strcasecmp(field->val.str, "rectangle") == 0) return ALTIUM_SHAPE_RECTANGLE; + if (rnd_strcasecmp(field->val.str, "roundedrectangle") == 0) return ALTIUM_SHAPE_ROUND_RECTANGLE; + if (rnd_strcasecmp(field->val.str, "round") == 0) return ALTIUM_SHAPE_ROUND; + rnd_message(RND_MSG_ERROR, "io_altium get_shape(): invalid shape name '%s'\n", field->val.str); + break; + case ALTIUM_FT_LNG: + switch(field->val.lng) { + case 1: return ALTIUM_SHAPE_ROUND; + case 2: return ALTIUM_SHAPE_RECTANGLE; +/* case 3: return ALTIUM_SHAPE_OVAL?;*/ + case 9: return ALTIUM_SHAPE_ROUND_RECTANGLE; + default: + rnd_message(RND_MSG_ERROR, "io_altium get_shape(): invalid shape ID %ld\n", field->val.lng); + } + break; + default: + rnd_message(RND_MSG_ERROR, "internal error: io_altium get_shape(): invalid field type %d\n", field->val_type); + } + return -1; +} + static int altium_parse_pad(rctx_t *rctx) { altium_record_t *rec; @@ -664,8 +715,8 @@ case altium_kw_field_net: netid = conv_long_field(field); break; case altium_kw_field_plated: plated = conv_bool_field(field); break; - case altium_kw_field_pastemaskexpansionmode: assert(field->val_type == ALTIUM_FT_STR); paste_mode = altium_kw_sphash(field->val.str); break; - case altium_kw_field_soldermaskexpansionmode: assert(field->val_type == ALTIUM_FT_STR); mask_mode = altium_kw_sphash(field->val.str); break; + case altium_kw_field_pastemaskexpansionmode: paste_mode = get_expansion_mode(field); break; + case altium_kw_field_soldermaskexpansionmode: mask_mode = get_expansion_mode(field); break; case altium_kw_field_pastemaskexpansion_manual: paste_man = conv_coord_field(field); break; case altium_kw_field_soldermaskexpansion_manual: mask_man = conv_coord_field(field); break; @@ -697,14 +748,25 @@ } } - assert(ly->val_type == ALTIUM_FT_STR); - if (rnd_strcasecmp(ly->val.str, "bottom") == 0) on_bottom = 1; - else if (rnd_strcasecmp(ly->val.str, "top") == 0) on_bottom = 0; - else if (rnd_strcasecmp(ly->val.str, "multilayer") == 0) on_all = 1; - else { - rnd_message(RND_MSG_ERROR, "Invalid pad object: invalid layer '%s' (should be top or bottom or multilayer; pad not created)\n", ly->val.str); - continue; + if (ly->val_type == ALTIUM_FT_STR) { + if (rnd_strcasecmp(ly->val.str, "bottom") == 0) on_bottom = 1; + else if (rnd_strcasecmp(ly->val.str, "top") == 0) on_bottom = 0; + else if (rnd_strcasecmp(ly->val.str, "multilayer") == 0) on_all = 1; + else { + rnd_message(RND_MSG_ERROR, "Invalid object: invalid pad layer '%s' (should be top or bottom or multilayer; pad not created)\n", ly->val.str); + continue; + } } + else if (ly->val_type == ALTIUM_FT_LNG) { + switch(ly->val.lng) { + case 1: on_bottom = 0; break; + case 32: on_bottom = 1; break; + case 74: on_all = 1; break; + default: + rnd_message(RND_MSG_ERROR, "Invalid object: invalid pad layer %ld (should be 1=top or 32=bottom or 74=multilayer; pad not created)\n", ly->val.lng); + continue; + } + } /* set final mask and paste offsets */ if (mask_mode == altium_kw_field_manual) { @@ -721,64 +783,65 @@ } /* create the abstract shapes */ - assert(shapename->val_type == ALTIUM_FT_STR); - if ((rnd_strcasecmp(shapename->val.str, "rectangle") == 0) || (rnd_strcasecmp(shapename->val.str, "roundedrectangle") == 0)) { - pcb_shape_rect(&copper_shape, xsize, ysize); - copper_valid = 1; - if (((xsize + mask_fin*2) > 0) && ((ysize + mask_fin*2) > 0)) { - pcb_shape_rect(&mask_shape, xsize + mask_fin*2, ysize + mask_fin*2); - mask_valid = 1; - } - if (((xsize + paste_fin*2) > 0) && ((ysize + paste_fin*2) > 0)) { - pcb_shape_rect(&paste_shape, xsize + paste_fin*2, ysize + paste_fin*2); - paste_valid = 1; - } - } - else if (rnd_strcasecmp(shapename->val.str, "round") == 0) { - if (xsize == ysize) { - copper_shape.shape = mask_shape.shape = PCB_PSSH_CIRC; - copper_shape.data.circ.x = copper_shape.data.circ.y = 0; - copper_shape.data.circ.dia = xsize; + switch(get_shape(shapename)) { + case ALTIUM_SHAPE_RECTANGLE: + case ALTIUM_SHAPE_ROUND_RECTANGLE: + pcb_shape_rect(&copper_shape, xsize, ysize); copper_valid = 1; - mask_shape.data.circ.x = mask_shape.data.circ.y = 0; - mask_shape.data.circ.dia = xsize + mask_fin*2; - mask_valid = (mask_shape.data.circ.dia > 0); - paste_shape = copper_shape; - paste_shape.data.circ.dia += paste_fin*2; - paste_valid = (paste_shape.data.circ.dia > 0); - } - else { - copper_shape.shape = mask_shape.shape = PCB_PSSH_LINE; - if (xsize > ysize) { - copper_shape.data.line.x1 = mask_shape.data.line.x1 = -xsize/2 + ysize/2; - copper_shape.data.line.x2 = mask_shape.data.line.x2 = +xsize/2 - ysize/2; - copper_shape.data.line.y1 = mask_shape.data.line.y1 = copper_shape.data.line.y2 = mask_shape.data.line.y2 = 0; - copper_shape.data.line.thickness = ysize; + if (((xsize + mask_fin*2) > 0) && ((ysize + mask_fin*2) > 0)) { + pcb_shape_rect(&mask_shape, xsize + mask_fin*2, ysize + mask_fin*2); + mask_valid = 1; + } + if (((xsize + paste_fin*2) > 0) && ((ysize + paste_fin*2) > 0)) { + pcb_shape_rect(&paste_shape, xsize + paste_fin*2, ysize + paste_fin*2); + paste_valid = 1; + } + break; + case ALTIUM_SHAPE_ROUND: + if (xsize == ysize) { + copper_shape.shape = mask_shape.shape = PCB_PSSH_CIRC; + copper_shape.data.circ.x = copper_shape.data.circ.y = 0; + copper_shape.data.circ.dia = xsize; copper_valid = 1; - mask_shape.data.line.thickness = ysize + mask_fin*2; - mask_valid = (mask_shape.data.line.thickness > 0); + mask_shape.data.circ.x = mask_shape.data.circ.y = 0; + mask_shape.data.circ.dia = xsize + mask_fin*2; + mask_valid = (mask_shape.data.circ.dia > 0); paste_shape = copper_shape; - paste_shape.data.line.thickness += paste_fin*2; - paste_valid = (paste_shape.data.line.thickness > 0); + paste_shape.data.circ.dia += paste_fin*2; + paste_valid = (paste_shape.data.circ.dia > 0); } else { - copper_shape.data.line.y1 = mask_shape.data.line.y1 = -ysize/2 + xsize/2; - copper_shape.data.line.y2 = mask_shape.data.line.y2 = +ysize/2 - xsize/2; - copper_shape.data.line.x1 = mask_shape.data.line.x1 = copper_shape.data.line.x2 = mask_shape.data.line.x2 = 0; - copper_shape.data.line.thickness = xsize; - copper_valid = 1; - mask_shape.data.line.thickness = xsize + mask_fin*2; - mask_valid = (mask_shape.data.line.thickness > 0);; - paste_shape = copper_shape; - paste_shape.data.line.thickness += paste_fin*2; - paste_valid = (paste_shape.data.line.thickness > 0); + copper_shape.shape = mask_shape.shape = PCB_PSSH_LINE; + if (xsize > ysize) { + copper_shape.data.line.x1 = mask_shape.data.line.x1 = -xsize/2 + ysize/2; + copper_shape.data.line.x2 = mask_shape.data.line.x2 = +xsize/2 - ysize/2; + copper_shape.data.line.y1 = mask_shape.data.line.y1 = copper_shape.data.line.y2 = mask_shape.data.line.y2 = 0; + copper_shape.data.line.thickness = ysize; + copper_valid = 1; + mask_shape.data.line.thickness = ysize + mask_fin*2; + mask_valid = (mask_shape.data.line.thickness > 0); + paste_shape = copper_shape; + paste_shape.data.line.thickness += paste_fin*2; + paste_valid = (paste_shape.data.line.thickness > 0); + } + else { + copper_shape.data.line.y1 = mask_shape.data.line.y1 = -ysize/2 + xsize/2; + copper_shape.data.line.y2 = mask_shape.data.line.y2 = +ysize/2 - xsize/2; + copper_shape.data.line.x1 = mask_shape.data.line.x1 = copper_shape.data.line.x2 = mask_shape.data.line.x2 = 0; + copper_shape.data.line.thickness = xsize; + copper_valid = 1; + mask_shape.data.line.thickness = xsize + mask_fin*2; + mask_valid = (mask_shape.data.line.thickness > 0);; + paste_shape = copper_shape; + paste_shape.data.line.thickness += paste_fin*2; + paste_valid = (paste_shape.data.line.thickness > 0); + } } - } + break; + default: + rnd_message(RND_MSG_ERROR, "Invalid pad object: invalid shape (pad not created)\n"); + continue; } - else { - rnd_message(RND_MSG_ERROR, "Invalid pad object: invalid shape '%s' (pad not created)\n", shapename->val.str); - continue; - } /* create shape stackup in shape[] */ n = 0; Index: trunk/src_plugins/io_altium/pcbdoc_bin.c =================================================================== --- trunk/src_plugins/io_altium/pcbdoc_bin.c (revision 35526) +++ trunk/src_plugins/io_altium/pcbdoc_bin.c (revision 35527) @@ -553,12 +553,45 @@ static int pcbdoc_bin_parse_pads6_fields(rnd_hidlib_t *hidlib, altium_tree_t *tree, altium_buf_t *tmp, const char *name) { unsigned char *d = tmp->data; + altium_record_t *rec; - /* if layer[0] is 74 (multilayer), use all shapes, else use only top on the specified layer */ - +/* printf("pad: layer=%d..%d net=%ld (comp=%ld) '%s'\n", d[0], d[1], load_int(d+3, 2), load_int(d+7, 2), name); printf(" x=%.2f y=%.2f hole=%.2f plated=%d mode=%d rot=%.3f\n", bmil(d+13), bmil(d+17), bmil(d+45), d[60], d[62], load_dbl(d+52)); printf(" top: %d sx=%.2f sy=%.2f; mid: %d sx=%.2f sy=%.2f; bot: %d sx=%.2f mid-sy=%.2f\n", d[49], bmil(d+21), bmil(d+25), d[50], bmil(d+29), bmil(d+33), d[51], bmil(d+37), bmil(d+41)); +*/ + + rec = pcbdoc_ascii_new_rec(tree, "Pad", altium_kw_record_pad); + FIELD_LNG(rec, layer, d[0]); + TODO("keepout is not used by the high level code; find an example"); + FIELD_LNG(rec, net, load_int(d+3, 2)); + FIELD_LNG(rec, component, load_int(d+7, 2)); + + FIELD_CRD(rec, x, bmil(d+13)); + FIELD_CRD(rec, y, bmil(d+17)); + FIELD_CRD(rec, holesize, bmil(d+45)); + FIELD_LNG(rec, plated, d[60]); + FIELD_DBL(rec, rotation, load_dbl(d+52)); + + FIELD_LNG(rec, shape, d[49]); + FIELD_CRD(rec, xsize, bmil(d+21)); + FIELD_CRD(rec, ysize, bmil(d+25)); + + if (d[0] == 74) { /* if layer[0] is 74 (multilayer), use all shapes, else use only top on the specified layer */ + FIELD_LNG(rec, _bin_mid_shape, d[50]); + FIELD_CRD(rec, _bin_mid_xsize, bmil(d+29)); + FIELD_CRD(rec, _bin_mid_ysize, bmil(d+33)); + FIELD_LNG(rec, _bin_bottom_shape, d[51]); + FIELD_CRD(rec, _bin_bottom_xsize, bmil(d+37)); + FIELD_CRD(rec, _bin_bottom_ysize, bmil(d+41)); + } + + FIELD_CRD(rec, pastemaskexpansion_manual, bmil(d+86)); + FIELD_CRD(rec, soldermaskexpansion_manual, bmil(d+90)); + FIELD_LNG(rec, pastemaskexpansionmode, d[101]); + FIELD_LNG(rec, soldermaskexpansionmode, d[102]); + + FIELD_STR(rec, name, make_blk(tree, name, strlen(name))); return 0; }