mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-23 04:11:54 -04:00
adds a telnet server; see #702
This commit is contained in:
parent
f52236ce29
commit
4ed012c174
@ -923,5 +923,17 @@ public final class Keys {
|
||||
public static final Key.KeyEnum<ScopeTrigger.Trigger> TRIGGER =
|
||||
new Key.KeyEnum<>("trigger", ScopeTrigger.Trigger.both, ScopeTrigger.Trigger.values());
|
||||
|
||||
/**
|
||||
* Selects the telnet port
|
||||
*/
|
||||
public static final Key.KeyInteger PORT =
|
||||
new Key.KeyInteger("port", 23)
|
||||
.setMin(1)
|
||||
.setMax((1 << 16) - 1);
|
||||
/**
|
||||
* Telnet escape
|
||||
*/
|
||||
public static final Key<Boolean> TELNET_ESCAPE =
|
||||
new Key<>("telnetEscape", true).allowGroupEdit();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.core.io.telnet;
|
||||
|
||||
/**
|
||||
* A simple thread save byte queue.
|
||||
*/
|
||||
public class ByteBuffer {
|
||||
private final byte[] data;
|
||||
private final int size;
|
||||
private int inBuffer;
|
||||
private int newest;
|
||||
private int oldest;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param size the size of the buffer
|
||||
*/
|
||||
public ByteBuffer(int size) {
|
||||
data = new byte[size];
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a byte at the top of the buffer
|
||||
*
|
||||
* @param value the byte value
|
||||
*/
|
||||
synchronized public void put(byte value) {
|
||||
if (inBuffer < size) {
|
||||
data[newest] = value;
|
||||
newest = inc(newest);
|
||||
inBuffer++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the byte at the tail of the buffer
|
||||
*/
|
||||
synchronized public byte peek() {
|
||||
if (inBuffer > 0) {
|
||||
return data[oldest];
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes a byte from the tail of the buffer
|
||||
*/
|
||||
synchronized public void delete() {
|
||||
oldest = inc(oldest);
|
||||
inBuffer--;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there is data available
|
||||
*/
|
||||
synchronized public boolean hasData() {
|
||||
return inBuffer > 0;
|
||||
}
|
||||
|
||||
private int inc(int n) {
|
||||
n++;
|
||||
if (n >= size)
|
||||
n = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
}
|
158
src/main/java/de/neemann/digital/core/io/telnet/Server.java
Normal file
158
src/main/java/de/neemann/digital/core/io/telnet/Server.java
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.core.io.telnet;
|
||||
|
||||
import de.neemann.digital.core.Observer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* The telnet server
|
||||
*/
|
||||
public class Server {
|
||||
private final ServerSocket serverSocket;
|
||||
private final ByteBuffer buffer;
|
||||
private boolean telnetEscape;
|
||||
private ClientThread client;
|
||||
private Observer notify;
|
||||
|
||||
Server(int port) throws IOException {
|
||||
buffer = new ByteBuffer(1024);
|
||||
serverSocket = new ServerSocket(port);
|
||||
ServerThread listener = new ServerThread();
|
||||
listener.start();
|
||||
}
|
||||
|
||||
void send(int value) {
|
||||
if (client != null)
|
||||
client.send(value);
|
||||
}
|
||||
|
||||
int getData() {
|
||||
return buffer.peek();
|
||||
}
|
||||
|
||||
void delete() {
|
||||
buffer.delete();
|
||||
}
|
||||
|
||||
void setNotify(Observer notify) {
|
||||
this.notify = notify;
|
||||
}
|
||||
|
||||
boolean hasData() {
|
||||
return buffer.hasData();
|
||||
}
|
||||
|
||||
private void setClient(ClientThread client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
void setTelnetEscape(boolean telnetEscape) {
|
||||
this.telnetEscape = telnetEscape;
|
||||
}
|
||||
|
||||
private void dataReceived(int data) {
|
||||
buffer.put((byte) data);
|
||||
if (notify != null)
|
||||
notify.hasChanged();
|
||||
}
|
||||
|
||||
private final class ServerThread extends Thread {
|
||||
|
||||
private ServerThread() {
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
Socket client = serverSocket.accept();
|
||||
ClientThread cl = new ClientThread(client, Server.this);
|
||||
cl.start();
|
||||
setClient(cl);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class ClientThread extends Thread {
|
||||
|
||||
private static final int ECHO = 1;
|
||||
private static final int SGA = 3;
|
||||
private static final int WILL = 251;
|
||||
private static final int WONT = 252;
|
||||
private static final int DO = 253;
|
||||
private static final int DONT = 254;
|
||||
private static final int IAC = 255;
|
||||
|
||||
private final InputStream in;
|
||||
private final OutputStream out;
|
||||
private final Socket client;
|
||||
private final Server server;
|
||||
|
||||
private ClientThread(Socket client, Server server) throws IOException {
|
||||
setDaemon(true);
|
||||
in = client.getInputStream();
|
||||
out = client.getOutputStream();
|
||||
if (server.telnetEscape) {
|
||||
out.write(IAC);
|
||||
out.write(WILL);
|
||||
out.write(SGA);
|
||||
out.write(IAC);
|
||||
out.write(WILL);
|
||||
out.write(ECHO);
|
||||
out.flush();
|
||||
}
|
||||
this.client = client;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
int data = in.read();
|
||||
if (data == IAC && server.telnetEscape) {
|
||||
int command = in.read();
|
||||
int option = in.read();
|
||||
} else
|
||||
server.dataReceived(data);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
client.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void send(int value) {
|
||||
try {
|
||||
out.write(value);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
client.close();
|
||||
} catch (IOException ioException) {
|
||||
ioException.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.core.io.telnet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Simple singleton to hold the server instances.
|
||||
* Usage of this singleton allows the telnet client to stay connected
|
||||
* also if the simulation is not running.
|
||||
*/
|
||||
public final class ServerHolder {
|
||||
/**
|
||||
* The singleton instance
|
||||
*/
|
||||
public static final ServerHolder INSTANCE = new ServerHolder();
|
||||
|
||||
private final HashMap<Integer, Server> serverMap;
|
||||
|
||||
private ServerHolder() {
|
||||
serverMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a server.
|
||||
*
|
||||
* @param port the port
|
||||
* @return the server
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public Server getServer(int port) throws IOException {
|
||||
Server server = serverMap.get(port);
|
||||
if (server == null) {
|
||||
server = new Server(port);
|
||||
serverMap.put(port, server);
|
||||
}
|
||||
return server;
|
||||
}
|
||||
}
|
109
src/main/java/de/neemann/digital/core/io/telnet/Telnet.java
Normal file
109
src/main/java/de/neemann/digital/core/io/telnet/Telnet.java
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.core.io.telnet;
|
||||
|
||||
import de.neemann.digital.core.*;
|
||||
import de.neemann.digital.core.element.Element;
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.ElementTypeDescription;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import de.neemann.digital.draw.elements.PinException;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static de.neemann.digital.core.element.PinInfo.input;
|
||||
|
||||
/**
|
||||
* The telnet node
|
||||
*/
|
||||
public class Telnet extends Node implements Element {
|
||||
|
||||
/**
|
||||
* The telnet server description
|
||||
*/
|
||||
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(Telnet.class,
|
||||
input("in"), input("C").setClock(), input("wr"), input("rd"))
|
||||
.addAttribute(Keys.ROTATE)
|
||||
.addAttribute(Keys.LABEL)
|
||||
.addAttribute(Keys.TELNET_ESCAPE)
|
||||
.addAttribute(Keys.PORT);
|
||||
|
||||
private final ObservableValue dataOut;
|
||||
private final ObservableValue dataAvail;
|
||||
private final int port;
|
||||
private final boolean telnetEscape;
|
||||
private ObservableValue dataIn;
|
||||
private ObservableValue clockValue;
|
||||
private ObservableValue writeEnable;
|
||||
private ObservableValue readEnableValue;
|
||||
private Server server;
|
||||
private boolean lastClock;
|
||||
private boolean readEnable;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param attributes The components attributes
|
||||
*/
|
||||
public Telnet(ElementAttributes attributes) {
|
||||
dataOut = new ObservableValue("out", 8)
|
||||
.setToHighZ()
|
||||
.setPinDescription(DESCRIPTION);
|
||||
dataAvail = new ObservableValue("av", 1)
|
||||
.setPinDescription(DESCRIPTION);
|
||||
port = attributes.get(Keys.PORT);
|
||||
telnetEscape = attributes.get(Keys.TELNET_ESCAPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputs(ObservableValues inputs) throws NodeException {
|
||||
dataIn = inputs.get(0).checkBits(8, this, 0);
|
||||
clockValue = inputs.get(1).checkBits(1, this, 1).addObserverToValue(this);
|
||||
writeEnable = inputs.get(2).checkBits(1, this, 2);
|
||||
readEnableValue = inputs.get(3).checkBits(1, this, 3).addObserverToValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readInputs() throws NodeException {
|
||||
boolean clock = clockValue.getBool();
|
||||
readEnable = readEnableValue.getBool();
|
||||
if (clock & !lastClock) {
|
||||
if (writeEnable.getBool())
|
||||
server.send((int) dataIn.getValue());
|
||||
if (readEnable)
|
||||
server.delete();
|
||||
}
|
||||
lastClock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeOutputs() throws NodeException {
|
||||
if (readEnable)
|
||||
dataOut.setValue(server.getData());
|
||||
else
|
||||
dataOut.setToHighZ();
|
||||
|
||||
dataAvail.setBool(server.hasData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValues getOutputs() throws PinException {
|
||||
return new ObservableValues(dataOut, dataAvail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Model model) throws NodeException {
|
||||
try {
|
||||
server = ServerHolder.INSTANCE.getServer(port);
|
||||
} catch (IOException e) {
|
||||
throw new NodeException(Lang.get("err_couldNotCreateServer"), e);
|
||||
}
|
||||
server.setTelnetEscape(telnetEscape);
|
||||
server.setNotify(() -> model.modify(Telnet.this::hasChanged));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implement's a telnet connection to the simulator
|
||||
*/
|
||||
package de.neemann.digital.core.io.telnet;
|
@ -15,6 +15,7 @@ import de.neemann.digital.core.extern.External;
|
||||
import de.neemann.digital.core.extern.ExternalFile;
|
||||
import de.neemann.digital.core.flipflops.*;
|
||||
import de.neemann.digital.core.io.*;
|
||||
import de.neemann.digital.core.io.telnet.Telnet;
|
||||
import de.neemann.digital.core.memory.*;
|
||||
import de.neemann.digital.core.pld.DiodeBackward;
|
||||
import de.neemann.digital.core.pld.DiodeForward;
|
||||
@ -150,6 +151,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
|
||||
.add(new LibraryNode(Lang.get("lib_peripherals"))
|
||||
.add(Keyboard.DESCRIPTION)
|
||||
.add(Terminal.DESCRIPTION)
|
||||
.add(Telnet.DESCRIPTION)
|
||||
.add(VGA.DESCRIPTION)
|
||||
.add(MIDI.DESCRIPTION)
|
||||
)
|
||||
|
@ -280,6 +280,16 @@
|
||||
</string>
|
||||
<string name="elem_Terminal_pin_en">Ein High an diesem Eingang aktiviert den Takteingang.</string>
|
||||
|
||||
<string name="elem_Telnet">Telnet</string>
|
||||
<string name="elem_Telnet_tt">Erlaubt eine Telnet-Verbindung zur Schaltung.
|
||||
Es können per Telnet Zeichen empfangen und gesendet werden.</string>
|
||||
<string name="elem_Telnet_pin_out">Datenausgabe</string>
|
||||
<string name="elem_Telnet_pin_av">Gibt eine Eins aus, wenn Daten vorhanden sind.</string>
|
||||
<string name="elem_Telnet_pin_in">Die zu sendenden Daten.</string>
|
||||
<string name="elem_Telnet_pin_C">Takteingang.</string>
|
||||
<string name="elem_Telnet_pin_wr">Wenn gesetzt, wird das Eingangsdatenbyte gesendet.</string>
|
||||
<string name="elem_Telnet_pin_rd">Wenn gesetzt, wird ein empfangenes Byte ausgegeben.</string>
|
||||
|
||||
<string name="elem_VGA">VGA Bildschirm</string>
|
||||
<string name="elem_VGA_tt">Analysiert die eingehenden Video-Signale und zeigt die entsprechende Grafik an.
|
||||
Da die Simulation nicht in Echtzeit laufen kann, wird zusätzlich zu den Videosignalen der Pixeltakt benötigt.</string>
|
||||
@ -1240,6 +1250,7 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
<string name="err_csvToManyValues">Zu viel Werte in einer Zeile!</string>
|
||||
<string name="err_errorWritingFile_N">Fehler beim Schreiben der Datei {0}.</string>
|
||||
<string name="err_circuitContainsNoComponents">Die Schaltung enthält keine Bauteile!</string>
|
||||
<string name="err_couldNotCreateServer">Der Server konnte nicht gestartet werden!</string>
|
||||
|
||||
<string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
|
||||
<string name="key_AddrBits_tt">Anzahl der Adress-Bits, die verwendet werden.</string>
|
||||
@ -1664,6 +1675,14 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
<string name="key_probeMode_DOWN">Zähle fallende Flanken</string>
|
||||
<string name="key_probeMode_BOTH">Zähle beide Flanken</string>
|
||||
|
||||
<string name="key_telnetEscape">Steuercodes</string>
|
||||
<string name="key_telnetEscape_tt">Wenn gesetzt, werden die Telnet Steuerkommandos gefiltert.
|
||||
Zusätzlich werden vom Server die Kommandos SGA uch ECHO gesendet.
|
||||
Wird diese Option deaktiviert, handelt es sich um einen einfachen TCP server.
|
||||
</string>
|
||||
<string name="key_port">Port</string>
|
||||
<string name="key_port_tt">Der vom Server zu öffnende Port.</string>
|
||||
|
||||
<string name="key_colorScheme">Farbschema</string>
|
||||
<string name="key_colorScheme_DEFAULT">Normal</string>
|
||||
<string name="key_colorScheme_DARK">Dunkel</string>
|
||||
|
@ -280,6 +280,16 @@
|
||||
<string name="elem_Terminal_pin_D">The data to write to the terminal</string>
|
||||
<string name="elem_Terminal_pin_en">A high at this input enables the clock input.</string>
|
||||
|
||||
<string name="elem_Telnet">Telnet</string>
|
||||
<string name="elem_Telnet_tt">Allows a Telnet connection to the circuit.
|
||||
It is possible to receive and send characters via Telnet.</string>
|
||||
<string name="elem_Telnet_pin_out">Data output</string>
|
||||
<string name="elem_Telnet_pin_av">Outputs a one if data is present.</string>
|
||||
<string name="elem_Telnet_pin_in">The data to be sent.</string>
|
||||
<string name="elem_Telnet_pin_C">Clock input</string>
|
||||
<string name="elem_Telnet_pin_wr">If set, the input data byte is sent.</string>
|
||||
<string name="elem_Telnet_pin_rd">If set, a received byte is output.</string>
|
||||
|
||||
<string name="elem_VGA">VGA Monitor</string>
|
||||
<string name="elem_VGA_tt">Analyzes the incoming video signals and displays the corresponding graphic.
|
||||
Since the simulation cannot run in real time, the pixel clock is required in addition to the video signals.</string>
|
||||
@ -1227,6 +1237,7 @@
|
||||
<string name="err_csvToManyValues">Too many values in one line!</string>
|
||||
<string name="err_errorWritingFile_N">Error writing file {0}.</string>
|
||||
<string name="err_circuitContainsNoComponents">The circuit contains no components!</string>
|
||||
<string name="err_couldNotCreateServer">Could not start the server!</string>
|
||||
|
||||
<string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
|
||||
<string name="key_AddrBits_tt">Number of address bits used.</string>
|
||||
@ -1651,6 +1662,13 @@
|
||||
<string name="key_probeMode_DOWN">Count on Falling Edge</string>
|
||||
<string name="key_probeMode_BOTH">Count both Edges</string>
|
||||
|
||||
<string name="key_telnetEscape">Commands</string>
|
||||
<string name="key_telnetEscape_tt">If set, the Telnet control commands are filtered.
|
||||
In addition, the server sends the SGA and ECHO commands. If this option is disabled,
|
||||
the server is a simple TCP server.</string>
|
||||
<string name="key_port">Port</string>
|
||||
<string name="key_port_tt">The port to be opened by the server.</string>
|
||||
|
||||
<string name="key_colorScheme">Color scheme</string>
|
||||
<string name="key_colorScheme_DEFAULT">Normal</string>
|
||||
<string name="key_colorScheme_DARK">Dark</string>
|
||||
|
@ -695,15 +695,29 @@
|
||||
<int>8</int>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="1080"/>
|
||||
<pos x="420" y="1100"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>GenericCode</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="120" y="1120"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Telnet</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>port</string>
|
||||
<int>2323</int>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="540" y="1100"/>
|
||||
</visualElement>
|
||||
</visualElements>
|
||||
<wires>
|
||||
<wire>
|
||||
<p1 x="500" y="1060"/>
|
||||
<p2 x="520" y="1100"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1080" y="640"/>
|
||||
<p2 x="1100" y="640"/>
|
||||
@ -752,6 +766,10 @@
|
||||
<p1 x="700" y="520"/>
|
||||
<p2 x="800" y="520"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="520" y="1160"/>
|
||||
<p2 x="540" y="1160"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1160"/>
|
||||
<p2 x="420" y="1160"/>
|
||||
@ -864,6 +882,10 @@
|
||||
<p1 x="780" y="280"/>
|
||||
<p2 x="800" y="280"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1180"/>
|
||||
<p2 x="420" y="1180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="220" y="540"/>
|
||||
<p2 x="260" y="540"/>
|
||||
@ -916,6 +938,10 @@
|
||||
<p1 x="580" y="1060"/>
|
||||
<p2 x="600" y="1060"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="1060"/>
|
||||
<p2 x="500" y="1060"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="760" y="1060"/>
|
||||
<p2 x="840" y="1060"/>
|
||||
@ -1073,8 +1099,8 @@
|
||||
<p2 x="240" y="1080"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="1080"/>
|
||||
<p2 x="420" y="1080"/>
|
||||
<p1 x="400" y="1080"/>
|
||||
<p2 x="500" y="1080"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="240" y="1080"/>
|
||||
@ -1181,20 +1207,24 @@
|
||||
<p2 x="1160" y="840"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="220" y="460"/>
|
||||
<p2 x="260" y="460"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="460"/>
|
||||
<p2 x="620" y="460"/>
|
||||
<p1 x="380" y="1100"/>
|
||||
<p2 x="420" y="1100"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="240" y="1100"/>
|
||||
<p2 x="260" y="1100"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1100"/>
|
||||
<p2 x="420" y="1100"/>
|
||||
<p1 x="520" y="1100"/>
|
||||
<p2 x="540" y="1100"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="220" y="460"/>
|
||||
<p2 x="260" y="460"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="460"/>
|
||||
<p2 x="620" y="460"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="720"/>
|
||||
@ -1276,6 +1306,18 @@
|
||||
<p1 x="760" y="220"/>
|
||||
<p2 x="800" y="220"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1120"/>
|
||||
<p2 x="420" y="1120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="500" y="1120"/>
|
||||
<p2 x="520" y="1120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="520" y="1120"/>
|
||||
<p2 x="540" y="1120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1140" y="480"/>
|
||||
<p2 x="1160" y="480"/>
|
||||
@ -1413,8 +1455,8 @@
|
||||
<p2 x="1200" y="500"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1140"/>
|
||||
<p2 x="420" y="1140"/>
|
||||
<p1 x="520" y="1140"/>
|
||||
<p2 x="540" y="1140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1080" y="760"/>
|
||||
@ -1644,6 +1686,14 @@
|
||||
<p1 x="520" y="740"/>
|
||||
<p2 x="520" y="780"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="520" y="1120"/>
|
||||
<p2 x="520" y="1140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="520" y="1140"/>
|
||||
<p2 x="520" y="1160"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="840" y="1000"/>
|
||||
<p2 x="840" y="1060"/>
|
||||
@ -1714,19 +1764,23 @@
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1020"/>
|
||||
<p2 x="400" y="1100"/>
|
||||
<p2 x="400" y="1080"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1080"/>
|
||||
<p2 x="400" y="1120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="580"/>
|
||||
<p2 x="400" y="780"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1100"/>
|
||||
<p2 x="400" y="1140"/>
|
||||
<p1 x="400" y="1120"/>
|
||||
<p2 x="400" y="1160"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="1140"/>
|
||||
<p2 x="400" y="1160"/>
|
||||
<p1 x="400" y="1160"/>
|
||||
<p2 x="400" y="1180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="220"/>
|
||||
@ -2028,6 +2082,10 @@
|
||||
<p1 x="500" y="560"/>
|
||||
<p2 x="500" y="580"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="500" y="1080"/>
|
||||
<p2 x="500" y="1120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="500" y="760"/>
|
||||
<p2 x="500" y="840"/>
|
||||
@ -2160,6 +2218,10 @@
|
||||
<p1 x="380" y="140"/>
|
||||
<p2 x="380" y="160"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="1060"/>
|
||||
<p2 x="380" y="1100"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="160"/>
|
||||
<p2 x="380" y="820"/>
|
||||
@ -2170,7 +2232,7 @@
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="920"/>
|
||||
<p2 x="380" y="1080"/>
|
||||
<p2 x="380" y="1060"/>
|
||||
</wire>
|
||||
</wires>
|
||||
<measurementOrdering/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user