package org.yamcs.simulator; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yamcs.simulator.ui.SimWindow; public class Simulator extends Thread { private static final Logger log = LoggerFactory.getLogger(Simulator.class); private int DEFAULT_MAX_LENGTH=65542; private int maxLength = DEFAULT_MAX_LENGTH; private SimulationConfiguration simConfig; private TelemetryLink tmLink; protected Queue<CCSDSPacket> pendingCommands = new ArrayBlockingQueue<>(100); //no more than 100 pending commands private boolean isLos = false; private LosStore losStore; private SimWindow simWindow; public Simulator(SimulationConfiguration simConfig) { this.simConfig = simConfig; tmLink = new TelemetryLink(this, simConfig); losStore = new LosStore(this, simConfig); } @Override public void run() { for(ServerConnection serverConnection : simConfig.getServerConnections()) { tmLink.yamcsServerConnect(serverConnection); //start the TC reception thread; new Thread(() -> { while(true) { try { // read commands pendingCommands.addAll(readPackets(new DataInputStream(serverConnection.getTcSocket().getInputStream()))); Thread.sleep(4000); } catch (IOException e) { serverConnection.setConnected(false); tmLink.yamcsServerConnect(serverConnection); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); // start the TM transmission thread log.debug("Start TM thread"); (new Thread(() -> tmLink.packetSend(serverConnection))).start(); } } /** * this runs in a separate thread but pushes commands to the main TM thread */ protected Queue<CCSDSPacket> readPackets(DataInputStream dIn) { Queue<CCSDSPacket> packetQueue = new ArrayBlockingQueue<>(1000); try { while(dIn.available() > 0) { //READ IN PACKET byte hdr[] = new byte[6]; dIn.readFully(hdr); int remaining=((hdr[4]&0xFF)<<8)+(hdr[5]&0xFF)+1; if(remaining>maxLength-6) throw new IOException("Remaining packet length too big: "+remaining+" maximum allowed is "+(maxLength-6)); byte[] b = new byte[6+remaining]; System.arraycopy(hdr, 0, b, 0, 6); dIn.readFully(b, 6, remaining); CCSDSPacket packet = new CCSDSPacket(ByteBuffer.wrap(b)); packetQueue.add(packet); } //System.out.println("Packets Stored & Sent = "+ losStored + " : "+ losSent); } catch(IOException e) { System.err.println("Connection lost : " + e); } catch(Exception e) { System.err.println("Error reading command " + e); e.printStackTrace(); } return packetQueue; } public SimulationConfiguration getSimulationConfiguration() { return simConfig; } public LosStore getLosStore() { return losStore; } public boolean isLOS() { return isLos; } public void setLOS(boolean isLos) { this.isLos = isLos; } public TelemetryLink getTMLink() { return tmLink; } protected void transmitTM(CCSDSPacket packet) { tmLink.tmTransmit(packet); } public void dumpLosDataFile(String filename) { // read data from los storage if(filename == null) { filename = losStore.getCurrentFileName(); } DataInputStream dataStream = losStore.readLosFile(filename); if(dataStream == null) return; // extract packets from the data stream and put them in queue for downlink Queue<CCSDSPacket> qLosData = readPackets(dataStream); for(CCSDSPacket ccsdsPacket : qLosData) { for (ServerConnection serverConnection : simConfig.getServerConnections()) serverConnection.setTmDumpPacket(ccsdsPacket); } // add packet notifying that the file has been downloaded entirely CCSDSPacket confirmationPacket = buildLosTransmittedRecordingPacket(filename); for(ServerConnection serverConnection : simConfig.getServerConnections()) serverConnection.setTmDumpPacket(confirmationPacket); } private static CCSDSPacket buildLosTransmittedRecordingPacket(String transmittedRecordName) { CCSDSPacket packet = new CCSDSPacket(0, 2, 10); packet.appendUserDataBuffer(transmittedRecordName.getBytes()); packet.appendUserDataBuffer(new byte[1]); return packet; } public void deleteLosDataFile(String filename) { losStore.deleteFile(filename); // add packet notifying that the file has been deleted CCSDSPacket confirmationPacket = buildLosDeletedRecordingPacket(filename); for(ServerConnection serverConnection : simConfig.getServerConnections()) serverConnection.setTmDumpPacket(confirmationPacket); } private static CCSDSPacket buildLosDeletedRecordingPacket(String deletedRecordName) { CCSDSPacket packet = new CCSDSPacket(0, 2, 11); packet.appendUserDataBuffer(deletedRecordName.getBytes()); packet.appendUserDataBuffer(new byte[1]); return packet; } public SimWindow getSimWindow() { return simWindow; } public void setSimWindow(SimWindow simWindow) { this.simWindow = simWindow; } public void startTriggeringLos() { losStore.startTriggeringLos(); } public void stopTriggeringLos() { losStore.stopTriggeringLos(); } }