package org.yamcs.tctm; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yamcs.YamcsServer; import org.yamcs.archive.PacketWithTime; import org.yamcs.protobuf.Yamcs.EndAction; import org.yamcs.time.RealtimeTimeService; import org.yamcs.time.TimeService; import com.google.common.util.concurrent.AbstractExecutionThreadService; /** * Plays files in pacts format, hrdp format or containing raw ccsds packets. * @author nm * */ public class FileTmPacketProvider extends AbstractExecutionThreadService implements Runnable, TmPacketDataLink { volatile boolean quitting=false; EndAction endAction; String fileName; int fileoffset = 0; int packetcount = 0; long delayBetweenPackets=500; volatile boolean disabled=false; TmSink tmSink; TmFileReader tmFileReader; long tmCount=0; static Logger log=LoggerFactory.getLogger(FileTmPacketProvider.class.getName()); TimeService timeService; public FileTmPacketProvider(String instance, String name, String fileName) throws IOException { this(fileName, "STOP",1000); timeService = YamcsServer.getTimeService(instance); } /** * Constructs a packet provider that sends packets from a file at the indicated speed. * If the parameter loop is set to true, then jump back at the beginning of the file once the end has been reached. * @param fileName * @param delayBetweenPackets * @throws IOException */ public FileTmPacketProvider(String fileName, String endActionStr, long delayBetweenPackets) throws IOException { this.fileName = fileName; this.delayBetweenPackets=delayBetweenPackets; if (endActionStr.equalsIgnoreCase("LOOP")) { endAction=EndAction.LOOP; } else if (endActionStr.equalsIgnoreCase("QUIT")) { endAction=EndAction.QUIT; } else if (endActionStr.equalsIgnoreCase("STOP")) { endAction=EndAction.STOP; } log.debug("attempting to open file {}", this.fileName); tmFileReader = new TmFileReader(this.fileName); timeService = new RealtimeTimeService(); } @Override public void setTmSink(TmSink tmProcessor) { this.tmSink=tmProcessor; } @Override public void run() { try { while(isRunning()) { while(disabled) { Thread.sleep(1000); } PacketWithTime pwrt; pwrt = tmFileReader.readPacket(timeService.getMissionTime()); if(pwrt==null) { if ( endAction==EndAction.LOOP ) { log.info("File {} finished, looping back to the beginning", fileName); tmFileReader = new TmFileReader(this.fileName); } else { log.info("File {} finished", fileName); break; } } if(delayBetweenPackets>0) { Thread.sleep(delayBetweenPackets); } tmSink.processPacket(pwrt); tmCount++; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (IOException e) { log.warn("Got exception while reading packets: ", e); } } /** * @return the delayBetweenPakets */ public long getDelayBetweenPackets() { return delayBetweenPackets; } /** * @param delayBetweenPackets the delayBetweenPakets to set */ public void setDelayBetweenPackets(int delayBetweenPackets) { this.delayBetweenPackets = delayBetweenPackets; } @Override public String getLinkStatus() { if (disabled) { return "DISABLED"; } if(quitting) { return "UNAVAIL"; } else { return "OK"; } } @Override public void triggerShutdown() { try { tmFileReader.close(); } catch (IOException e) { log.warn("Got exception while closing the stream: ", e); } } @Override public void disable() { disabled=true; } @Override public void enable() { disabled=false; } @Override public boolean isDisabled() { return disabled; } @Override public String getDetailedStatus() { return "Playing file "+fileName+", endAction="+endAction+" delayBetweenPackets="+delayBetweenPackets+" packetcount="+packetcount; } @Override public long getDataCount() { return tmCount; } }