// Breadboard component for the LogicSimulator // Copyright (C) 2022 Sascha Nitsch // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . interface BreadboardParam extends BaseComponentParam { nopower?: boolean; onlypower?: boolean; } // eslint-disable-next-line @typescript-eslint/no-unused-vars class Breadboard extends BaseComponent { private l: string; private unitX: number; private unitY: number; private active: Map; private nopower: boolean; private onlypower: boolean; private descrlabel: string; constructor(simulator: Simulator, id: string, param: BreadboardParam) { simulator.loadCSS('breadboard'); super(simulator, id, param); this.nopower = param.nopower || false; this.onlypower = param.onlypower || false; this.descrlabel = typeof param.label === 'string' ? param.label : '' || ''; this.active = new Map(); this.l = 'ABCDEFGHIJ'; let x: number; let y: number; this.unitX = 2 * 2.54; this.unitY = 2 * 2.54; if (!param || !param.onlypower) { for (x = 0; x < 60; ++x) { for (y = 0; y < 10; ++y) { this.pins.set( this.l[y] + x, new TriState(this, (x + 1.5) * this.unitX, this.unitY * (16 - y - (y > 4 ? 2 : 0)), undefined, { id: this.l[y] + x, }) ); } } } y = 12; if (!param || !param.nopower) { for (x = 0; x < 50; ++x) { this.pins.set( 'pa' + x, new TriState(this, this.unitX * (x + 2.5 + Math.floor(x / 5)), 2.5 * this.unitY, undefined, { id: 'pa' + x }) ); this.pins.set( 'ma' + x, new TriState(this, this.unitX * (x + 2.5 + Math.floor(x / 5)), 1.5 * this.unitY, undefined, { id: 'ma' + x }) ); if (!param || !param.onlypower) { this.pins.set( 'pb' + x, new TriState(this, this.unitX * (x + 2.5 + Math.floor(x / 5)), 19.5 * this.unitY, undefined, { id: 'pb' + x, }) ); this.pins.set( 'mb' + x, new TriState(this, this.unitX * (x + 2.5 + Math.floor(x / 5)), 18.5 * this.unitY, undefined, { id: 'mb' + x, }) ); } } } //this.wires = {}; this.zIndex = 0; } setup(parent: SVGElement) { super.doSetup('breadboard', parent); if (this.element === null) return; const g = this.element.childNodes[0]; const tpl = this.element.querySelectorAll('.pintemplate')[0]; this.pins.forEach((k) => { // const k = this.pins.get(key); if (!(k instanceof TriState)) { return; } //console.log(this.state[key].x(),this.state[key].y()); const node = tpl.cloneNode(true); node.setAttribute('class', 'pin'); node.setAttribute('transform', 'translate(' + k.getOffsetX() + ',' + k.getOffsetY() + ')'); g.appendChild(node); }); if (this.nopower) { const power = this.element.querySelectorAll('.power'); for (let i = 0; i < power.length; ++i) { const p = power[i].parentNode; if (p !== null) { p.removeChild(power[i]); } } } if (this.onlypower) { let rem = this.element.querySelectorAll('.bottom'); for (let i = 0; i < rem.length; ++i) { const r = rem[i].parentNode; if (r !== null) { r.removeChild(rem[i]); } } rem = this.element.querySelectorAll('.center'); for (let i = 0; i < rem.length; ++i) { const r = rem[i].parentNode; if (r !== null) { r.removeChild(rem[i]); } } if (!this.descrlabel) { rem = this.element.querySelectorAll('.label'); for (let i = 0; i < rem.length; ++i) { const r = rem[i].parentNode; if (r !== null) { r.removeChild(rem[i]); } } } } } connected(pin: TriState) { this.active.set(pin.getParam().id || '', pin); } finalize() { let row; let pins; let col; let i; const bus = ['pa', 'ma', 'pb', 'mb']; for (row = 0; row < 4; ++row) { pins = []; for (col = 0; col < 50; ++col) { const a = this.active.get(bus[row] + col); if (a !== undefined) { pins.push(a); } } if (pins.length > 1) { let sourceId = 0; // find names wire for (i = 0; i < pins.length; ++i) { const pin = pins[i].connectedWire; if (pin && pin.autoid === false) { sourceId = i; break; } } const source = pins[sourceId].connectedWire; if (source !== null) { for (i = 0; i < pins.length; ++i) { if (i === sourceId) continue; source.join(pins[i].connectedWire); pins[i].connectedWire = null; const id = pins[i].getParam().id; if (id) { this.active.delete(id); } } const id = pins[sourceId].getParam().id; if (id) { this.active.delete(id); } // remove ourself source.remove(this); } } } for (col = 0; col < 60; ++col) { for (let start = 0; start < 10; start += 5) { pins = []; for (row = start; row < start + 5; ++row) { const a = this.active.get(this.l[row] + col); if (a !== undefined) { pins.push(a); } } if (pins.length > 1) { for (i = 1; i < pins.length; ++i) { if (pins[0].connectedWire) { pins[0].connectedWire.join(pins[i].connectedWire); pins[i].connectedWire = null; const id = pins[i].getParam().id; if (id) { this.active.delete(id); } } } const id = pins[0].getParam().id; if (id) { this.active.delete(id); } // remove ourself if (pins[0].connectedWire) { pins[0].connectedWire.remove(this); } } } } } getPos(column: string): number[] { let t; if (column[0] >= 'A' && column[0] <= 'J') { // exact pin t = this.pins.get(column); } else { t = this.pins.get('E' + column); } if (t === undefined) return [0, 0]; const x = this.x + t.getOffsetX() * this.scaleX; const y = this.y + t.getOffsetY() * this.scaleY; return [x, y]; } io(): void { this.active.forEach((value) => { value.getAndReset(); }); } }