diff --git a/examples/demo02.yml b/examples/demo02.yml index 5002e7d2..d83167ff 100644 --- a/examples/demo02.yml +++ b/examples/demo02.yml @@ -22,9 +22,8 @@ connectors: X4: <<: *molex_f pinlabels: [GND, +12V, MISO, MOSI, SCK] - ferrule_crimp: + F: style: simple - autogenerate: true type: Crimp ferrule subtype: 0.25 mm² color: YE @@ -64,6 +63,6 @@ connections: - W3: [1-4] - X4: [1,3-5] - - - ferrule_crimp + - F. - W4: [1,2] - X4: [1,2] diff --git a/examples/ex04.yml b/examples/ex04.yml index 74148ecf..c3c7234e 100644 --- a/examples/ex04.yml +++ b/examples/ex04.yml @@ -8,13 +8,12 @@ cables: category: bundle connectors: - ferrule_crimp: + F: style: simple - autogenerate: true type: Crimp ferrule connections: - - - ferrule_crimp + - F. - W1: [1-6] - - ferrule_crimp + - F. diff --git a/src/wireviz/DataClasses.py b/src/wireviz/DataClasses.py index 44c063cf..700e2170 100644 --- a/src/wireviz/DataClasses.py +++ b/src/wireviz/DataClasses.py @@ -141,7 +141,6 @@ class Connector: show_name: Optional[bool] = None show_pincount: Optional[bool] = None hide_disconnected_pins: bool = False - autogenerate: bool = False loops: List[List[Pin]] = field(default_factory=list) ignore_in_bom: bool = False additional_components: List[AdditionalComponent] = field(default_factory=list) @@ -173,7 +172,8 @@ def __post_init__(self) -> None: raise Exception('Pins are not unique') if self.show_name is None: - self.show_name = not self.autogenerate # hide auto-generated designators by default + # hide designators for simple and for auto-generated connectors by default + self.show_name = (self.style != 'simple' and self.name[0:2] != '__') if self.show_pincount is None: self.show_pincount = self.style != 'simple' # hide pincount for simple (1 pin) connectors by default @@ -226,7 +226,7 @@ class Cable: colors: List[Colors] = field(default_factory=list) wirelabels: List[Wire] = field(default_factory=list) color_code: Optional[ColorScheme] = None - show_name: bool = True + show_name: Optional[bool] = None show_wirecount: bool = True show_wirenumbers: Optional[bool] = None ignore_in_bom: bool = False @@ -309,9 +309,11 @@ def __post_init__(self) -> None: else: raise Exception('lists of part data are only supported for bundles') - # by default, show wire numbers for cables, hide for bundles - if self.show_wirenumbers is None: - self.show_wirenumbers = self.category != 'bundle' + if self.show_name is None: + self.show_name = self.name[0:2] != '__' # hide designators for auto-generated cables by default + + if not self.show_wirenumbers: + self.show_wirenumbers = self.category != 'bundle' # by default, show wire numbers for cables, hide for bundles for i, item in enumerate(self.additional_components): if isinstance(item, dict): @@ -350,3 +352,17 @@ class Connection: via_port: Wire to_name: Optional[Designator] to_port: Optional[PinIndex] + +@dataclass +class MatePin: + from_name: Designator + from_port: PinIndex + to_name: Designator + to_port: PinIndex + shape: str + +@dataclass +class MateComponent: + from_name: Designator + to_name: Designator + shape: str diff --git a/src/wireviz/Harness.py b/src/wireviz/Harness.py index edd8046c..433023db 100644 --- a/src/wireviz/Harness.py +++ b/src/wireviz/Harness.py @@ -10,7 +10,7 @@ import re from wireviz import wv_colors, __version__, APP_NAME, APP_URL -from wireviz.DataClasses import Metadata, Options, Tweak, Connector, Cable +from wireviz.DataClasses import Cable, Connector, MatePin, MateComponent, Metadata, Options, Tweak from wireviz.wv_colors import get_color_hex, translate_color from wireviz.wv_gv_html import nested_html_table, html_colorbar, html_image, \ html_caption, remove_links, html_line_breaks @@ -19,8 +19,7 @@ HEADER_PN, HEADER_MPN, HEADER_SPN from wireviz.wv_html import generate_html_output from wireviz.wv_helper import awg_equiv, mm2_equiv, tuplelist2tsv, flatten2d, \ - open_file_read, open_file_write - + open_file_read, open_file_write, is_arrow @dataclass class Harness: @@ -31,6 +30,7 @@ class Harness: def __post_init__(self): self.connectors = {} self.cables = {} + self.mates = [] self._bom = [] # Internal Cache for generated bom self.additional_bom_items = [] @@ -40,6 +40,12 @@ def add_connector(self, name: str, *args, **kwargs) -> None: def add_cable(self, name: str, *args, **kwargs) -> None: self.cables[name] = Cable(name, *args, **kwargs) + def add_mate_pin(self, *args, **kwargs) -> None: + self.mates.append(MatePin(*args, **kwargs)) + + def add_mate_component(self, *args, **kwargs) -> None: + self.mates.append(MateComponent(*args, **kwargs)) + def add_bom_item(self, item: dict) -> None: self.additional_bom_items.append(item) @@ -66,7 +72,12 @@ def connect(self, from_name: str, from_pin: (int, str), via_name: str, via_wire: raise Exception(f'{name}:{pin} not found.') # check via cable - if via_name in self.cables: + if is_arrow(via_name): + if '-' in via_name: + self.mates[(from_name, from_pin, to_name, to_pin)] = via_name + elif '=' in via_name: + self.mates[(from_name, to_name)] = via_name + elif via_name in self.cables: cable = self.cables[via_name] # check if provided name is ambiguous if via_wire in cable.colors and via_wire in cable.wirelabels: @@ -114,8 +125,17 @@ def create_graph(self) -> Graph: for connection_color in cable.connections: if connection_color.from_port is not None: # connect to left self.connectors[connection_color.from_name].ports_right = True + self.connectors[connection_color.from_name].activate_pin(connection_color.from_port) if connection_color.to_port is not None: # connect to right self.connectors[connection_color.to_name].ports_left = True + self.connectors[connection_color.to_name].activate_pin(connection_color.to_port) + + for mate in self.mates: + if isinstance(mate, MatePin): + self.connectors[mate.from_name].ports_right = True + self.connectors[mate.from_name].activate_pin(mate.from_port) + self.connectors[mate.to_name].ports_left = True + self.connectors[mate.to_name].activate_pin(mate.to_port) for connector in self.connectors.values(): @@ -407,6 +427,30 @@ def typecheck(name: str, value: Any, expect: type) -> None: typecheck('tweak.append', self.tweak.append, str) dot.body.append(self.tweak.append) + for mate in self.mates: + if mate.shape[0] == '<' and mate.shape[-1] == '>': + dir = 'both' + elif mate.shape[0] == '<': + dir = 'back' + elif mate.shape[-1] == '>': + dir = 'forward' + else: + dir = 'none' + + if isinstance(mate, MatePin): + color = '#000000' + elif isinstance(mate, MateComponent): + color = '#000000:#000000' + else: + raise Exception(f'{mate} is an unknown mate') + + dot.attr('edge', color=color, style='dashed', dir=dir) + from_port = f':p{mate.from_port}r' if isinstance(mate, MatePin) and self.connectors[mate.from_name].style != 'simple' else '' + code_from = f'{mate.from_name}{from_port}:e' + to_port = f':p{mate.to_port}l' if isinstance(mate, MatePin) and self.connectors[mate.to_name].style != 'simple' else '' + code_to = f'{mate.to_name}{to_port}:w' + dot.edge(code_from, code_to) + return dot @property diff --git a/src/wireviz/wireviz.py b/src/wireviz/wireviz.py index 95674945..e41a6356 100755 --- a/src/wireviz/wireviz.py +++ b/src/wireviz/wireviz.py @@ -15,7 +15,7 @@ from wireviz import __version__ from wireviz.DataClasses import Metadata, Options, Tweak from wireviz.Harness import Harness -from wireviz.wv_helper import expand, open_file_read +from wireviz.wv_helper import expand, get_single_key_and_value, is_arrow, open_file_read def parse(yaml_input: str, file_out: (str, Path) = None, return_types: (None, str, Tuple[str]) = None) -> Any: @@ -35,20 +35,33 @@ def parse(yaml_input: str, file_out: (str, Path) = None, return_types: (None, st yaml_data = yaml.safe_load(yaml_input) + + # define variables ========================================================= + # containers for parsed component data and connection sets + template_connectors = {} + template_cables = {} + connection_sets = [] + # actual harness harness = Harness( metadata = Metadata(**yaml_data.get('metadata', {})), options = Options(**yaml_data.get('options', {})), tweak = Tweak(**yaml_data.get('tweak', {})), ) + # others + designators_and_templates = {} # store mapping of components to their respective template + autogenerated_designators = {} # keep track of auto-generated designators to avoid duplicates + if 'title' not in harness.metadata: harness.metadata['title'] = Path(file_out).stem # add items + # parse YAML input file ==================================================== + sections = ['connectors', 'cables', 'connections'] types = [dict, dict, list] for sec, ty in zip(sections, types): - if sec in yaml_data and type(yaml_data[sec]) == ty: - if len(yaml_data[sec]) > 0: + if sec in yaml_data and type(yaml_data[sec]) == ty: # section exists + if len(yaml_data[sec]) > 0: # section has contents if ty == dict: for key, attribs in yaml_data[sec].items(): # The Image dataclass might need to open an image file with a relative path. @@ -56,132 +69,191 @@ def parse(yaml_input: str, file_out: (str, Path) = None, return_types: (None, st if isinstance(image, dict): image['gv_dir'] = Path(file_out if file_out else '').parent # Inject context + # store component templates only; do not generate instances yet if sec == 'connectors': - if not attribs.get('autogenerate', False): - harness.add_connector(name=key, **attribs) + template_connectors[key] = attribs elif sec == 'cables': - harness.add_cable(name=key, **attribs) - else: - pass # section exists but is empty + template_cables[key] = attribs + else: # section exists but is empty + pass else: # section does not exist, create empty section if ty == dict: yaml_data[sec] = {} elif ty == list: yaml_data[sec] = [] - # add connections - - def check_designators(what, where): # helper function - for i, x in enumerate(what): - if x not in yaml_data[where[i]]: - return False - return True - - autogenerated_ids = {} - for connection in yaml_data['connections']: - # find first component (potentially nested inside list or dict) - first_item = connection[0] - if isinstance(first_item, list): - first_item = first_item[0] - elif isinstance(first_item, dict): - first_item = list(first_item.keys())[0] - elif isinstance(first_item, str): - pass - - # check which section the first item belongs to - alternating_sections = ['connectors','cables'] - for index, section in enumerate(alternating_sections): - if first_item in yaml_data[section]: - expected_index = index - break + connection_sets = yaml_data['connections'] + + # go through connection sets, generate and connect components ============== + + template_separator_char = '.' # TODO: make user-configurable (in case user wants to use `.` as part of their template/component names) + + def resolve_designator(inp, separator): + if separator in inp: # generate a new instance of an item + if inp.count(separator) > 1: + raise Exception(f'{inp} - Found more than one separator ({separator})') + template, designator = inp.split(separator) + if designator == '': + autogenerated_designators[template] = autogenerated_designators.get(template, 0) + 1 + designator = f'__{template}_{autogenerated_designators[template]}' + # check if redefining existing component to different template + if designator in designators_and_templates: + if designators_and_templates[designator] != template: + raise Exception(f'Trying to redefine {designator} from {designators_and_templates[designator]} to {template}') + else: + designators_and_templates[designator] = template else: - raise Exception('First item not found anywhere.') - expected_index = 1 - expected_index # flip once since it is flipped back at the *beginning* of every loop - - # check that all iterable items (lists and dicts) are the same length - # and that they are alternating between connectors and cables/bundles, starting with either - itemcount = None - for item in connection: - expected_index = 1 - expected_index # make sure items alternate between connectors and cables - expected_section = alternating_sections[expected_index] - if isinstance(item, list): - itemcount_new = len(item) - for subitem in item: - if not subitem in yaml_data[expected_section]: - raise Exception(f'{subitem} is not in {expected_section}') - elif isinstance(item, dict): - if len(item.keys()) != 1: - raise Exception('Dicts may contain only one key here!') - itemcount_new = len(expand(list(item.values())[0])) - subitem = list(item.keys())[0] - if not subitem in yaml_data[expected_section]: - raise Exception(f'{subitem} is not in {expected_section}') - elif isinstance(item, str): - if not item in yaml_data[expected_section]: - raise Exception(f'{item} is not in {expected_section}') - continue - if itemcount is not None and itemcount_new != itemcount: - raise Exception('All lists and dict lists must be the same length!') - itemcount = itemcount_new - if itemcount is None: - raise Exception('No item revealed the number of connections to make!') - - # populate connection list - connection_list = [] - for i, item in enumerate(connection): - if isinstance(item, str): # one single-pin component was specified - sublist = [] - for i in range(1, itemcount + 1): - if yaml_data['connectors'][item].get('autogenerate'): - autogenerated_ids[item] = autogenerated_ids.get(item, 0) + 1 - new_id = f'_{item}_{autogenerated_ids[item]}' - harness.add_connector(new_id, **yaml_data['connectors'][item]) - sublist.append([new_id, 1]) - else: - sublist.append([item, 1]) - connection_list.append(sublist) - elif isinstance(item, list): # a list of single-pin components were specified - sublist = [] - for subitem in item: - if yaml_data['connectors'][subitem].get('autogenerate'): - autogenerated_ids[subitem] = autogenerated_ids.get(subitem, 0) + 1 - new_id = f'_{subitem}_{autogenerated_ids[subitem]}' - harness.add_connector(new_id, **yaml_data['connectors'][subitem]) - sublist.append([new_id, 1]) - else: - sublist.append([subitem, 1]) - connection_list.append(sublist) - elif isinstance(item, dict): # a component with multiple pins was specified - sublist = [] - id = list(item.keys())[0] - pins = expand(list(item.values())[0]) - for pin in pins: - sublist.append([id, pin]) - connection_list.append(sublist) + template, designator = (inp, inp) + if designator in designators_and_templates: + pass # referencing an exiting connector, no need to add again else: - raise Exception('Unexpected item in connection list') - - # actually connect components using connection list - for i, item in enumerate(connection_list): - id = item[0][0] # TODO: make more elegant/robust/pythonic - if id in harness.cables: - for j, con in enumerate(item): - if i == 0: # list started with a cable, no connector to join on left side - from_name = None - from_pin = None + designators_and_templates[designator] = template + return (template, designator) + + # utilities to check for alternating connectors and cables/arrows ========== + + alternating_types = ['connector','cable/arrow'] + expected_type = None + + def check_type(designator, template, actual_type): + nonlocal expected_type + if not expected_type: # each connection set may start with either section + expected_type = actual_type + + if actual_type != expected_type: # did not alternate + raise Exception(f'Expected {expected_type}, but "{designator}" ("{template}") is {actual_type}') + + def alternate_type(): # flip between connector and cable/arrow + nonlocal expected_type + expected_type = alternating_types[1 - alternating_types.index(expected_type)] + + for connection_set in connection_sets: + + # figure out number of parallel connections within this set + connectioncount = [] + for entry in connection_set: + if isinstance(entry, list): + connectioncount.append(len(entry)) + elif isinstance(entry, dict): + connectioncount.append(len(expand(list(entry.values())[0]))) # - X1: [1-4,6] yields 5 + else: + pass # strings do not reveal connectioncount + if not any(connectioncount): + raise Exception('No item in connection set revealed number of connections') + # TODO: The following should be a valid connection set, + # even though no item reveals the connection count; + # the count is not needed because only a component-level mate happens. + # - + # - CONNECTOR + # - ==> + # - CONNECTOR + + # check that all entries are the same length + if len(set(connectioncount)) > 1: + raise Exception('All items in connection set must reference the same number of connections') + # all entries are the same length, connection count is set + connectioncount = connectioncount[0] + + # expand string entries to list entries of correct length + for index, entry in enumerate(connection_set): + if isinstance(entry, str): + connection_set[index] = [entry] * connectioncount + + # resolve all designators + for index, entry in enumerate(connection_set): + if isinstance(entry, list): + for subindex, item in enumerate(entry): + template, designator = resolve_designator(item, template_separator_char) + connection_set[index][subindex] = designator + elif isinstance(entry, dict): + key = list(entry.keys())[0] + template, designator = resolve_designator(key, template_separator_char) + value = entry[key] + connection_set[index] = {designator: value} + else: + pass # string entries have been expanded in previous step + + # expand all pin lists + for index, entry in enumerate(connection_set): + if isinstance(entry, list): + connection_set[index] = [{designator: 1} for designator in entry] + elif isinstance(entry, dict): + designator = list(entry.keys())[0] + pinlist = expand(entry[designator]) + connection_set[index] = [{designator: pin} for pin in pinlist] + else: + pass # string entries have been expanded in previous step + + # Populate wiring harness ============================================== + + expected_type = None # reset check for alternating types + # at the beginning of every connection set + # since each set may begin with either type + + # generate components + for entry in connection_set: + for item in entry: + designator = list(item.keys())[0] + template = designators_and_templates[designator] + + if designator in harness.connectors: # existing connector instance + check_type(designator, template, 'connector') + elif template in template_connectors.keys(): # generate new connector instance from template + check_type(designator, template, 'connector') + harness.add_connector(name = designator, **template_connectors[template]) + + elif designator in harness.cables: # existing cable instance + check_type(designator, template, 'cable/arrow') + elif template in template_cables.keys(): # generate new cable instance from template + check_type(designator, template, 'cable/arrow') + harness.add_cable(name = designator, **template_cables[template]) + + elif is_arrow(designator): + check_type(designator, template, 'cable/arrow') + # arrows do not need to be generated here + else: + raise Exception(f'{template} is an unknown template/designator/arrow.') + + alternate_type() # entries in connection set must alternate between connectors and cables/arrows + + # transpose connection set list + # before: one item per component, one subitem per connection in set + # after: one item per connection in set, one subitem per component + connection_set = list(map(list, zip(*connection_set))) + + # connect components + for index_entry, entry in enumerate(connection_set): + for index_item, item in enumerate(entry): + designator = list(item.keys())[0] + + if designator in harness.cables: + if index_item == 0: # list started with a cable, no connector to join on left side + from_name, from_pin = (None, None) else: - from_name = connection_list[i-1][j][0] - from_pin = connection_list[i-1][j][1] - via_name = item[j][0] - via_pin = item[j][1] - if i == len(connection_list) - 1: # list ends with a cable, no connector to join on right side - to_name = None - to_pin = None + from_name, from_pin = get_single_key_and_value(connection_set[index_entry][index_item-1]) + via_name, via_pin = (designator, item[designator]) + if index_item == len(entry) - 1: # list ends with a cable, no connector to join on right side + to_name, to_pin = (None, None) else: - to_name = connection_list[i+1][j][0] - to_pin = connection_list[i+1][j][1] + to_name, to_pin = get_single_key_and_value(connection_set[index_entry][index_item+1]) harness.connect(from_name, from_pin, via_name, via_pin, to_name, to_pin) + elif is_arrow(designator): + if index_item == 0: # list starts with an arrow + raise Exception('An arrow cannot be at the start of a connection set') + elif index_item == len(entry) - 1: # list ends with an arrow + raise Exception('An arrow cannot be at the end of a connection set') + + from_name, from_pin = get_single_key_and_value(connection_set[index_entry][index_item-1]) + via_name, via_pin = (designator, None) + to_name, to_pin = get_single_key_and_value(connection_set[index_entry][index_item+1]) + if '-' in designator: # mate pin by pin + harness.add_mate_pin(from_name, from_pin, to_name, to_pin, designator) + elif '=' in designator and index_entry == 0: # mate two connectors as a whole + harness.add_mate_component(from_name, to_name, designator) + + # harness population completed ============================================= + if "additional_bom_items" in yaml_data: for line in yaml_data["additional_bom_items"]: harness.add_bom_item(line) diff --git a/src/wireviz/wv_helper.py b/src/wireviz/wv_helper.py index ffc4bd84..83fe3e98 100644 --- a/src/wireviz/wv_helper.py +++ b/src/wireviz/wv_helper.py @@ -66,6 +66,12 @@ def expand(yaml_data): return output +def get_single_key_and_value(d: dict): + k = list(d.keys())[0] + v = d[k] + return (k, v) + + def int2tuple(inp): if isinstance(inp, tuple): output = inp @@ -106,6 +112,18 @@ def open_file_write(filename): def open_file_append(filename): return open(filename, 'a', encoding='UTF-8') +def is_arrow(inp): + """ + Matches strings of one or multiple `-` or `=` (but not mixed) + optionally starting with `<` and/or ending with `>`. + + Examples: + <-, --, ->, <-> + <==, ==, ==>, <=> + """ + # regex by @shiraneyo + return bool(re.match(r"^\s*(?P-+|=+)(?P>?)\s*$", inp)) + def aspect_ratio(image_src): try: from PIL import Image diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 00000000..e28d9257 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,5 @@ +*.bom.tsv +*.gv +*.html +*.png +*.svg diff --git a/test/test1.yml b/test/test1.yml new file mode 100644 index 00000000..0d88a64b --- /dev/null +++ b/test/test1.yml @@ -0,0 +1,25 @@ +# based on @stmaxed's example in #134 + +connectors: + X1: &X + type: Screw connector + subtype: male + color: GN + pincount: 4 + pinlabels: [A, B, C, D] + F: + style: simple + type: Ferrule + color: GY + +cables: + W: + color: BK + colors: [BK, WH, BU, BN] + +connections: + - # ferrules + connector X1 + - W.W1: [1-4] + - F. + - --> + - X1: [1-4] diff --git a/test/test2.yml b/test/test2.yml new file mode 100644 index 00000000..a8a4c85c --- /dev/null +++ b/test/test2.yml @@ -0,0 +1,25 @@ +# based on @MSBGit's example in #134 + +connectors: + X1: &dupont + type: Dupont 2.54mm + subtype: male + pincount: 5 + color: BK + X2: + <<: *dupont + subtype: female + +cables: + W: + category: bundle + colors: [RD, BK, BU, GN] + length: 0.2 + +connections: + - + - W.W1: [1-4] + - X1: [1-4] + - ==> + - X2: [1-4] + - W.W2: [1-4] diff --git a/test/test3.yml b/test/test3.yml new file mode 100644 index 00000000..a01bedf2 --- /dev/null +++ b/test/test3.yml @@ -0,0 +1,33 @@ +# expanding upon @stmaxed's example in #134 + +connectors: + X1: &X + type: Screw connector + subtype: male + color: GN + pincount: 4 + pinlabels: [A, B, C, D] + X2: + <<: *X + subtype: female + F: + style: simple + type: Ferrule + color: GY + +cables: + W: + color: BK + colors: [BK, WH, BU, BN] + +connections: + - # ferrules + connector X1 + - W.W1: [1-4] + - F. + - --> + - X1: [1-4] + - ==> + - X2: [1-4] + - <-- + - F. + - W.W2: [1-4] diff --git a/test/test4.yml b/test/test4.yml new file mode 100644 index 00000000..85b90814 --- /dev/null +++ b/test/test4.yml @@ -0,0 +1,26 @@ +# based on @formatc1702's example in #184 + +connectors: + X: + pincount: 4 + pinlabels: [A, B, C, D] + F: + style: simple + type: ferrule + +cables: + C: + wirecount: 4 + color_code: DIN + +connections: + - + - X.X1: [1-4] + - C.C1: [1-4] + - [F.F1, F.F2, F.F3, F.F4] # generate new instances of F and assign designators + - C.C2: [1-4] + - X.X2: [1-4] + - + - [F1, F2, F3, F4] # use previously assigned designators + - C.C3: [1-4] + - X.X3: [1-4] diff --git a/test/test5.yml b/test/test5.yml new file mode 100644 index 00000000..0e670327 --- /dev/null +++ b/test/test5.yml @@ -0,0 +1,64 @@ +connectors: + XS: + type: Screw terminal connector + subtype: male + color: GN + pincount: 3 + XM: + type: Molex KK 254 + subtype: female + pincount: 3 + F: + style: simple + type: Ferrule + subtype: 0.25 mm2 + color: LB + LED_RD: &LED + type: LED + subtype: 5mm + show_pincount: false + color: RD + pins: [+, -] + pinlabels: [Anode, Cathode] + LED_GN: + <<: *LED + color: GN + LED_YE: + <<: *LED + color: YE + +cables: + C: + category: bundle + # show_name: false + colors: [RD, BK] + gauge: 0.25 mm2 + W: + category: bundle + # show_name: false + colors: [BN] + gauge: 0.25 mm2 + +connections: + - + - [F.F1, F.F2] + - C.W1: [1,2] + - LED_RD: [+,-] + - + - F.F3 + - W.W2: [1] + - LED_GN: [+] + - + - LED_GN: [-] + - W.W3: [1] + - + - XS.X1: [1-3] + - <-- + - [F1, F2, F3] + - + - LED_YE: [+,-] + - C.W4: [1,2] + - XM.X2: [1,2] + - + - W3: [1] + - X2: [3] diff --git a/test/test9.yml b/test/test9.yml new file mode 100644 index 00000000..bad0256f --- /dev/null +++ b/test/test9.yml @@ -0,0 +1,55 @@ +connectors: + JSTMALE: &JST_SM # use generic names here, assign designators at generation time + type: JST SM + subtype: male + pincount: 4 + pinlabels: [A, B, C, D] + JSTFEMALE: + <<: *JST_SM # easily create JSTMALE's matching connector + subtype: female + X4: # this connector is only used once, use fixed designator here already + type: Screw terminal connector + pincount: 4 + color: GN + pinlabels: [W, X, Y, Z] + S: + style: simple + type: Splice + color: CU + F: + style: simple + type: Ferrule + color: GY + + +cables: + CABLE: + wirecount: 4 + color_code: DIN + length: 0.1 + WIRE: + wirecount: 1 + colors: [BK] + length: 0.1 + +connections: + - + - JSTMALE.X1: [4-1] # use `.` syntax to generate a new instance of JSTMALE, named X1 + - CABLE.W1: [1-4] # same syntax for cables + - [S., S., S.S1, S.] # splice W1 and W2 together; only wire #3 needs a user-defined designator + - CABLE.W2: [1-4] + - S. # test shorthand, auto-get required number of ferrules from context + - CABLE.W21: [1-4] + - JSTFEMALE.X2: [1-4] + - <=> # mate X2 and X3 + - JSTMALE.X3: [1-4] + - CABLE.W3: [1-4] + - [F., F., F., F.] + - --> # insert ferrules into screw terminal connector + - X4: [2,1,4,3] # X4 does not require auto-generation, thus no `.` syntax here + - + - S1: [1] # reuse previously generated splice + # TODO: Make it work with `- F1` only, making pin 1 is implied + - WIRE.: [1] # We don't care about a simple wire's designator, auto-generate please! + # TODO: Make it work with `- W.W4: 1`, dropping the need for `[]` + - X2: [4] diff --git a/tutorial/tutorial05.yml b/tutorial/tutorial05.yml index e894a452..d4739c55 100644 --- a/tutorial/tutorial05.yml +++ b/tutorial/tutorial05.yml @@ -5,7 +5,6 @@ connectors: subtype: female F1: style: simple - autogenerate: true type: Crimp ferrule subtype: 0.5 mm² color: OG # optional color @@ -19,6 +18,6 @@ cables: connections: - - - F1 # a new ferrule is auto-generated for each of the four wires + - F1. # a new ferrule is auto-generated for each of the four wires - W1: [1-4] - X1: [1-4] diff --git a/tutorial/tutorial06.yml b/tutorial/tutorial06.yml index 51431573..0cd79b69 100644 --- a/tutorial/tutorial06.yml +++ b/tutorial/tutorial06.yml @@ -5,13 +5,11 @@ connectors: subtype: female F_10: # this is a unique ferrule style: simple - show_name: false # non-autogenerated connectors show their name by default; override type: Crimp ferrule subtype: 1.0 mm² color: YE # optional color F_05: # this is a ferrule that will be auto-generated on demand style: simple - autogenerate: true type: Crimp ferrule subtype: 0.5 mm² color: OG @@ -25,6 +23,6 @@ cables: connections: - - - [F_05, F_10, F_10, F_05] + - [F_05., F_10.F1, F_10.F1, F_05.] - W1: [1-4] - X1: [1-4]