All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.simulation.simulator.TmTcLink Maven / Gradle / Ivy

package org.yamcs.simulation.simulator;

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.util.concurrent.AbstractExecutionThreadService;

/**
 * TCP link that can be used both for TM and TC
 */
public class TmTcLink extends AbstractExecutionThreadService {

    private static final Logger log = LoggerFactory.getLogger(TmTcLink.class);
    final String name;
    private Simulator simulator;
    int port;
    volatile boolean connected;
    Socket socket;
    ServerSocket serverSocket;
    DataInputStream inputStream;

    private int maxTcLength = Simulator.DEFAULT_MAX_LENGTH;
    private int MIN_TC_LENGTH = 16;

    private BlockingQueue queue = new LinkedBlockingQueue<>(100);

    public TmTcLink(String name, Simulator simulator, int port) {
        this.name = name;
        this.simulator = simulator;
        this.port = port;
    }

    public void sendPacket(byte[] packet) {
        try {
            if (connected) {
                queue.put(packet);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    @Override
    protected void run() throws Exception {
        while (isRunning()) {
            if (!connected) {
                connect();
            }
            if (!connected) {
                continue;
            }
            try {
                byte[] p = queue.poll(1, TimeUnit.SECONDS);
                if (p != null) {
                    socket.getOutputStream().write(p);
                }
            } catch (IOException e1) {
                log.error("Error while sending " + name + " packet", e1);
                connect();
            }

            try {
                if (socket.getInputStream().available() > 0) {
                    CCSDSPacket tc = readPacket(inputStream);
                    if (tc != null) {
                        simulator.processTc(tc);
                    } else {
                        connected = false;
                    }
                }
            } catch (IOException e1) {
                log.error("Error while receiving packet on " + name + " socket", e1);
                connect();
            }
        }
    }

    void connect() {
        // Check for previous connection, used for loss of server.
        if (socket != null) {
            try {
                connected = false;
                inputStream.close();
                socket.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            log.info("Waiting for {} connection from server on port {}", name, port);
            serverSocket = new ServerSocket(port);
            socket = serverSocket.accept();
            inputStream = new DataInputStream(socket.getInputStream());
            connected = true;
            log.info("Connected: {}:{}", socket.getInetAddress(), socket.getPort());
        } catch (Exception e) {
            if(isRunning()) {
                e.printStackTrace();
            }
        }
    }

    public void ackPacketSend(CCSDSPacket packet) {
        if (connected) {
            try {
                packet.writeTo(socket.getOutputStream());
            } catch (IOException e1) {
                log.error("Error while sending {} packet", name, e1);
                connect();
            }
        }
    }

    CCSDSPacket readPacket(DataInputStream dIn) {
        try {
            byte hdr[] = new byte[6];
            dIn.readFully(hdr);
            int remaining = ((hdr[4] & 0xFF) << 8) + (hdr[5] & 0xFF) + 1;
            if(remaining < MIN_TC_LENGTH - 6) {
                throw new IOException("Command too short: " + (remaining+6) + " minimum required " + MIN_TC_LENGTH);
            }
            if (remaining > maxTcLength - 6) {
                throw new IOException(
                        "Remaining packet length too big: " + remaining + " maximum allowed is " + (maxTcLength - 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));
            return packet;
        } catch (EOFException e) {
            log.error(name+" Connection lost");
            connected = false;
        } catch (Exception e) {
            connected = false;
            log.error("Error reading command " + e.getMessage(), e);
        }
        return null;
    }
    
    protected void triggerShutdown() {
        if(serverSocket!=null) {
            try {
                serverSocket.close();
            } catch (IOException e) {
                //ignore error
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy