173 lines
6.6 KiB
Python
173 lines
6.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from typing import Optional, List, Any, Union
|
|
from dataclasses import dataclass, field
|
|
from wireviz.wv_helper import int2tuple
|
|
from wireviz import wv_colors
|
|
|
|
|
|
@dataclass
|
|
class Connector:
|
|
name: str
|
|
manufacturer: Optional[str] = None
|
|
manufacturer_part_number: Optional[str] = None
|
|
internal_part_number: Optional[str] = None
|
|
style: Optional[str] = None
|
|
category: Optional[str] = None
|
|
type: Optional[str] = None
|
|
subtype: Optional[str] = None
|
|
pincount: Optional[int] = None
|
|
notes: Optional[str] = None
|
|
pinout: List[Any] = field(default_factory=list)
|
|
pinnumbers: List[Any] = field(default_factory=list)
|
|
color: Optional[str] = None
|
|
show_name: bool = None
|
|
show_pincount: bool = None
|
|
hide_disconnected_pins: bool = False
|
|
autogenerate: bool = False
|
|
loops: List[Any] = field(default_factory=list)
|
|
|
|
def __post_init__(self):
|
|
self.ports_left = False
|
|
self.ports_right = False
|
|
self.visible_pins = {}
|
|
|
|
if self.style == 'simple':
|
|
if self.pincount and self.pincount > 1:
|
|
raise Exception('Connectors with style set to simple may only have one pin')
|
|
self.pincount = 1
|
|
|
|
if self.pincount is None:
|
|
if self.pinout:
|
|
self.pincount = len(self.pinout)
|
|
elif self.pinnumbers:
|
|
self.pincount = len(self.pinnumbers)
|
|
else:
|
|
raise Exception('You need to specify at least one, pincount, pinout or pinnumbers')
|
|
|
|
if self.pinout and self.pinnumbers:
|
|
if len(self.pinout) != len(self.pinnumbers):
|
|
raise Exception('Given pinout and pinnumbers size mismatch')
|
|
|
|
# create default lists for pinnumbers (sequential) and pinouts (blank) if not specified
|
|
if not self.pinnumbers:
|
|
self.pinnumbers = list(range(1, self.pincount + 1))
|
|
if not self.pinout:
|
|
self.pinout = [''] * self.pincount
|
|
|
|
if len(self.pinnumbers) != len(set(self.pinnumbers)):
|
|
raise Exception('Pin numbers are not unique')
|
|
|
|
if self.show_name is None:
|
|
self.show_name = not self.autogenerate # hide auto-generated designators by default
|
|
|
|
if self.show_pincount is None:
|
|
self.show_pincount = self.style != 'simple' # hide pincount for simple (1 pin) connectors by default
|
|
|
|
for loop in self.loops:
|
|
# TODO: check that pins to connect actually exist
|
|
# TODO: allow using pin labels in addition to pin numbers, just like when defining regular connections
|
|
# TODO: include properties of wire used to create the loop
|
|
if len(loop) != 2:
|
|
raise Exception('Loops must be between exactly two pins!')
|
|
|
|
def activate_pin(self, pin):
|
|
self.visible_pins[pin] = True
|
|
|
|
|
|
@dataclass
|
|
class Cable:
|
|
name: str
|
|
manufacturer: Optional[Union[str, List[str]]] = None
|
|
manufacturer_part_number: Optional[Union[str, List[str]]] = None
|
|
internal_part_number: Optional[Union[str, List[str]]] = None
|
|
category: Optional[str] = None
|
|
type: Optional[str] = None
|
|
gauge: Optional[float] = None
|
|
gauge_unit: Optional[str] = None
|
|
show_equiv: bool = False
|
|
length: float = 0
|
|
wirecount: Optional[int] = None
|
|
shield: bool = False
|
|
notes: Optional[str] = None
|
|
colors: List[Any] = field(default_factory=list)
|
|
color_code: Optional[str] = None
|
|
show_name: bool = True
|
|
show_wirecount: bool = True
|
|
|
|
def __post_init__(self):
|
|
|
|
if isinstance(self.gauge, str): # gauge and unit specified
|
|
try:
|
|
g, u = self.gauge.split(' ')
|
|
except Exception:
|
|
raise Exception('Gauge must be a number, or number and unit separated by a space')
|
|
self.gauge = g
|
|
|
|
if u.upper() == 'AWG':
|
|
self.gauge_unit = u.upper()
|
|
else:
|
|
self.gauge_unit = u.replace('mm2', 'mm\u00B2')
|
|
|
|
elif self.gauge is not None: # gauge specified, assume mm2
|
|
if self.gauge_unit is None:
|
|
self.gauge_unit = 'mm\u00B2'
|
|
else:
|
|
pass # gauge not specified
|
|
|
|
self.connections = []
|
|
|
|
if self.wirecount: # number of wires explicitly defined
|
|
if self.colors: # use custom color palette (partly or looped if needed)
|
|
pass
|
|
elif self.color_code: # use standard color palette (partly or looped if needed)
|
|
if self.color_code not in wv_colors.COLOR_CODES:
|
|
raise Exception('Unknown color code')
|
|
self.colors = wv_colors.COLOR_CODES[self.color_code]
|
|
else: # no colors defined, add dummy colors
|
|
self.colors = [''] * self.wirecount
|
|
|
|
# make color code loop around if more wires than colors
|
|
if self.wirecount > len(self.colors):
|
|
m = self.wirecount // len(self.colors) + 1
|
|
self.colors = self.colors * int(m)
|
|
# cut off excess after looping
|
|
self.colors = self.colors[:self.wirecount]
|
|
else: # wirecount implicit in length of color list
|
|
if not self.colors:
|
|
raise Exception('Unknown number of wires. Must specify wirecount or colors (implicit length)')
|
|
self.wirecount = len(self.colors)
|
|
|
|
# if lists of part numbers are provided check this is a bundle and that it matches the wirecount.
|
|
for idfield in [self.manufacturer, self.manufacturer_part_number, self.internal_part_number]:
|
|
if isinstance(idfield, list):
|
|
if self.category == "bundle":
|
|
# check the length
|
|
if len(idfield) != self.wirecount:
|
|
raise Exception('lists of part data must match wirecount')
|
|
else:
|
|
raise Exception('lists of part data are only supported for bundles')
|
|
|
|
# for BOM generation
|
|
self.wirecount_and_shield = (self.wirecount, self.shield)
|
|
|
|
def connect(self, from_name, from_pin, via_pin, to_name, to_pin):
|
|
from_pin = int2tuple(from_pin)
|
|
via_pin = int2tuple(via_pin)
|
|
to_pin = int2tuple(to_pin)
|
|
if len(from_pin) != len(to_pin):
|
|
raise Exception('from_pin must have the same number of elements as to_pin')
|
|
for i, _ in enumerate(from_pin):
|
|
# self.connections.append((from_name, from_pin[i], via_pin[i], to_name, to_pin[i]))
|
|
self.connections.append(Connection(from_name, from_pin[i], via_pin[i], to_name, to_pin[i]))
|
|
|
|
|
|
@dataclass
|
|
class Connection:
|
|
from_name: Any
|
|
from_port: Any
|
|
via_port: Any
|
|
to_name: Any
|
|
to_port: Any
|