omdl  v1.0
OpenSCAD Mechanical Design Library
pcie_expansion.scad
Go to the documentation of this file.
1 //! A PCI Express expansion chassis and/or enclosure generator.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2026
6 
7  \copyright
8 
9  This file is part of [omdl] (https://github.com/royasutton/omdl),
10  an OpenSCAD mechanical design library.
11 
12  The \em omdl is free software; you can redistribute it and/or modify
13  it under the terms of the [GNU Lesser General Public License]
14  (http://www.gnu.org/licenses/lgpl.html) as published by the Free
15  Software Foundation; either version 2.1 of the License, or (at
16  your option) any later version.
17 
18  The \em omdl is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  Lesser General Public License for more details.
22 
23  You should have received a copy of the GNU Lesser General Public
24  License along with the \em omdl; if not, write to the Free Software
25  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26  02110-1301, USA; or see <http://www.gnu.org/licenses/>.
27 
28  \details
29 
30  \amu_define group_name (PCIe Expansion)
31  \amu_define group_brief (PCI Express expansion chassis and/or enclosure generator.)
32 
33  \amu_include (include/amu/doxyg_init_pd_gds_ipg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 
38 /***************************************************************************//**
39  \amu_include (include/amu/doxyg_define_in_parent_open.amu)
40  \amu_define includes_required_add
41  (
42  shapes/select_common_2d.scad
43  shapes/select_common_3d.scad
44  transforms/base_cs.scad
45  transforms/layout.scad
46  models/2d/joint/dovetail.scad
47  parts/3d/fastener/clamps.scad
48  parts/3d/enclosure/project_box_rectangle.scad
49  )
50  \amu_include (include/amu/includes_required.amu)
51 *******************************************************************************/
52 
53 //----------------------------------------------------------------------------//
54 // global configuration
55 //----------------------------------------------------------------------------//
56 
57 //! \name Configuration: PCI-E standard
58 //! @{
59 
60 //! <map> PCI-E standard specifications common to full and half-length cards.
61 //! \hideinitializer
63 [
64  //! \cond DOXYGEN_SHOULD_SKIP_THIS
65  ["h_connector_max", 11.25],
66  ["l_keya_2_bkto", 59.05],
67  ["w_bkt_width", 18.42],
68  ["w_pcb_mth", 1.57],
69  ["h_rbpcbt_2_fngrb", 3.40],
70  ["bkt_mth", 0.86],
71  ["h_bkt_tab", 5.07],
72  ["w_bkt_tabo", 4.11],
73  ["l_card_max_full", 312.00],
74  ["l_card_max_half", 167.65],
75  //! \endcond
76 ];
77 
78 //! <map> PCI-E full-length card standard specifications.
79 //! \hideinitializer
81 [
82  //! \cond DOXYGEN_SHOULD_SKIP_THIS
83  ["h_card_max", 111.15],
84  ["h_card_max_2_pciblck", 106.65],
85  ["h_pciblck_2_bktb", 100.36],
86  ["h_bktb_2_bkttabb", 120.02],
87  ["w_bkt_tab", 10.20],
88  ["wh_copen_window", [12.06, 89.90]],
89  ["h_bktb_2_copen", 10.16],
90  ["w_pcb_2_copen", 0.35],
91  ["wl_mnt_tab", [+21.59 - 2.54, 11.43]],
92  ["w_mnt_tab_o", -1.57/2 + 18.42 - 21.59],
93  ["wl_mnt_hole_o", [-1.57/2 - 1.27, -64.13]],
94  //! \endcond
95 ];
96 
97 //! <map> PCI-E half-length card standard specifications.
98 //! \hideinitializer
100 [
101  //! \cond DOXYGEN_SHOULD_SKIP_THIS
102  ["h_card_max", 68.90],
103  ["h_card_max_2_pciblck", 64.40],
104  ["h_pciblck_2_bktb", 63.58],
105  ["h_bktb_2_bkttabb", 79.20],
106  ["w_bkt_tab", 10.19],
107  ["wh_copen_window", [12.07, 54.53 + 5.08*2]],
108  ["h_bktb_2_copen", 9.04 - 5.08],
109  ["w_pcb_2_copen", 0.37],
110  ["wl_mnt_tab", [18.59, 11.84]],
111  ["w_mnt_tab_o", +1.57/2 + 0.37],
112  ["wl_mnt_hole_o", [+1.57/2 + 14.71, -65.40]],
113  //! \endcond
114 ];
115 
116 //! @}
117 
118 //! \name Configuration: Riser board
119 //! @{
120 
121 //! \cond DOXYGEN_SHOULD_SKIP_THIS
122 riser_map_doc =
123 [
124  ["bottom_clearance", "Vertical clearance under riser board"],
125  ["slot_count", "Riser physical slot count (fixed)"],
126  ["vslot_count", "Riser virtual slot count (user adjustable)"],
127  ["multi_slot_offset", "PCI-E multi-slot, slot-to-slot spacing"],
128  ["slot1_to_edge1", "Riser board slot-1 to adjacent edge distance"],
129  ["slotn_to_edgen", "Riser board slot-n to adjacent edge distance"],
130  ["slot_key_to_edgef", "Riser board key to front edge distance"],
131  ["slot_link_width", "Slot connector link width {1|4|8|16}"],
132  ["pcb_length", "Riser board PCB length front to rear"],
133  ["pcb_th", "Riser board PCB thickness"],
134  ["mount_holes", "Riser board mount holes; referenced to slot-1 key"],
135  ["mount_holes_add", "Riser board mount holes additions"],
136  ["post_rotate", "Mount post rotation in degrees"],
137  ["post_fins", "Mount post fin configuration: see project_box_rectangle()"],
138  ["post_hole_d", "Mount post hole diameter"],
139  ["post_pad_d", "Mount post diameter"]
140 ];
141 //! \endcond
142 
143 //! <map> USB 3.0 PCE164P-NO3 VER 007 1-slot riser board.
144 /***************************************************************************//**
145  \details
146 
147  A configuration for the PCE164P-NO3 VER 007 1-slot riser board.
148  This is the default riser board and can be used as a basis for
149  constructing new riser board configuration.
150 
151  \amu_define title (Riser board configuration)
152  \amu_define scope_id (riser_PCE164P_NO3_VER_007)
153  \amu_define output_scad (false)
154  \amu_define output_console (false)
155 
156  \amu_include (include/amu/scope_table.amu)
157 
158  \hideinitializer
159 *******************************************************************************/
161 [
162  //! \cond DOXYGEN_SHOULD_SKIP_THIS
163  ["bottom_clearance", 3],
164  ["slot_count", 1],
165  ["vslot_count", 0],
166  ["multi_slot_offset", 20.32],
167  ["slot1_to_edge1", 15],
168  ["slotn_to_edgen", 28],
169  ["slot_key_to_edgef", 113.25],
170  ["slot_link_width", 16],
171  ["pcb_length", 127.75],
172  ["pcb_th", 1.75],
173  ["mount_holes",
174  let
175  (
176  w1 = 36.00,
177  l1 = 96.50,
178  ko = [-11.50, -11.00]
179  )
180  [
181  [ 0, 0] + ko,
182  [w1, 0] + ko,
183  [ 0, l1] + ko,
184  [w1, l1] + ko
185  ]
186  ],
187  ["mount_holes_add", undef],
188  ["post_rotate", 45],
189  ["post_fins", [4]],
190  ["post_hole_d", 3.00],
191  ["post_pad_d", 2.75 * 3.00]
192  //! \endcond
193 ];
194 
195 //! <map> AAAPCIE4HUB multiplier HUB 4-slot riser board.
196 /***************************************************************************//**
197  \details
198 
199  A configuration for the AAAPCIE4HUB multiplier HUB 1-slot riser board.
200 
201  \amu_define title (Riser board configuration)
202  \amu_define scope_id (riser_AAAPCIE4HUB)
203  \amu_define output_scad (false)
204  \amu_define output_console (false)
205 
206  \amu_include (include/amu/scope_table.amu)
207 
208  \hideinitializer
209 *******************************************************************************/
211 [
212  //! \cond DOXYGEN_SHOULD_SKIP_THIS
213  ["bottom_clearance", 3],
214  ["slot_count", 4],
215  ["vslot_count", 0],
216  ["multi_slot_offset", 20.32],
217  ["slot1_to_edge1", 12],
218  ["slotn_to_edgen", 12],
219  ["slot_key_to_edgef", 74],
220  ["slot_link_width", 1],
221  ["pcb_length", 99],
222  ["pcb_th", 1.5],
223  ["mount_holes",
224  let
225  (
226  w1 = 20.00,
227  w2 = 77.00,
228  l1 = 46.00,
229  ko = [-9.00, -7.0]
230  )
231  [
232  [ 0, 0] + ko,
233  [w1, 0] + ko,
234  [w2, 0] + ko,
235  [ 0, l1] + ko,
236  [w1, l1] + ko,
237  [w2, l1] + ko
238  ]
239  ],
240  ["mount_holes_add", undef],
241  ["post_rotate", 45],
242  ["post_fins", [4]],
243  ["post_hole_d", 3.00],
244  ["post_pad_d", 2.75 * 3.00]
245  //! \endcond
246 ];
247 
248 //! <map> SFF-8612 4X lane to 16X 1-slot riser board.
249 /***************************************************************************//**
250  \details
251 
252  A configuration for the SFF-8612 4X lane to 16X 1-slot riser board.
253 
254  \amu_define title (Riser board configuration)
255  \amu_define scope_id (riser_SFF_8612_4X_to_PCI_E_16X)
256  \amu_define output_scad (false)
257  \amu_define output_console (false)
258 
259  \amu_include (include/amu/scope_table.amu)
260 
261  \hideinitializer
262 *******************************************************************************/
264 [
265  //! \cond DOXYGEN_SHOULD_SKIP_THIS
266  ["bottom_clearance", 0],
267  ["slot_count", 1],
268  ["vslot_count", 0],
269  ["multi_slot_offset", 20.32],
270  ["slot1_to_edge1", 5.75],
271  ["slotn_to_edgen", 37.00],
272  ["slot_key_to_edgef", 89.50],
273  ["slot_link_width", 16],
274  ["pcb_length", 122.00],
275  ["pcb_th", 1.75],
276  ["mount_holes",
277  let
278  (
279  w1 = 37.00,
280  l1 = 116.00,
281  ko = [-3.00, -29.00]
282  )
283  [
284  [ 0, 0] + ko,
285  [w1, 0] + ko,
286  [ 0, l1] + ko,
287  [w1, l1] + ko
288  ]
289  ],
290  ["mount_holes_add", undef],
291  ["post_rotate", 45],
292  ["post_fins", [4]],
293  ["post_hole_d", 2.75],
294  ["post_pad_d", 2.75 * 2.75]
295  //! \endcond
296 ];
297 
298 //! @}
299 
300 //! \name Configuration: Enclosure
301 //! @{
302 
303 //! \cond DOXYGEN_SHOULD_SKIP_THIS
304 enclosure_map_doc =
305 [
306  ["rounding", "Enclosure corner rounding radius"],
307  ["wth", "Enclosure minimum wall thickness"],
308  ["board_count", "Enclosure riser board count"],
309  ["multi_board_offset", "Multi-riser inter board offset"],
310  ["space_add_edge1", "Space to add to riser edge-1"],
311  ["space_add_edgen", "Space to add to riser edge-n"],
312  ["space_add_length", "Space to add to riser end length"],
313  ["space_add_height", "Space to add to enclosure height"],
314  ["space_min_length", "Enclosure minimum interior length"],
315  ["space_min_height", "Enclosure minimum interior height"],
316  ["rb_min_clearance", "Riser board minimum bottom clearance"],
317  ["rib_pcb_gap", "Rib removal gap for PCIE and riser board PCB"],
318  ["lips_sides", "Sides lips specification: see project_box_rectangle()"],
319  ["lips_base", "Base lips specification: see project_box_rectangle()"],
320  ["lips_cover", "Cover lips specification: see project_box_rectangle()"],
321  ["walls", "Enclosure interior walls: see project_box_rectangle()"],
322  ["ribs", "Enclosure wall rib specification: see project_box_rectangle()"],
323  ["posts_sides_conf", "Post configuration sides: [mode, default]: see project_box_rectangle()"],
324  ["posts_base_conf", "Post configuration base: [mode, default]: see project_box_rectangle()"],
325  ["posts_cover_conf", "Post configuration cover: [mode, default]: see project_box_rectangle()"],
326  ["posts_sides", "Post instances sides only: see project_box_rectangle()"],
327  ["posts_base", "Post instances base only: see project_box_rectangle()"],
328  ["posts_cover", "Post instances cover only: see project_box_rectangle()"],
329  ["posts", "Post instances for sides, base and cover: see project_box_rectangle()"],
330  ["clamps_base", "Enclosure base clamps: see clamp_zt_1p()"],
331  ["holes_sides", "Enclosure side hole instances: see project_box_rectangle()"],
332  ["holes_base", "Enclosure base hole instances: see project_box_rectangle()"],
333  ["holes_cover", "Enclosure cover hole instances: see project_box_rectangle()"],
334  ["shapes_sides", "Enclosure side shapes instances: see project_box_rectangle()"],
335  ["shapes_base", "Enclosure base shapes instances: see project_box_rectangle()"],
336  ["shapes_cover", "Enclosure cover shapes instances: see project_box_rectangle()"],
337  ["bracket_window_gap", "Bracket connector window gap [w]"],
338  ["bracket_shoe_gap_p", "Bracket shoe gap% [w, l, h]"],
339  ["bracket_shoe_offset", "Bracket shoe vertical offset [h]"],
340  ["bracket_mount_tab", "Bracket mount tab configuration"],
341  ["cut_sides", "Enclosure sides cut [insets, vr, vrm]"],
342  ["mode_rounding", "Enclosure rounding mode: {0|1|2}"],
343  ["mode_sides", "Enclosure sides mode"],
344  ["mode_proj_box", "Mode for project_box_rectangle() module"],
345  ["verb_proj_box", "Verbosity for project_box_rectangle()"]
346 ];
347 //! \endcond
348 
349 //! <map> Default enclosure configuration.
350 /***************************************************************************//**
351  \details
352 
353  The default enclosure configuration map.
354 
355  \amu_define title (Default enclosure configuration)
356  \amu_define scope_id (enclosure_def)
357  \amu_define output_scad (false)
358  \amu_define output_console (false)
359 
360  \amu_include (include/amu/scope_table.amu)
361 
362  ## Multi-value and structured parameters
363 
364  ### bracket_mount_tab
365 
366  e | data type | default value | parameter description
367  ---:|:-----------------:|:-----------------:|:------------------------------------
368  0 | decimal | | thickness
369  1 | decimal | | tab-boarders (width addition)
370  2 | decimal | | screw hole diameter
371  3 | decimal-list-4 \| decimal | | tab rounding
372  4 | decimal-list-4 \| decimal | | tab rounding modes
373  4 | decimal-list-5 \| decimal | | dovetail configuration: see joint2d_dovetail() \p t
374 
375  ### clamps_base
376 
377  #### Data structure schema:
378 
379  name | schema
380  ---------------:|:----------------------------------------------
381  clamps_base | [[configuration, instances]]
382 
383  #### Data structure fields: clamps_base[0]: configuration
384 
385  e | data type | default value | parameter description
386  ---:|:-----------------:|:-----------------:|:------------------------------------
387  0 | decimal-list-2 | | wire hole size [w, h]
388  1 | decimal-list-2 | | zip-tie hole size [w, h]
389  2 | decimal-list-3 | | clamp envelope size [w, h, d]
390  3 | datastruct | | tunnel configuration: see clamp_zt_1p() \p tunnel
391  4 | decimal-list3-list-4 | | vr [clamp, wire, tunnel]
392  5 | integer-list3-list-4 | | vrm [clamp, wire, tunnel]
393 
394  #### Data structure fields: clamps_base[1]: instances
395 
396  e | data type | default value | parameter description
397  ---:|:-----------------:|:-----------------:|:------------------------------------
398  0 | integer-list-2 | | enclosure side [w, l]
399  1 | decimal | | clamp rotate [z]
400  2 | integer | | clamp align [d]
401  3 | decimal-list-2 | | clamp move [w, l]
402  4 | datastruct | | side passage hole
403 
404  #### Data structure fields: clamps_base[1]: instances[4]: side passage hole
405 
406  e | data type | default value | parameter description
407  ---:|:-----------------:|:-----------------:|:------------------------------------
408  0 | binary | | enabled
409  1 | decimal | | vertical cut extension
410  2 | datastruct | | wall cone: see clamp_cg() \p cone
411 
412  ### cut_sides
413 
414  e | data type | default value | parameter description
415  ---:|:-----------------:|:-----------------:|:------------------------------------
416  0 | decimal-list-4 | | edge cut insets: [bb, bt, ft, fb]
417  1 | decimal-list-4 | | cut rounding: [bb, bt, ft, fb]
418  2 | integer-list-4 | | cut rounding mode: [bb, bt, ft, fb]
419 
420  ### holes_sides
421 
422  See the documentation for project_box_rectangle() under the section
423  for \p hole configuration for more details on hole specification.
424 
425  ### shapes_sides
426 
427  See the documentation for project_box_rectangle() under the section
428  for \p shape configuration for more details on shape specification.
429 
430  ### posts
431 
432  See the documentation for project_box_rectangle() under the section
433  for \p post configuration for more details on post specification.
434 
435  ### mode_sides
436 
437  Integer value is binary encoded.
438 
439  b | description
440  ---:|:---------------------------------------
441  0 | Add mount tab shelves
442  1 | Hull adjacent-slot mount tab shelf
443  2 | Hull removal of adjacent-slot connector windows
444  3 | Hull removal of adjacent-slot ribs from wall
445  4 | Hull removal of adjacent-slot bracket slide-down space
446  5 | Enable enclosure side cutting
447  6 | Cut enclosure front (positive side)
448  7 | Cut enclosure rear (negative side near bracket)
449  8 | Remove ribs on front enclosure wall for riser PCB
450  9 | Remove ribs on front enclosure wall for PCIE card PCB
451 
452  \hideinitializer
453 *******************************************************************************/
455 [
456  //! \cond DOXYGEN_SHOULD_SKIP_THIS
457  ["rounding", 6.75],
458  ["wth", 2.0],
459 
460  ["board_count", 1],
461  ["multi_board_offset", 0],
462 
463  ["space_add_edge1", 0],
464  ["space_add_edgen", 0],
465  ["space_add_length", 0],
466  ["space_add_height", 0],
467 
468  ["space_min_length", 0],
469  ["space_min_height", 0],
470 
471  ["rb_min_clearance", 0],
472 
473  ["rib_pcb_gap", 1/2],
474 
475  ["lips_sides", 1 + 8],
476  ["lips_base", 1],
477  ["lips_cover", 2],
478 
479  ["walls",
480  undef
481  ],
482 
483  ["ribs", 0],
484 
485  ["posts_sides_conf",
486  [
487  0, // mode (binary encoded integer)
488  [ // defaults
489  undef, // hole0
490  undef, // hole1
491  undef, // post1
492  undef, // hole2
493  undef, // post2
494  undef, // fins0
495  undef, // fins1
496  undef // calculation
497  ]
498  ]
499  ],
500  ["posts_base_conf",
501  [
502  0, // mode (binary encoded integer)
503  [ // defaults
504  undef, // hole0
505  undef, // hole1
506  undef, // post1
507  undef, // hole2
508  undef, // post2
509  undef, // fins0
510  undef, // fins1
511  undef // calculation
512  ]
513  ]
514  ],
515  ["posts_cover_conf",
516  [
517  0, // mode (binary encoded integer)
518  [ // defaults
519  undef, // hole0
520  undef, // hole1
521  undef, // post1
522  undef, // hole2
523  undef, // post2
524  undef, // fins0
525  undef, // fins1
526  undef // calculation
527  ]
528  ]
529  ],
530  ["posts_sides",
531  let(u=undef, t=2, o=7.5, f=[4, 120, u, 1/6])
532  [
533  [t, [-1,-1], [+o,+o], 180, u, u, u, f],
534  [t, [-1,+1], [+o,-o], 090, u, u, u, f],
535  [t, [+1,-1], [-o,+o], 270, u, u, u, f],
536  [t, [+1,+1], [-o,-o], 000, u, u, u, f]
537  ]
538  ],
539  ["posts_base",
540  let(u=undef, t=3, o=7.5, f=[2, 180, u, 1/6])
541  [
542  [t, [-1,-1], [+o,+o], 000, u, u, u, f],
543  [t, [-1,+1], [+o,-o], 270, u, u, u, f],
544  [t, [+1,-1], [-o,+o], 090, u, u, u, f],
545  [t, [+1,+1], [-o,-o], 180, u, u, u, f]
546  ]
547  ],
548  ["posts_cover",
549  let(u=undef, t=3, o=7.5, f=[2, 180, u, 1/6])
550  [
551  [t, [-1,-1], [+o,+o], 000, u, u, u, f],
552  [t, [-1,+1], [+o,-o], 270, u, u, u, f],
553  [t, [+1,-1], [-o,+o], 090, u, u, u, f],
554  [t, [+1,+1], [-o,-o], 180, u, u, u, f]
555  ]
556  ],
557  ["posts",
558  undef
559  ],
560 
561  ["clamps_base",
562  [ // clamp set list [[conf, inst]]
563  [ // set-0: [conf, inst]
564  [ // set-0, 0: configuration
565  [7.00, 4.75], // wire hole size [w, h]
566  [5.50, 2.25], // zip-tie hole size [w, h]
567  [20, 10, 10], // clamp envelope size [w, h, d]
568  [ // tunnel configuration
569  3, // 0: corner radius
570  [0], // 1: instance offset list
571  binary_ishl(2, 0) // 2: mode w-sel, h-sel, window
572  + binary_ishl(2, 2)
573  + binary_ishl(0, 4),
574  [0, -1.00], // 3: radial offset [w, h]
575  [0, -0.25] // 4: position offset [w, h]
576  ],
577  [3.00, 1.00, 1.25], // vr [clamp, wire, tunnel]
578  undef // vrm [clamp, wire, tunnel]
579  ],
580  [ // set-0, 1: instance list
581  [
582  [0,1], // enclosure side [w, l]
583  0, // clamp rotate [z]
584  1, // clamp align [d]
585  [0,0], // clamp move [w, l]
586  [ // side passage hole
587  true, // enabled
588  5 + 3/64, // vertical cut extension
589  [1, 2.5, 1/2, 31] // wall cone configuration [side, w, h, mode]
590  ]
591  ]
592  ]
593  ]
594  ]
595  ],
596 
597  ["holes_sides",
598  [
599  [
600  [2, [5/2, 6]],
601  -1,
602  [
603  0,
604  [0,0,1/2],
605  [90,0,90],
606  0,
607  30,
608  [0, -10],
609  [20, 3],
610  [+10.75, -10.75],
611  [true, false]
612  ]
613  ],
614  [
615  [3, [5/2,10], 1.5],
616  -1,
617  [
618  0,
619  [0,0,-1/2],
620  [90,0,90],
621  0,
622  0,
623  [0, +5.5],
624  18,
625  10.75,
626  true
627  ]
628  ]
629  ]
630  ],
631  ["holes_base",
632  undef
633  ],
634  ["holes_cover",
635  undef
636  ],
637 
638  ["shapes_sides",
639  undef
640  ],
641  ["shapes_base",
642  undef
643  ],
644  ["shapes_cover",
645  undef
646  ],
647 
648  ["bracket_window_gap", 2.00],
649  ["bracket_shoe_gap_p", 25/100],
650  ["bracket_shoe_offset", -2.00],
651  ["bracket_mount_tab",
652  [
653  3.25, // thickness
654  4.00, // tab-boarders (width addition)
655  3.125, // screw hole diameter
656  [3,3,5,5], // tab rounding
657  [1,1,4,3], // tab rounding modes
658  [5.0, 6.0, 2.0, 3/4, 1/4] // dovetail configuration: see joint2d_dovetail(t)
659  ]
660  ],
661 
662  ["cut_sides",
663  [
664  [18, 12, 10, 10], // edge cut insets: [bb, bt, ft, fb]
665  [10, 15, 0, 0], // cut rounding: [bb, bt, ft, fb]
666  [1, 4, 0, 0] // cut rounding mode: [bb, bt, ft, fb]
667  ]
668  ],
669 
670  ["mode_rounding", 2],
671  ["mode_sides", 0],
672  ["mode_proj_box", 0],
673  ["verb_proj_box", 0]
674  //! \endcond
675 ];
676 
677 //! @}
678 
679 //----------------------------------------------------------------------------//
680 // global variables
681 //----------------------------------------------------------------------------//
682 
683 //! \name Variables
684 //! @{
685 
686 //! <boolean> Set to true to check configuration structure.
687 pcie_expansion_debug = false;
688 
689 //! <boolean> Set to true for verbose configuration checking.
691 
692 //! <map> Default riser board configuration.
694 
695 //! @}
696 
697 //----------------------------------------------------------------------------//
698 // functions
699 //----------------------------------------------------------------------------//
700 
701 //! \name Functions
702 //! @{
703 
704 //! Get riser board size for riser configuration.
705 /***************************************************************************//**
706  \param riser_pcb <map> The riser board configuration.
707  \param slots <integer> Optional slot count override.
708 
709  \returns <decimal-list-3> The riser board size [w, l, h].
710 *******************************************************************************/
711 function pcie_expansion_rb_size
712 (
713  riser_pcb,
714 
715  vslots
716 ) =
717  let
718  (
719  rb_vslot_count = is_undef( vslots ) ?
720  map_get_value(riser_pcb, "vslot_count")
721  : vslots,
722 
723  rb_slot_count = map_get_value(riser_pcb, "slot_count"),
724 
725  rb_slot1_to_edge1 = map_get_value(riser_pcb, "slot1_to_edge1"),
726  rb_slotn_to_edgen = map_get_value(riser_pcb, "slotn_to_edgen"),
727  rb_multi_slot_offset = map_get_value(riser_pcb, "multi_slot_offset"),
728  rb_slot_key_to_edgef = map_get_value(riser_pcb, "slot_key_to_edgef"),
729  rb_pcb_length = map_get_value(riser_pcb, "pcb_length"),
730  rb_pcb_th = map_get_value(riser_pcb, "pcb_th"),
731 
732  w = rb_slot1_to_edge1
733  + (rb_slot_count + max(0, rb_vslot_count) - 1) * rb_multi_slot_offset
734  + rb_slotn_to_edgen,
735 
736  l = rb_pcb_length,
737 
738  h = rb_pcb_th
739  )
740  [ w, l, h ];
741 
742 //! Get enclosure internal or external size.
743 /***************************************************************************//**
744  \param pcie_base <map> PCI-E standard common configuration.
745  \param pcie_form <map> PCI-E half or full configuration.
746  \param riser_pcb <map> The riser board configuration.
747  \param enclosure <map> The enclosure design configuration.
748 
749  \param riser_pcb_width <decimal> The riser board width.
750 
751  \param external <boolean> Set \b true to return external size and
752  \b false for internal size.
753 
754  \returns <decimal-list-3> The enclosure size [w, l, h].
755 *******************************************************************************/
756 function pcie_expansion_size
757 (
758  pcie_base = pcie_spec_common,
759  pcie_form = pcie_spec_half,
760  riser_pcb = riser_pcb_def,
761  enclosure = enclosure_def,
762 
763  riser_pcb_width,
764 
765  external = false
766 ) =
767  let
768  (
769  riser_width = is_undef( riser_pcb_width ) ?
770  first( pcie_expansion_rb_size(riser_pcb) )
771  : riser_pcb_width,
772 
773  // pcie
774  pcie_spec = map_merge(pcie_form, pcie_base),
775 
776  pcie_l_keya_2_bkto = map_get_value(pcie_spec, "l_keya_2_bkto"),
777  pcie_h_card_max = map_get_value(pcie_spec, "h_card_max"),
778  pcie_h_rbpcbt_2_fngrb = map_get_value(pcie_spec, "h_rbpcbt_2_fngrb"),
779 
780  // riser
781  rb_bottom_clearance = map_get_value(riser_pcb, "bottom_clearance"),
782  rb_pcb_th = map_get_value(riser_pcb, "pcb_th"),
783  rb_slot_key_to_edgef = map_get_value(riser_pcb, "slot_key_to_edgef"),
784 
785  // enclosure
786  encl_wth = map_get_value(enclosure, "wth"),
787  encl_board_count = map_get_value(enclosure, "board_count"),
788  encl_multi_board_offset = map_get_value(enclosure, "multi_board_offset"),
789  encl_space_add_edge1 = map_get_value(enclosure, "space_add_edge1"),
790  encl_space_add_edgen = map_get_value(enclosure, "space_add_edgen"),
791  encl_space_add_length = map_get_value(enclosure, "space_add_length"),
792  encl_space_add_height = map_get_value(enclosure, "space_add_height"),
793  encl_space_min_length = map_get_value(enclosure, "space_min_length"),
794  encl_space_min_height = map_get_value(enclosure, "space_min_height"),
795 
796  encl_rb_min_clearance = map_get_value(enclosure, "rb_min_clearance"),
797 
798  // riser board mount post height = (rib height + board bottom clearance)
799  rb_mount_post_height = encl_wth
800  + max(rb_bottom_clearance, encl_rb_min_clearance),
801 
802  w = riser_width
803  + (encl_board_count-1) * (riser_width + encl_multi_board_offset)
804  + encl_space_add_edge1
805  + encl_space_add_edgen,
806 
807  l = rb_slot_key_to_edgef
808  + pcie_l_keya_2_bkto
809  + encl_space_add_length,
810 
811  h = rb_mount_post_height
812  + rb_pcb_th
813  + pcie_h_rbpcbt_2_fngrb
814  + pcie_h_card_max
815  + encl_space_add_height,
816 
817  l_min = max(l, encl_space_min_length),
818  h_min = max(h, encl_space_min_height)
819  )
820  ( external ) ? [ w, l_min, h_min ] + [ encl_wth*2, encl_wth*2, encl_wth*2 ]
821  : [ w, l_min, h_min ];
822 
823 //! Get list of slot key locations of all riser boards.
824 /***************************************************************************//**
825  \param pcie_base <map> PCI-E standard common configuration.
826  \param pcie_form <map> PCI-E half or full configuration.
827  \param riser_pcb <map> The riser board configuration.
828  \param enclosure <map> The enclosure design configuration.
829 
830  \param riser_pcb_width <decimal> The riser board width.
831  \param enclosure_size <decimal-list-3> The enclosure's internal size.
832 
833  \param center_w <boolean> Use center of the enclosure as zero for
834  the widths.
835 
836  \param zero_lh <boolean> Zero the lengths and heights for each
837  slot location, corresponding to the enclosure location
838  [center, bottom].
839 
840  \param edge1_w <boolean> The initial offset is for each riser board
841  edge-1 rather than the slot-1 for board edge identification.
842 
843  \param adjust_h <boolean> Adjust all heights by the offset of the
844  enclosure sides and cover relative to the base when
845  assembled.
846 
847  \returns <datastruct> The location <decimal-list-3> of each slot on
848  each riser board; a <decimal-list-list-list-3> or
849  (board.slot.location_wlh).
850 *******************************************************************************/
852 (
853  pcie_base = pcie_spec_common,
854  pcie_form = pcie_spec_half,
855  riser_pcb = riser_pcb_def,
856  enclosure = enclosure_def,
857 
858  riser_pcb_width,
859  enclosure_size,
860 
861  center_w = true,
862  zero_lh = false,
863  edge1_w = false,
864  adjust_h = false
865 ) =
866  let
867  (
868  riser_width = is_undef( riser_pcb_width ) ?
869  first( pcie_expansion_rb_size(riser_pcb) )
870  : riser_pcb_width,
871 
872  encl_size_wlh = is_undef( enclosure_size ) ?
874  (
875  pcie_base,
876  pcie_form,
877  riser_pcb,
878  enclosure,
879 
880  riser_width
881  )
882  : enclosure_size,
883 
884  // pcie
885  pcie_spec = map_merge(pcie_form, pcie_base),
886 
887  pcie_l_keya_2_bkto = map_get_value(pcie_spec, "l_keya_2_bkto"),
888 
889  // riser
890  rb_slot_count = map_get_value(riser_pcb, "slot_count"),
891  rb_vslot_count = map_get_value(riser_pcb, "vslot_count"),
892  rb_multi_slot_offset = map_get_value(riser_pcb, "multi_slot_offset"),
893  rb_slot1_to_edge1 = map_get_value(riser_pcb, "slot1_to_edge1"),
894  rb_bottom_clearance = map_get_value(riser_pcb, "bottom_clearance"),
895 
896  // enclosure
897  encl_wth = map_get_value(enclosure, "wth"),
898  encl_board_count = map_get_value(enclosure, "board_count"),
899  encl_multi_board_offset = map_get_value(enclosure, "multi_board_offset"),
900  encl_space_add_edge1 = map_get_value(enclosure, "space_add_edge1"),
901 
902  encl_rb_min_clearance = map_get_value(enclosure, "rb_min_clearance"),
903 
904  // riser board mount post height = (rib height + board bottom clearance)
905  rb_mount_post_height = encl_wth
906  + max(rb_bottom_clearance, encl_rb_min_clearance),
907 
908  w_zero = + encl_space_add_edge1
909  + ( edge1_w ? 0 : rb_slot1_to_edge1 )
910  - ( ! center_w ? 0 : first(encl_size_wlh)/2 ),
911 
912  l_zero = zero_lh ? 0 : - second(encl_size_wlh)/2 + pcie_l_keya_2_bkto,
913  h_zero = zero_lh ? 0 : + encl_wth + rb_mount_post_height,
914 
915  h_zadj = adjust_h ? -encl_wth*2 : 0
916  )
917  [ // each riser board
918  for (rb_n = [0:encl_board_count-1])
919  [ // each riser board slot
920  for (rb_s = [0 : rb_slot_count + max(0, rb_vslot_count) - 1])
921  let
922  ( // instance offsets: board and board-slot
923  w_oi = rb_n * (riser_width + encl_multi_board_offset),
924  w_os = rb_s * rb_multi_slot_offset
925  )
926  [w_zero + w_oi + w_os, l_zero, h_zero + h_zadj]
927  ]
928  ];
929 
930 //! @}
931 
932 //----------------------------------------------------------------------------//
933 // modules
934 //----------------------------------------------------------------------------//
935 
936 //! \name Modules
937 //! @{
938 
939 //! \cond DOXYGEN_SHOULD_SKIP_THIS
941 {
943 
944  //
945  // check maps
946  //
947 
948  map_check(pcie_spec_common, verbose);
949  map_check(pcie_spec_full, verbose);
950  map_check(pcie_spec_half, verbose);
951 
953  map_check(riser_AAAPCIE4HUB, verbose);
955 
956  map_check(enclosure_def, verbose);
957 }
958 //! \endcond
959 
960 //! Generate a PCI Express expansion open chassis or closed enclosure
961 /***************************************************************************//**
962  \param pcie_base <map> PCI-E standard common configuration.
963  \param pcie_form <map> PCI-E half or full configuration.
964  \param riser_pcb <map> The riser board configuration.
965  \param enclosure <map> The enclosure design configuration.
966 
967  \param show_riser <boolean> Render model of riser board on the
968  enclosure base.
969 
970  \param part_color <color-list-6> a list of colors for each part;
971  [base, sides, cover, ...].
972 
973  \param part <integer> The part to construct; A binary encoded
974  integer value (see below).
975 
976  \param mode <integer> The construction orientation mode with
977  (0=design, 1=print, 2=assembled, 3=exploded, 4=build-plate).
978 
979  \param verb <integer> The output console verbosity.
980 
981  \details
982 
983  This module is designed to construct chassis and enclosures for
984  common Peripheral Component Interconnect Express (PCIe) riser
985  boards, which provide external access to PCIe slots. These riser
986  boards are commonly used to connect one or more GPUs, or other PCIe
987  cards, externally to a computer system. The module offers the
988  capability to generate both open chassis and closed enclosures.
989 
990  ## Multi-value and structured parameters
991 
992  ### part
993 
994  Integer value is binary encoded.
995 
996  b | description
997  ---:|:---------------------------------------
998  0 | base
999  1 | sides with in-place bracket mount tab shelf
1000  2 | cover
1001  3 | sides with female dovetails for use with separate mount tab
1002  4 | separate bracket mount tab with male dovetails
1003  5 | mount tab dovetail joint test assembly (design mode)
1004  6 | mount tab dovetail joint test build plate for fabrication
1005 
1006  Before fabricating a design that includes a dovetailed bracket
1007  mount tab, create and assemble a dovetail test joint to verify
1008  proper fit. Enable the test joint by setting part bit 6 to 1 (for
1009  example, `part = pow(2, 6))`. To refine or evaluate the dovetail
1010  configuration, model an assembled test joint by enabling \p part
1011  bit 5.
1012 
1013  \amu_define scope_id (example)
1014  \amu_define title (Enclosure customization example)
1015  \amu_define image_views (front right back diag)
1016  \amu_define image_columns (4)
1017  \amu_define image_size (sxga)
1018  \amu_define output_scad (true)
1019 
1020  \amu_include (include/amu/scope_diagrams_3d.amu)
1021 
1022  [PCIe]: https://en.wikipedia.org/wiki/PCI_Express
1023 *******************************************************************************/
1024 module pcie_expansion
1025 (
1026  pcie_base = pcie_spec_common,
1027  pcie_form = pcie_spec_half,
1028  riser_pcb = riser_pcb_def,
1029  enclosure = enclosure_def,
1030 
1031  show_riser = false,
1032 
1033  part_color,
1034 
1035  part = 7,
1036  mode = 3,
1037 
1038  verb = 0
1039 )
1040 {
1041  //
1042  // enclosure base
1043  //
1044  module enclosure_base(enable = 1+2)
1045  {
1046  // enable: B0: base, B1: wire_clamp
1047 
1048  // base
1049  encl_bracket_shoe_offset = map_get_value(enclosure, "bracket_shoe_offset");
1050  encl_holes_base = map_get_value(enclosure, "holes_base");
1051  encl_shapes_base = map_get_value(enclosure, "shapes_base");
1052 
1053  // sides and base
1054  encl_clamps_base = map_get_value(enclosure, "clamps_base");
1055  encl_bracket_shoe_gap_p = map_get_value(enclosure, "bracket_shoe_gap_p");
1056 
1057  // construct wire clamps
1058  module wire_clamps(mode)
1059  {
1060  for (clamp_sets = encl_clamps_base)
1061  {
1062  clamp_conf = first(clamp_sets);
1063  clamp_inst = second(clamp_sets);
1064 
1065  for (inst = clamp_inst)
1066  {
1067  eci_side = defined_e_or( inst, 0, [0, 0] );
1068  eci_rotate = defined_e_or( inst, 1, 0 );
1069  eci_align = defined_e_or( inst, 2, 1 );
1070  eci_offset = defined_e_or( inst, 3, [0, 0] );
1071 
1072  translate
1073  (
1074  [
1075  first(encl_size_wlh)/2 * first(eci_side) + first(eci_offset),
1076  second(encl_size_wlh)/2 * second(eci_side) + second(eci_offset),
1077  0
1078  ]
1079  )
1080  rotate([90, 0, eci_rotate])
1081  clamp_zt_1p
1082  (
1083  size = clamp_conf[0],
1084  ztie = clamp_conf[1],
1085  clamp = clamp_conf[2],
1086  tunnel = clamp_conf[3],
1087  vr = clamp_conf[4],
1088  vrm = clamp_conf[5],
1089 
1090  align = [0, 1, eci_align],
1091  mode = mode
1092  );
1093  }
1094  }
1095  }
1096 
1097  // model riser board
1098  module model_riser()
1099  {
1100  rb_slot_count = map_get_value(riser_pcb, "slot_count");
1101 
1102  rb_slot1_to_edge1 = map_get_value(riser_pcb, "slot1_to_edge1");
1103  rb_slot_key_to_edgef = map_get_value(riser_pcb, "slot_key_to_edgef");
1104 
1105  rb_slot_link_width = map_get_value(riser_pcb, "slot_link_width");
1106 
1107  rb_mount_holes = map_get_value(riser_pcb, "mount_holes");
1108  rb_post_hole_d = map_get_value(riser_pcb, "post_hole_d");
1109 
1110  // pcie slot lane width map and slot key offset
1111  sm = [ [1, 25], [4, 39], [8, 56], [16, 89] ];
1112  ko = 14.50;
1113 
1114  // slot size for riser lane width (use 1x when undefined)
1115  ss = [7.50, defined_or(map_get_value(sm, rb_slot_link_width), 25), 11.25];
1116 
1117  // riser and slot fixed offsets
1118  ro = [-rb_slot1_to_edge1, -riser_size0.y + rb_slot_key_to_edgef, 0];
1119  so = [-ss.x/2, -ko, rb_pcb_th];
1120 
1121  for (wlh_rb_inst = slot_keys_wlh)
1122  {
1123  // riser board pcd and mount holes
1124  difference()
1125  {
1126  wlh_rb_inst_o = first( wlh_rb_inst );
1127 
1128  translate(wlh_rb_inst_o + ro)
1129  cube(riser_size0, center=false);
1130 
1131  for (p = rb_mount_holes)
1132  translate(wlh_rb_inst_o + concat(p, -eps*2))
1133  cylinder(d=rb_post_hole_d, h=rb_pcb_th+eps*4, center=false);
1134  }
1135 
1136  // riser board slots; only show physical slots (skip vslots)
1137  for (i = [0 : rb_slot_count-1])
1138  {
1139  wlh_slot_inst = wlh_rb_inst[i];
1140 
1141  translate(wlh_slot_inst + so)
1142  cube(ss, center=false);
1143  }
1144  }
1145  }
1146 
1147  // rise board mount posts
1148  rb_mount_post_insts =
1149  let
1150  (
1151  rb_mount_holes = map_get_value(riser_pcb, "mount_holes"),
1152  rb_mount_holes_add = map_get_value(riser_pcb, "mount_holes_add"),
1153 
1154  rb_post_rotate = map_get_value(riser_pcb, "post_rotate"),
1155  rb_post_fins = map_get_value(riser_pcb, "post_fins"),
1156  rb_post_hole_d = map_get_value(riser_pcb, "post_hole_d"),
1157  rb_post_pad_d = map_get_value(riser_pcb, "post_pad_d"),
1158 
1159  insts = is_undef(rb_mount_holes_add) ?
1160  rb_mount_holes
1161  : concat(rb_mount_holes, rb_mount_holes_add)
1162  )
1163  [
1164  for (rb_s = slot_keys_wlh, pm_inst = insts)
1165  let
1166  (
1167  rb_s1 = first(rb_s), // board instance slot-1
1168  wl_o = [first(rb_s1), second(rb_s1)], // width and length offset
1169  post_h = third(rb_s1) - encl_wth // post height
1170  )
1171  [
1172  0, // type
1173  [0, 0], // zero
1174  wl_o + pm_inst, // move
1175  rb_post_rotate, // rotate
1176  undef, // hole0
1177  [rb_post_hole_d, post_h], // hole1
1178  [rb_post_pad_d, post_h], // post
1179  rb_post_fins // fins
1180  ]
1181  ];
1182 
1183  // merge all posts
1184  encl_posts_base_all =
1185  merge_post_inst_sets
1186  (
1187  encl_posts_base_conf,
1188  [ encl_posts_base, rb_mount_post_insts ],
1189  1, [ encl_posts ]
1190  );
1191 
1192  // reference: slot-1 of rb-1 [w, l, h]
1193  wlh_rb1s1_bwo =
1194  [
1195  -pcie_w_pcb_mth/2 - pcie_bkt_mth + pcie_w_bkt_tabo,
1196 
1197  -pcie_l_keya_2_bkto,
1199  rb_pcb_th
1200  + ( pcie_h_card_max - pcie_h_card_max_2_pciblck )
1201  + pcie_h_rbpcbt_2_fngrb
1202  + pcie_h_pciblck_2_bktb
1203  - pcie_h_bktb_2_bkttabb
1204  ];
1205 
1206  //
1207  // construct base
1208  //
1209  if ( binary_bit_is(enable, 0, 1) )
1210  difference()
1211  {
1212  // bracket shoe tab dimensions
1213  tab_sm = 1 + encl_bracket_shoe_gap_p;
1214  tab_ho = encl_bracket_shoe_offset;
1215 
1216  tab_so = pcie_w_bkt_width * (1 - tab_sm)/4;
1217 
1218  tab_bw = pcie_w_bkt_width * tab_sm;
1219  tab_tw = pcie_w_bkt_tab * tab_sm;
1220  tab_tl = pcie_bkt_mth * tab_sm;
1221  tab_th = pcie_h_bkt_tab * tab_sm;
1222 
1223  // enclosure base with tab shoe blocks
1224  union()
1225  {
1226  // enclosure base
1228  (
1229  wth = encl_wth,
1230  size = firstn(encl_size_wlh, 2),
1231  lid = encl_wth,
1232  h = encl_wth,
1233  lip = encl_lips_base,
1234  rib = encl_ribs,
1235  wall = encl_walls,
1236  post = encl_posts_base_all,
1237  hole = encl_holes_base,
1238  shape = encl_shapes_base,
1239  vr = encl_rounding,
1240  vrm = encl_mode_rounding,
1241  align = [0, 0, 0],
1242  mode = binary_or(encl_mode_proj_box, 1), // bit-0=1, others unchanged
1243  verb = encl_verb_proj_box
1244  );
1245 
1246  // add tab shoe (as needed for minimal insertion = encl_wth)
1247  for (wlh_rb_inst = slot_keys_wlh)
1248  for (wlh_slot_inst = wlh_rb_inst)
1249  let
1250  (
1251  so = wlh_slot_inst + wlh_rb1s1_bwo + [tab_so - encl_wth, 0, 0],
1252  // height for minimal insertion = encl_wth
1253  sh = max(encl_wth*2, third(so) + encl_wth),
1254  vrm = [1, 1, 4 ,3],
1255  vr = encl_wth/2
1256  )
1257  translate( firstn(so, 2) )
1258  extrude_linear_uss(sh)
1259  pg_rectangle([tab_tw+encl_wth*2, tab_tl + encl_wth], vrm=vrm, vr=vr);
1260  }
1261 
1262  // remove slot for bracket bottom shoe tab
1263  for (wlh_rb_inst = slot_keys_wlh)
1264  for (wlh_slot_inst = wlh_rb_inst)
1265  translate(wlh_slot_inst + wlh_rb1s1_bwo)
1266  rotate([90, 0, 0])
1267  translate([tab_so, tab_ho, -tab_tl])
1268  extrude_linear_uss(tab_tl)
1269  {
1270  pg_rectangle([tab_tw, tab_th]);
1271  pg_trapezoid(b=[tab_tw, tab_bw], h=tab_th, a=117.125, o=[0, tab_th]);
1272  }
1273 
1274  // remove wire clamp tunnels
1275  if ( binary_bit_is(enable, 1, 1) )
1276  wire_clamps(0);
1277  }
1278 
1279  // add wire clamps
1280  if ( binary_bit_is(enable, 1, 1) )
1281  wire_clamps(1);
1282 
1283  // model riser boards
1284  if ( show_riser == true )
1285  %model_riser();
1286  }
1287 
1288  //
1289  // enclosure sides
1290  //
1291  module enclosure_sides(enable = 1+2+4+8)
1292  {
1293  /*
1294  enable
1295 
1296  B0: sides
1297  B1: wire clamps passage hole
1298  B2: wire clamps passage cone
1299  B3: in-place bracket mount tab shelf
1300  B4: remove female dovetails from side for use with separate shelf
1301  B5: separate bracket mount tab shelf with male dovetails added
1302 
1303  mode_sides bits
1304 
1305  B0: add mount tab shelves
1306  B1: hull adjacent-slot mount tab shelf
1307  B2: hull removal of adjacent-slot connector windows
1308  B3: hull removal of adjacent-slot ribs from wall
1309  B4: hull removal of adjacent-slot bracket slide-down space
1310  B5: enable enclosure side cutting
1311  B6: cut enclosure front (positive side)
1312  B7: cut enclosure rear (negative side near bracket)
1313  B8: remove ribs on front edge of wall for riser PCB
1314  B9: remove ribs on front edge of wall for PCIE card PCB
1315  */
1316 
1317  // riser board
1318  rb_slot1_to_edge1 = map_get_value(riser_pcb, "slot1_to_edge1");
1319 
1320  // sides
1321  encl_rib_pcb_gap = map_get_value(enclosure, "rib_pcb_gap");
1322  encl_mode_sides = map_get_value(enclosure, "mode_sides");
1323  encl_cut_sides = map_get_value(enclosure, "cut_sides");
1324  encl_holes_sides = map_get_value(enclosure, "holes_sides");
1325  encl_shapes_sides = map_get_value(enclosure, "shapes_sides");
1326  encl_bracket_mount_tab = map_get_value(enclosure, "bracket_mount_tab");
1327 
1328  // sides and base
1329  encl_clamps_base = map_get_value(enclosure, "clamps_base");
1330  encl_bracket_window_gap = map_get_value(enclosure, "bracket_window_gap");
1331 
1332  // construct wire clamps and passage ways
1333  module wire_clamps_passage( mode )
1334  {
1335  for (clamp_sets = encl_clamps_base)
1336  {
1337  clamp_conf = first(clamp_sets);
1338  clamp_inst = second(clamp_sets);
1339 
1340  for (inst = clamp_inst)
1341  {
1342  eci_side = defined_e_or( inst, 0, [0, 0] );
1343  eci_rotate = defined_e_or( inst, 1, 0 );
1344  eci_align = defined_e_or( inst, 2, 1 );
1345  eci_offset = defined_e_or( inst, 3, [0, 0] );
1346  eci_passage = defined_e_or( inst, 4, [0, 0] );
1347 
1348  pass_enable = defined_e_or( eci_passage, 0, false );
1349  pass_hcut = defined_e_or( eci_passage, 1, 0 );
1350  pass_cone = defined_e_or( eci_passage, 2, undef );
1351 
1352  wire = clamp_conf[0];
1353 
1354  if ( pass_enable )
1355  translate
1356  (
1357  [
1358  first(encl_size_wlh)/2 * first(eci_side) + first(eci_offset),
1359  second(encl_size_wlh)/2 * second(eci_side) + second(eci_offset),
1360  -pass_hcut/2
1361  ]
1362  )
1363  rotate([90, 0, eci_rotate])
1364  clamp_cg
1365  (
1366  size = wire + [0, pass_hcut],
1367  cone = pass_cone,
1368  wth = encl_wth*2,
1369  gap = 10,
1370  mode = mode
1371  );
1372  }
1373  }
1374  }
1375 
1376  // bracket mount tab shelf and mount screw-hole
1377  module bracket_mount_tab_shelf
1378  (
1379  inplace = true,
1380  dovetail = false,
1381  dovetail_type = 0
1382  )
1383  {
1384  // selective move to bottom of sides with y-offset by encl_wth
1385  function zz_oy ( p ) = inplace ? p : [p.x, p.y - encl_wth*3, -encl_wth + wth];
1386 
1387  wth = defined_e_or(encl_bracket_mount_tab, 0, encl_wth); // tab thickness
1388  wa = defined_e_or(encl_bracket_mount_tab, 1, 0); // tab width addition
1389  hd = defined_e_or(encl_bracket_mount_tab, 2, 3.125); // screw hole diameter
1390  vr = defined_e_or(encl_bracket_mount_tab, 3, 0); // tab rounding radius
1391  vrm = defined_e_or(encl_bracket_mount_tab, 4, 1); // tab rounding modes
1392  dt = defined_e_or(encl_bracket_mount_tab, 5, [5, 6]); // dovetail configuration
1393 
1394  for (wlh_rb_inst = slot_keys_wlh)
1395  difference()
1396  {
1397  // mode_sides B1: hull adjacent-slot mount tab shelf
1398  hull_cs( binary_bit_is(encl_mode_sides, 1, 1) )
1399  for (wlh_slot_inst = wlh_rb_inst)
1400  translate( zz_oy (wlh_slot_inst + wlh_rb1s1_bwo) )
1401  {
1402  w_o = -wa + pcie_w_mnt_tab_o;
1403  l_o = -encl_wth;
1404  h_o = -wth;
1405 
1406  translate([w_o, l_o, h_o])
1407  mirror([0, 1, 0])
1408  extrude_linear_uss(wth, center=false)
1409  pg_rectangle(size=pcie_wl_mnt_tab + [2,0]*wa, vr=vr, vrm=vrm, center=false);
1410  }
1411 
1412  // mount tab screw hole
1413  for (wlh_slot_inst = wlh_rb_inst)
1414  translate( zz_oy (wlh_slot_inst + wlh_rb1s1_bwo) )
1415  {
1416  w_o = 0;
1417  l_o = +pcie_l_keya_2_bkto;
1418  h_o = -wth/2;
1419 
1420  translate([w_o, l_o, h_o] + concat(pcie_wl_mnt_hole_o, 0))
1421  cylinder(d=hd, h=wth+eps*4, center=true);
1422  }
1423  }
1424 
1425  // add dovetails
1426  for (wlh_rb_inst = slot_keys_wlh, wlh_slot_inst = wlh_rb_inst)
1427  translate( zz_oy (wlh_slot_inst + wlh_rb1s1_bwo) )
1428  {
1429  // dovetail configuration
1430  w = first( pcie_wl_mnt_tab );
1431  d = encl_wth + eps*4;
1432 
1433  w_o = pcie_w_mnt_tab_o;
1434  l_o = -encl_wth;
1435  h_o = -wth;
1436 
1437  translate([w_o, l_o, h_o])
1438  extrude_linear_uss(wth, center=false)
1439  joint2d_dovetail(t=dt, d=d, w=w, center=true, type=dovetail_type);
1440  }
1441  }
1442 
1443  // cut enclosure sides
1444  module cut_enclosure_sides( cut_sides )
1445  {
1446  // external enclosure size (ignoring protrusions).
1447  es = encl_size_wlh
1448  + [2, 2, 1] * encl_wth
1449  + [4, 4, 2] * eps;
1450 
1451  sco = defined_e_or(cut_sides, 0, es.y/10);
1452  vr = defined_e_or(cut_sides, 1, 0);
1453  vrm = defined_e_or(cut_sides, 2, 0);
1454 
1455  bbo = defined_e_or(sco, 0, sco);
1456  bto = defined_e_or(sco, 1, bbo);
1457  fto = defined_e_or(sco, 2, bto);
1458  fbo = defined_e_or(sco, 3, bbo);
1459 
1461  (
1462  [
1463  [+(es.y/2 - fbo), 0],
1464  [-(es.y/2 - bbo), 0],
1465  [-(es.y/2 - bto), es.z],
1466  [+(es.y/2 - fto), es.z],
1467  ],
1468  vr=vr,
1469  vrm=vrm
1470  );
1471 
1472  translate([0, 0, -encl_wth])
1473  rotate([90, 0, 90])
1474  extrude_linear_uss(es.x * 2, center=true)
1475  union()
1476  {
1477  polygon( cp );
1478 
1479  // mode_sides B6-7: remove enclosure front and/or rear side walls
1480  for ( x = [0, 1] )
1481  if ( binary_bit_is(encl_mode_sides, 6+x, 1) )
1482  mirror([x, 0])
1483  pg_rectangle([es.y, es.z]);
1484  }
1485  }
1486 
1487  // merge all posts
1488  encl_posts_sides_all =
1489  merge_post_inst_sets
1490  (
1491  encl_posts_sides_conf,
1492  [ encl_posts_sides ],
1493  0, [ encl_posts ]
1494  );
1495 
1496  // reference: base to sides zero alignment
1497  wlh_s2b_ao = [ 0, 0, encl_wth*2 ];
1498 
1499  // reference: slot-1 of rb-1 [w, l, h]
1500  wlh_rb1s1_bwo =
1501  [
1502  0,
1503 
1504  -pcie_l_keya_2_bkto,
1505 
1506  rb_pcb_th
1507  + ( pcie_h_card_max - pcie_h_card_max_2_pciblck )
1508  + pcie_h_rbpcbt_2_fngrb
1509  + pcie_h_pciblck_2_bktb
1510  ] - wlh_s2b_ao;
1511 
1512  // decode ribs configuration
1513  decode_ribs = defined_e_or(encl_ribs, 0, encl_ribs);
1514 
1515  // mode bit-0=1, others unchanged (to ensure no ribs on lid section)
1516  masked_ribs = binary_or(decode_ribs, 1);
1517 
1518  // repackage ribs configuration
1519  encode_ribs = is_list(encl_ribs) ?
1520  concat(masked_ribs, tailn(encl_ribs))
1521  : masked_ribs;
1522 
1523  //
1524  // construct sides
1525  //
1526  if ( binary_bit_is(enable, 0, 1) )
1527  difference()
1528  {
1529  union()
1530  {
1531  // enclosure sides
1533  (
1534  wth = encl_wth,
1535  size = firstn(encl_size_wlh, 2),
1536  lid = undef,
1537  h = third(encl_size_wlh),
1538  lip = encl_lips_sides,
1539  rib = encode_ribs,
1540  wall = encl_walls,
1541  post = encl_posts_sides_all,
1542  hole = encl_holes_sides,
1543  shape = encl_shapes_sides,
1544  vr = encl_rounding,
1545  vrm = encl_mode_rounding,
1546  align = [0, 0, 0],
1547  mode = binary_or(encl_mode_proj_box, 1), // bit-0=1, others unchanged
1548  verb = encl_verb_proj_box
1549  );
1550 
1551  // add cone to wire clamp passage hole
1552  if ( binary_bit_is(enable, 2, 1) )
1553  translate(wlh_s2b_ao)
1554  wire_clamps_passage(1);
1555 
1556  // mode_sides B0: add bracket mount tab shelf and mount screw-hole(s)
1557  if ( binary_bit_is(enable, 3, 1) && binary_bit_is(encl_mode_sides, 0, 1) )
1558  bracket_mount_tab_shelf(inplace=true, dovetail=false);
1559  }
1560 
1561  // project_box_rectangle() default rib height = encl_wth
1562  rib_h = encl_wth * 2;
1563 
1564  // bracket window features gap [w]
1565  gap_w = encl_bracket_window_gap;
1566 
1567  // remove per-board x per-slot features
1568  for (wlh_rb_inst = slot_keys_wlh)
1569  {
1570  // mode_sides B2: remove connector window
1571  hull_cs( binary_bit_is(encl_mode_sides, 2, 1) )
1572  for (wlh_slot_inst = wlh_rb_inst)
1573  translate(wlh_slot_inst + wlh_rb1s1_bwo)
1574  {
1575  w = pcie_wh_copen_window; // window
1576  e = encl_wth + rib_h; // extrude
1577  r = [-90, 0, 0]; // rotation
1578  t = [ pcie_w_pcb_mth/2 + pcie_w_pcb_2_copen,
1579  -encl_wth - eps*4,
1580  -pcie_h_bktb_2_copen ];
1581 
1582  translate( t - [gap_w/2, 0, 0] ) rotate( r )
1583  extrude_linear_uss(e, center=false)
1584  pg_rectangle(size=w + [gap_w, 0, 0], center=false);
1585  }
1586 
1587  // mode_sides B3: remove ribs from wall
1588  hull_cs( binary_bit_is(encl_mode_sides, 3, 1) )
1589  for (wlh_slot_inst = wlh_rb_inst)
1590  translate(wlh_slot_inst + wlh_rb1s1_bwo)
1591  {
1592  w = [pcie_w_bkt_width, pcie_h_bktb_2_bkttabb];
1593  e = rib_h + eps*4;
1594  r = [-90, 0, 0];
1595  t = [ -pcie_w_pcb_mth/2 - pcie_bkt_mth, 0, 0 ];
1596 
1597  translate( t - [gap_w/2, 0, 0] ) rotate( r )
1598  extrude_linear_uss(e, center=false)
1599  pg_rectangle(size=w + [gap_w, 0, 0], center=false);
1600  }
1601 
1602  // mode_sides B4: remove slide-down space for bracket mount tab
1603  hull_cs( binary_bit_is(encl_mode_sides, 4, 1) )
1604  for (wlh_slot_inst = wlh_rb_inst)
1605  translate(wlh_slot_inst + wlh_rb1s1_bwo)
1606  {
1607  w = pcie_wl_mnt_tab + [0, rib_h];
1608  e = pcie_h_connector_max - pcie_h_rbpcbt_2_fngrb + pcie_bkt_mth;
1609  r = [0, 0, 0];
1610  t = [ pcie_w_mnt_tab_o, -second(pcie_wl_mnt_tab), 0 ];
1611 
1612  translate( t - [gap_w/2, 0, 0] ) rotate( r )
1613  extrude_linear_uss(e, center=false)
1614  pg_rectangle(size=w + [gap_w, 0, 0], center=false);
1615  }
1616 
1617  // mode_sides B8: remove ribs on front edge of wall for riser PCB
1618  if ( binary_bit_is(encl_mode_sides, 8, 1) )
1619  {
1620  // position of slot-1 of riser board instance
1621  wlh_rbs1 = first( wlh_rb_inst );
1622 
1623  // reference: slot-1 key on front interior wall at base of riser
1624  wlh_rb1s1_fwo =
1625  [
1626  wlh_rbs1.x - rb_slot1_to_edge1,
1627  encl_size_wlh.y/2,
1628  wlh_rbs1.z
1629  ];
1630 
1631  g = [encl_rib_pcb_gap, encl_rib_pcb_gap];
1632 
1633  translate( wlh_rb1s1_fwo )
1634  {
1635  w = [riser_size0.x, riser_size0.z] + g;
1636  e = rib_h + eps*8;
1637  r = [90, 0, 0];
1638  t = [ -g.x/2, eps*4, -g.y/2-rib_h ];
1639 
1640  translate( t ) rotate( r )
1641  extrude_linear_uss(e, center=false)
1642  pg_rectangle(size=w, center=false);
1643  }
1644  }
1645 
1646  // mode_sides B9: remove ribs on front edge of wall for PCIE card PCB
1647  if ( binary_bit_is(encl_mode_sides, 9, 1) )
1648  {
1649  for (wlh_slot_inst = wlh_rb_inst)
1650  {
1651  // reference: slot-1 key on front interior wall at base of riser
1652  wlh_rb1s1_fwo =
1653  [
1654  wlh_slot_inst.x,
1655  encl_size_wlh.y/2,
1656  wlh_slot_inst.z
1657  ];
1658 
1659  g = [encl_rib_pcb_gap, 0];
1660 
1661  translate( wlh_rb1s1_fwo )
1662  {
1663  w = [pcie_w_pcb_mth, encl_size_wlh.z] + g;
1664  e = rib_h + eps*8;
1665  r = [90, 0, 0];
1666  t = [ -g.x/2 - pcie_w_pcb_mth/2, eps*4, -g.y/2-rib_h ];
1667 
1668  translate( t ) rotate( r )
1669  extrude_linear_uss(e, center=false)
1670  pg_rectangle(size=w, center=false);
1671  }
1672  }
1673  }
1674  }
1675 
1676  // remove wire clamp passage hole
1677  if ( binary_bit_is(enable, 1, 1) )
1678  translate(wlh_s2b_ao)
1679  wire_clamps_passage(0);
1680 
1681  // mode_sides B5: cut sides for open enclosure modes
1682  if ( binary_bit_is(encl_mode_sides, 5, 1) )
1683  cut_enclosure_sides( encl_cut_sides );
1684 
1685  // remove bracket mount tab shelf dovetail slots
1686  if ( binary_bit_is(enable, 4, 1) && binary_bit_is(encl_mode_sides, 0, 1) )
1687  bracket_mount_tab_shelf(inplace=true, dovetail=true, dovetail_type=2);
1688  }
1689 
1690  //
1691  // separate bracket mount tab shelf with dovetail joint
1692  //
1693  if ( binary_bit_is(enable, 5, 1) && binary_bit_is(encl_mode_sides, 0, 1) )
1694  bracket_mount_tab_shelf(inplace=false, dovetail=true, dovetail_type=0);
1695  }
1696 
1697  //
1698  // enclosure cover
1699  //
1700  module enclosure_cover(enable = 1)
1701  {
1702  // enable: B0: base
1703 
1704  // cover
1705  encl_holes_cover = map_get_value(enclosure, "holes_cover");
1706  encl_shapes_cover = map_get_value(enclosure, "shapes_cover");
1707 
1708  // merge all posts
1709  encl_posts_cover_all =
1710  merge_post_inst_sets
1711  (
1712  encl_posts_cover_conf,
1713  [ encl_posts_cover ],
1714  1, [ encl_posts ]
1715  );
1716 
1717  //
1718  // construct cover
1719  //
1720  if ( binary_bit_is(enable, 0, 1) )
1721  mirror([ 0, 0, 1])
1723  (
1724  wth = encl_wth,
1725  size = firstn(encl_size_wlh, 2),
1726  lid = encl_wth,
1727  h = encl_wth*2,
1728  lip = encl_lips_cover,
1729  rib = encl_ribs,
1730  wall = encl_walls,
1731  post = encl_posts_cover_all,
1732  hole = encl_holes_cover,
1733  shape = encl_shapes_cover,
1734  vr = encl_rounding,
1735  vrm = encl_mode_rounding,
1736  align = [0, 0, 0],
1737  mode = binary_or(encl_mode_proj_box, 1), // bit-0=1, others unchanged
1738  verb = encl_verb_proj_box
1739  );
1740  }
1741 
1742  //
1743  // dovetail joint test assemble
1744  //
1745  module dovetail_test(select = 0)
1746  {
1747  encl_bracket_mount_tab = map_get_value(enclosure, "bracket_mount_tab");
1748 
1749  wth = defined_e_or(encl_bracket_mount_tab, 0, encl_wth);
1750  dt = defined_e_or(encl_bracket_mount_tab, 5, [5, 6]);
1751 
1752  w = first( pcie_wl_mnt_tab );
1753  d = encl_wth + eps*4;
1754  x = w / 5;
1755 
1756  // assembled joint
1757  if (select == 0)
1758  {
1759  difference()
1760  {
1761  translate([-x/2, +eps*2, -wth/2-eps*2])
1762  cube([w+x, d-eps*4, wth*3/2], center=false);
1763  extrude_linear_uss(wth, center=false)
1764  joint2d_dovetail(t=dt, d=d, w=w, center=true, type=2);
1765  }
1766 
1767  #union()
1768  {
1769  extrude_linear_uss(wth, center=false)
1770  joint2d_dovetail(t=dt, d=d, w=w, center=true, type=0);
1771  translate([-x/2, -d, 0])
1772  cube([w+x, d, wth], center=false);
1773  }
1774  }
1775 
1776  // test joint build plate for 3d printer
1777  if (select == 1)
1778  {
1779  // female joint printed horizontally
1780  translate([0, wth + d*2, 0])
1781  rotate([90, 0, 0])
1782  difference()
1783  {
1784  translate([-x/2, +eps*2, -wth/2-eps*2])
1785  cube([w+x, d-eps*4, wth*3/2], center=false);
1786  extrude_linear_uss(wth, center=false)
1787  joint2d_dovetail(t=dt, d=d, w=w, center=true, type=2);
1788  }
1789 
1790  // female joint printed vertically
1791  translate([0, 0, +wth/2])
1792  difference()
1793  {
1794  translate([-x/2, +eps*2, -wth/2-eps*2])
1795  cube([w+x, d-eps*4, wth*3/2], center=false);
1796  extrude_linear_uss(wth, center=false)
1797  joint2d_dovetail(t=dt, d=d, w=w, center=true, type=2);
1798  }
1799 
1800  // male joint
1801  translate([0, -d*2, 0])
1802  union()
1803  {
1804  extrude_linear_uss(wth, center=false)
1805  joint2d_dovetail(t=dt, d=d, w=w, center=true, type=0);
1806  translate([-x/2, -d, 0])
1807  cube([w+x, d, wth], center=false);
1808  }
1809  }
1810  }
1811 
1812  //
1813  // merge post instances
1814  //
1815  function merge_post_inst_sets
1816  (
1817  post_configuration,
1818  local_instance_sets,
1819  global_type_append,
1820  global_instance_sets
1821  ) =
1822  [
1823  post_configuration,
1824 
1825  [ // copy local instances unchanged
1826  for (set = local_instance_sets)
1827  for (instance = set)
1828  instance,
1829 
1830  // update type for global instances
1831  for (set = global_instance_sets)
1832  for (instance = set)
1833  let
1834  (
1835  type = first(instance),
1836  inst = tailn(instance)
1837  )
1838  concat(type + global_type_append, inst)
1839  ]
1840  ];
1841 
1842  //
1843  // module global variables
1844  //
1845 
1846  // pci specification:
1847  pcie_spec = map_merge(pcie_form, pcie_base);
1848 
1849  pcie_h_connector_max = map_get_value(pcie_spec, "h_connector_max");
1850  pcie_l_keya_2_bkto = map_get_value(pcie_spec, "l_keya_2_bkto");
1851  pcie_w_bkt_width = map_get_value(pcie_spec, "w_bkt_width");
1852  pcie_w_pcb_mth = map_get_value(pcie_spec, "w_pcb_mth");
1853  pcie_h_rbpcbt_2_fngrb = map_get_value(pcie_spec, "h_rbpcbt_2_fngrb");
1854  pcie_bkt_mth = map_get_value(pcie_spec, "bkt_mth");
1855  pcie_h_card_max = map_get_value(pcie_spec, "h_card_max");
1856  pcie_h_card_max_2_pciblck = map_get_value(pcie_spec, "h_card_max_2_pciblck");
1857  pcie_h_pciblck_2_bktb = map_get_value(pcie_spec, "h_pciblck_2_bktb");
1858  pcie_h_bktb_2_bkttabb = map_get_value(pcie_spec, "h_bktb_2_bkttabb");
1859  pcie_w_bkt_tab = map_get_value(pcie_spec, "w_bkt_tab");
1860  pcie_h_bkt_tab = map_get_value(pcie_spec, "h_bkt_tab");
1861  pcie_w_bkt_tabo = map_get_value(pcie_spec, "w_bkt_tabo");
1862  pcie_wh_copen_window = map_get_value(pcie_spec, "wh_copen_window");
1863  pcie_h_bktb_2_copen = map_get_value(pcie_spec, "h_bktb_2_copen");
1864  pcie_w_pcb_2_copen = map_get_value(pcie_spec, "w_pcb_2_copen");
1865  pcie_wl_mnt_tab = map_get_value(pcie_spec, "wl_mnt_tab");
1866  pcie_w_mnt_tab_o = map_get_value(pcie_spec, "w_mnt_tab_o");
1867  pcie_wl_mnt_hole_o = map_get_value(pcie_spec, "wl_mnt_hole_o");
1868 
1869  // riser board:
1870  rb_pcb_th = map_get_value(riser_pcb, "pcb_th");
1871 
1872  // enclosure: common (base, sides, cover)
1873  encl_rounding = map_get_value(enclosure, "rounding");
1874  encl_mode_rounding = map_get_value(enclosure, "mode_rounding");
1875  encl_wth = map_get_value(enclosure, "wth");
1876  encl_ribs = map_get_value(enclosure, "ribs");
1877  encl_lips_sides = map_get_value(enclosure, "lips_sides");
1878  encl_lips_base = map_get_value(enclosure, "lips_base");
1879  encl_lips_cover = map_get_value(enclosure, "lips_cover");
1880  encl_walls = map_get_value(enclosure, "walls");
1881  encl_mode_proj_box = map_get_value(enclosure, "mode_proj_box");
1882  encl_verb_proj_box = map_get_value(enclosure, "verb_proj_box");
1883 
1884  // enclosure: posts (base, sides, cover)
1885  encl_posts_sides_conf = map_get_value(enclosure, "posts_sides_conf");
1886  encl_posts_base_conf = map_get_value(enclosure, "posts_base_conf");
1887  encl_posts_cover_conf = map_get_value(enclosure, "posts_cover_conf");
1888  encl_posts_sides = map_get_value(enclosure, "posts_sides");
1889  encl_posts_base = map_get_value(enclosure, "posts_base");
1890  encl_posts_cover = map_get_value(enclosure, "posts_cover");
1891  encl_posts = map_get_value(enclosure, "posts");
1892 
1893  // rise board width
1894  riser_size0 = pcie_expansion_rb_size(riser_pcb, 0);
1895  riser_size = pcie_expansion_rb_size(riser_pcb);
1896  riser_width = first( riser_size );
1897 
1898  // enclosure internal size
1899  encl_size_wlh = pcie_expansion_size
1900  (
1901  pcie_base,
1902  pcie_form,
1903  riser_pcb,
1904  enclosure,
1905 
1906  riser_width,
1907  false
1908  );
1909 
1910  // riser boards and slot key offsets
1911  slot_keys_wlh = pcie_expansion_rbs_keys
1912  (
1913  pcie_base,
1914  pcie_form,
1915  riser_pcb,
1916  enclosure,
1917 
1918  riser_width,
1919  encl_size_wlh,
1920 
1921  true,
1922  false,
1923  false
1924  );
1925 
1926  //
1927  // main: enclosure construction
1928  //
1929 
1930  if (verb > 0)
1931  {
1932  encl_size_int = encl_size_wlh;
1933  encl_size_ext = pcie_expansion_size
1934  (
1935  pcie_base,
1936  pcie_form,
1937  riser_pcb,
1938  enclosure,
1939 
1940  riser_width,
1941  true
1942  );
1943 
1944  echo(strl([parent_module(0), ".size.exterior: [w, l, h] = ", encl_size_ext]));
1945  echo(strl([parent_module(0), ".size.interior: [w, l, h] = ", encl_size_int]));
1946  }
1947 
1948  // mode: construction orientation configurations [rotate, translate]
1949  rt_base_sides_cover =
1950  let
1951  (
1952  nop = [0, 0, 0],
1953  t = encl_wth,
1954  w = first(encl_size_wlh),
1955  h = third(encl_size_wlh),
1956  s = t * 10, // "explode-view" separation
1957  b = t * 8, // build plate separation
1958  e = eps*2 // assembled view overlap
1959  )
1960  [ // [0=design, 1=print, 2=assembled, 3=exploded, 4=build-plate]
1961  [ // base
1962  [nop, nop],
1963  [nop, nop],
1964  [nop, [0, 0, -t-h/2+e]],
1965  [nop, [0, 0, -s-t-h/2]],
1966  [nop, [-b-w, 0, 0]]
1967  ],
1968  [ // sides
1969  [nop, nop],
1970  [nop, [0, 0, t]],
1971  [nop, [0, 0, t-h/2]],
1972  [nop, [0, 0, t-h/2]],
1973  [nop, [0, 0, t]],
1974  ],
1975  [ // cover
1976  [nop, nop],
1977  [[0, 180, 0], nop],
1978  [nop, [0, 0, +t*2+h/2]],
1979  [nop, [0, 0, +s+t*2+h/2]],
1980  [[0, 180, 0], [b+w, 0, 0]]
1981  ]
1982  ];
1983 
1984  rt_base = select_ci( first(rt_base_sides_cover), mode, false);
1985  rt_sides = select_ci(second(rt_base_sides_cover), mode, false);
1986  rt_cover = select_ci( third(rt_base_sides_cover), mode, false);
1987 
1988  // part construction control
1989  module construct_ctrl( bit, rt )
1990  {
1991  if ( binary_bit_is(part, bit, 1) )
1992  color(defined_e_or(part_color, bit, undef))
1993  translate(second(rt))
1994  rotate(first(rt))
1995  children();
1996  }
1997 
1998  // base
1999  construct_ctrl( 0, rt_base )
2000  enclosure_base();
2001 
2002  // sides with in-place bracket mount tab shelf
2003  construct_ctrl( 1, rt_sides )
2004  enclosure_sides(1+2+4+8);
2005 
2006  // cover
2007  construct_ctrl( 2, rt_cover )
2008  enclosure_cover();
2009 
2010  // sides with female dovetails for use with separate shelf
2011  construct_ctrl( 3, rt_sides )
2012  enclosure_sides(1+2+4+16);
2013 
2014  // separate bracket mount tab shelf with male dovetails
2015  construct_ctrl( 4, rt_sides )
2016  enclosure_sides(32);
2017 
2018  // dovetail joint test assembly
2019  construct_ctrl( 5, [zero3d, origin3d] )
2020  dovetail_test(0);
2021 
2022  // dovetail joint test build plate
2023  construct_ctrl( 6, [zero3d, origin3d] )
2024  dovetail_test(1);
2025 }
2026 
2027 //! @}
2028 
2029 //! @}
2030 //! @}
2031 
2032 
2033 //----------------------------------------------------------------------------//
2034 // openscad-amu auxiliary scripts
2035 //----------------------------------------------------------------------------//
2036 
2037 /*
2038 BEGIN_SCOPE example;
2039  BEGIN_OPENSCAD;
2040  include <omdl-base.scad>;
2041  include <shapes/select_common_2d.scad>;
2042  include <shapes/select_common_3d.scad>;
2043  include <transforms/base_cs.scad>;
2044  include <transforms/layout.scad>;
2045  include <models/2d/joint/dovetail.scad>;
2046  include <parts/3d/fastener/clamps.scad>;
2047  include <parts/3d/enclosure/project_box_rectangle.scad>;
2048  include <parts/3d/computer/pcie_expansion.scad>;
2049 
2050  encl_conf =
2051  [
2052  ["board_count", 1],
2053  ["space_min_length", 238],
2054  ["mode_sides", 1]
2055  ];
2056 
2057  custom_encl = map_merge( encl_conf, enclosure_def );
2058  map_check( custom_encl );
2059 
2060  pcie_expansion( enclosure=custom_encl, verb=1 );
2061 
2062  // end_include
2063  END_OPENSCAD;
2064 
2065  BEGIN_MFSCRIPT;
2066  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
2067  table_unset_all sizes;
2068 
2069  images name "sizes" types "sxga";
2070  views name "views" views "front right back diag";
2071 
2072  variables set_opts_combine "sizes views";
2073  variables add_opts "--viewall --autocenter --view=axes";
2074 
2075  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
2076  END_MFSCRIPT;
2077 END_SCOPE;
2078 */
2079 
2080 /*
2081 BEGIN_SCOPE riser_PCE164P_NO3_VER_007;
2082  BEGIN_OPENSCAD;
2083  include <omdl-base.scad>;
2084  include <transforms/base_cs.scad>;
2085  include <parts/3d/fastener/clamps.scad>;
2086  include <parts/3d/enclosure/project_box_rectangle.scad>;
2087  include <parts/3d/computer/pcie_expansion.scad>;
2088 
2089  map = riser_PCE164P_NO3_VER_007;
2090  doc = riser_map_doc;
2091 
2092  table_write
2093  (
2094  r = map_to_table( [map, doc], sort=true ),
2095  c = [["key","key"], ["value","value"], ["description","description"]]
2096  );
2097  END_OPENSCAD;
2098 
2099  BEGIN_MFSCRIPT;
2100  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
2101  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
2102  END_MFSCRIPT;
2103 END_SCOPE;
2104 
2105 BEGIN_SCOPE riser_AAAPCIE4HUB;
2106  BEGIN_OPENSCAD;
2107  include <omdl-base.scad>;
2108  include <transforms/base_cs.scad>;
2109  include <parts/3d/fastener/clamps.scad>;
2110  include <parts/3d/enclosure/project_box_rectangle.scad>;
2111  include <parts/3d/computer/pcie_expansion.scad>;
2112 
2113  map = riser_AAAPCIE4HUB;
2114  doc = riser_map_doc;
2115 
2116  table_write
2117  (
2118  r = map_to_table( [map, doc], sort=true ),
2119  c = [["key","key"], ["value","value"], ["description","description"]]
2120  );
2121  END_OPENSCAD;
2122 
2123  BEGIN_MFSCRIPT;
2124  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
2125  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
2126  END_MFSCRIPT;
2127 END_SCOPE;
2128 
2129 BEGIN_SCOPE riser_SFF_8612_4X_to_PCI_E_16X;
2130  BEGIN_OPENSCAD;
2131  include <omdl-base.scad>;
2132  include <transforms/base_cs.scad>;
2133  include <parts/3d/fastener/clamps.scad>;
2134  include <parts/3d/enclosure/project_box_rectangle.scad>;
2135  include <parts/3d/computer/pcie_expansion.scad>;
2136 
2137  map = riser_SFF_8612_4X_to_PCI_E_16X;
2138  doc = riser_map_doc;
2139 
2140  table_write
2141  (
2142  r = map_to_table( [map, doc], sort=true ),
2143  c = [["key","key"], ["value","value"], ["description","description"]]
2144  );
2145  END_OPENSCAD;
2146 
2147  BEGIN_MFSCRIPT;
2148  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
2149  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
2150  END_MFSCRIPT;
2151 END_SCOPE;
2152 */
2153 
2154 /*
2155 BEGIN_SCOPE enclosure_def;
2156  BEGIN_OPENSCAD;
2157  include <omdl-base.scad>;
2158  include <transforms/base_cs.scad>;
2159  include <parts/3d/fastener/clamps.scad>;
2160  include <parts/3d/enclosure/project_box_rectangle.scad>;
2161  include <parts/3d/computer/pcie_expansion.scad>;
2162 
2163  map = enclosure_def;
2164  doc = enclosure_map_doc;
2165 
2166  table_write
2167  (
2168  r = map_to_table( [map, doc], sort=true ),
2169  c = [["key","key"], ["value","value"], ["description","description"]]
2170  );
2171  END_OPENSCAD;
2172 
2173  BEGIN_MFSCRIPT;
2174  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
2175  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
2176  END_MFSCRIPT;
2177 END_SCOPE;
2178 */
2179 
2180 //----------------------------------------------------------------------------//
2181 // end of file
2182 //----------------------------------------------------------------------------//
origin3d
<point-3d> The origin point coordinate in 3-dimensional Euclidean space.
Definition: constants.scad:425
zero3d
<decimal-list-2> A 3d zero vector (a list with three zeros).
Definition: constants.scad:422
eps
<decimal> Epsilon, small distance to deal with overlapping shapes.
Definition: constants.scad:195
function binary_ishl(v, s=1)
Base-2 binary left-shift operation for an integer.
function binary_bit_is(v, b, t=1)
Test if a binary bit position of an integer value equals a test bit.
function binary_or(v1, v2, _bv=1)
Base-2 binary OR operation for integers.
function firstn(v, n=1)
Return a list containing the first n elements of an iterable value.
function defined_e_or(v, i, d)
Returns an element from an iterable if it exists, or a default value if not.
function third(v)
Return the third element of an iterable value.
function second(v)
Return the second element of an iterable value.
function first(v)
Return the first element of an iterable value.
function tailn(v, n=1)
Return a list containing all but the first n elements of an iterable value.
function select_ci(v, i, l=true)
Select specified element from list or return a default.
function strl(v)
Convert a list of values to a concatenated string.
function map_get_value(m, k)
Get the map value associated with a key.
module map_check(m, verbose=false)
Perform basic format checks on a map and output errors to console.
Definition: map.scad:788
function map_merge(m1, m2)
Merge the unique key-value pairs of a second map with those of a first.
function defined_or(v, d)
Return given value, if defined, or a secondary value, if primary is not defined.
function polygon_round_eve_all_p(c, vr=0, vrm=1, vfn, w=true, cw=true)
Compute coordinates that round all of the vertices between each adjacent edges in 2D.
module joint2d_dovetail(t=1, d=1, w=10, o=0, type=0, trim=false, center=false, align)
Create 2D edge profiles for dovetail joint construction.
Definition: dovetail.scad:380
riser_pcb_def
<map> Default riser board configuration.
pcie_expansion_debug
<boolean> Set to true to check configuration structure.
function pcie_expansion_rb_size(riser_pcb, vslots)
Get riser board size for riser configuration.
riser_PCE164P_NO3_VER_007
<map> USB 3.0 PCE164P-NO3 VER 007 1-slot riser board.
pcie_spec_half
pcie_spec_full
riser_SFF_8612_4X_to_PCI_E_16X
<map> SFF-8612 4X lane to 16X 1-slot riser board.
function pcie_expansion_size(pcie_base=pcie_spec_common, pcie_form=pcie_spec_half, riser_pcb=riser_pcb_def, enclosure=enclosure_def, riser_pcb_width, external=false)
Get enclosure internal or external size.
enclosure_def
<map> Default enclosure configuration.
pcie_spec_common
module pcie_expansion(pcie_base=pcie_spec_common, pcie_form=pcie_spec_half, riser_pcb=riser_pcb_def, enclosure=enclosure_def, show_riser=false, part_color, part=7, mode=3, verb=0)
Generate a PCI Express expansion open chassis or closed enclosure.
pcie_expansion_debug_verbose
<boolean> Set to true for verbose configuration checking.
riser_AAAPCIE4HUB
<map> AAAPCIE4HUB multiplier HUB 4-slot riser board.
function pcie_expansion_rbs_keys(pcie_base=pcie_spec_common, pcie_form=pcie_spec_half, riser_pcb=riser_pcb_def, enclosure=enclosure_def, riser_pcb_width, enclosure_size, center_w=true, zero_lh=false, edge1_w=false, adjust_h=false)
Get list of slot key locations of all riser boards.
module project_box_rectangle(wth, h, size, vr, vrm, inset, lid, lip, rib, wall, post, hole, shape, align, mode=0, verb=0)
A rectangular box maker for project boxes, enclosures and housings.
module clamp_zt_1p(size=1, ztie=1, clamp, tunnel, vr, vrm, align, mode=1)
A one piece zip tie clamp to secure wires or provide strain relief.
Definition: clamps.scad:1274
module clamp_cg(size=1, clamp, cone, grip, wth=0, gap=10, mode)
A clamp, bushing, and/or grip for wire, hose, and/or pipe wall penetrations.
Definition: clamps.scad:747
module cone(size=1, vr, center=false)
A cone.
Definition: common_3d.scad:461
module pg_trapezoid(b=1, h, l=1, a=90, o=origin2d, vr, vrm=1, vfn, center=false)
A polygon trapezoid with individual vertex rounding and arc facets.
Definition: polygon.scad:724
module pg_rectangle(size=1, o, vr, vrm=1, vfn, center=false)
A polygon rectangle with vertex rounding.
Definition: polygon.scad:773
module hull_cs(c=true, s)
Conditionally apply the convex hull transformation.
Definition: base_cs.scad:169
module extrude_linear_uss(h, center=false, c=true, ha=0)
Linearly extrude a 2d shape with uniformly-spaced profile scaling.
Definition: extrude.scad:666