main
c49a4ab ยท 23 days ago 6 commits
  1package internal
  2
  3import (
  4	"fmt"
  5	"sort"
  6	"strconv"
  7	"strings"
  8)
  9
 10type Circuit struct {
 11	Version               string      `yaml:"cddx2yamlVersion"`
 12	CircuitDiagramVersion string      `yaml:"circuitDiagramVersion"`
 13	Components            []Component `yaml:"components"`
 14	Connections           [][]string  `yaml:"connections"`
 15}
 16
 17type Component struct {
 18	ID    string   `yaml:"id"`
 19	Type  string   `yaml:"type"`
 20	Value string   `yaml:"value,omitempty"`
 21	Label string   `yaml:"label,omitempty"`
 22	Pins  []string `yaml:"pins,omitempty"`
 23}
 24
 25type typeCatalog map[string]string
 26
 27type idCounters map[string]int
 28
 29func documentFromXML(c *xmlCircuit) *Circuit {
 30	types := make(typeCatalog, len(c.Adds))
 31	for _, add := range c.Adds {
 32		types[add.ID] = add.Item
 33	}
 34
 35	counters := make(idCounters)
 36	components := make([]Component, 0, len(c.Components))
 37	for _, xc := range c.Components {
 38		comp := xc.toComponent(types, counters)
 39		for _, cn := range xc.Conns {
 40			comp.addPin(xc.resolvePin(cn.Pin))
 41		}
 42		components = append(components, comp)
 43	}
 44
 45	return &Circuit{
 46		Version:               Version,
 47		CircuitDiagramVersion: c.Version,
 48		Components:            components,
 49		Connections:           collectConnections(c.Components, components),
 50	}
 51}
 52
 53func (types typeCatalog) name(definitionID string) string {
 54	return types[definitionID]
 55}
 56
 57func (counters idCounters) next(prefix string) string {
 58	counters[prefix]++
 59	return fmt.Sprintf("%s-%d", prefix, counters[prefix])
 60}
 61
 62func idPrefix(typeName string) string {
 63	if typeName == "microcontroller" {
 64		return "IC"
 65	}
 66	if typeName == "" {
 67		return "UNK"
 68	}
 69	if len(typeName) < 3 {
 70		return strings.ToUpper(typeName)
 71	}
 72	return strings.ToUpper(typeName[:3])
 73}
 74
 75func (c xmlComponent) toComponent(types typeCatalog, counters idCounters) Component {
 76	typeName := types.name(c.DefinitionID)
 77	label := c.label(types)
 78	if typeName == label {
 79		label = ""
 80	}
 81	return Component{
 82		ID:    counters.next(idPrefix(typeName)),
 83		Type:  typeName,
 84		Label: label,
 85		Value: c.electricalValue(),
 86		Pins:  c.pins(),
 87	}
 88}
 89
 90func (c xmlComponent) label(types typeCatalog) string {
 91	if v, ok := c.prop("header"); ok && v != "" {
 92		return v
 93	}
 94	return types.name(c.DefinitionID)
 95}
 96
 97func (c xmlComponent) electricalValue() string {
 98	value, _ := c.prop("value")
 99	for _, key := range []string{"resistance", "inductance", "frequency", "voltage", "capacitance"} {
100		if v, ok := c.prop(key); ok {
101			value = v
102		}
103	}
104	return value
105}
106
107func (c xmlComponent) pins() []string {
108	pinByIndex := make(map[int]string)
109	for _, p := range c.Props {
110		idx, ok := pinIndex(p.Key)
111		if !ok {
112			continue
113		}
114		pinByIndex[idx] = p.Value
115	}
116
117	indices := make([]int, 0, len(pinByIndex))
118	for idx := range pinByIndex {
119		indices = append(indices, idx)
120	}
121	sort.Ints(indices)
122
123	var pins []string
124	seen := make(map[string]bool)
125	for _, idx := range indices {
126		name := pinByIndex[idx]
127		if seen[name] {
128			fmt.Printf("Warning: duplicate pin name %q for component %q\n", name, c.DefinitionID)
129			continue
130		}
131		seen[name] = true
132		pins = append(pins, name)
133	}
134	return pins
135}
136
137func pinIndex(key string) (int, bool) {
138	for _, prefix := range []string{"pin", "p", "#"} {
139		rest, ok := strings.CutPrefix(key, prefix)
140		if !ok {
141			continue
142		}
143		idx, err := strconv.Atoi(rest)
144		if err != nil {
145			continue
146		}
147		return idx, true
148	}
149	return 0, false
150}