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

org.yamcs.sle.user.RcfServiceUserHandler Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
package org.yamcs.sle.user;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.CompletableFuture;

import com.beanit.jasn1.ber.BerTag;

import org.yamcs.sle.AntennaId;
import org.yamcs.sle.CcsdsTime;
import org.yamcs.sle.Constants;
import org.yamcs.sle.Isp1Authentication;
import org.yamcs.sle.SleParameter;
import org.yamcs.sle.RacfSleMonitor;
import org.yamcs.sle.SleException;
import org.yamcs.sle.State;
import org.yamcs.sle.StringConverter;
import org.yamcs.sle.Constants.ApplicationIdentifier;
import org.yamcs.sle.Constants.DeliveryMode;
import org.yamcs.sle.Constants.FrameQuality;
import org.yamcs.sle.Constants.LockStatus;
import org.yamcs.sle.Constants.ParameterName;
import org.yamcs.sle.Constants.ProductionStatus;
import org.yamcs.sle.GVCID;

import ccsds.sle.transfer.service.common.types.InvokeId;
import ccsds.sle.transfer.service.rcf.outgoing.pdus.RcfTransferDataInvocation.PrivateAnnotation;
import ccsds.sle.transfer.service.rcf.incoming.pdus.RcfGetParameterInvocation;
import ccsds.sle.transfer.service.rcf.incoming.pdus.RcfStartInvocation;
import ccsds.sle.transfer.service.rcf.incoming.pdus.RcfUserToProviderPdu;
import ccsds.sle.transfer.service.rcf.outgoing.pdus.FrameOrNotification;
import ccsds.sle.transfer.service.rcf.outgoing.pdus.RcfGetParameterReturn;
import ccsds.sle.transfer.service.rcf.outgoing.pdus.RcfStartReturn;
import ccsds.sle.transfer.service.rcf.outgoing.pdus.RcfStatusReportInvocation;
import ccsds.sle.transfer.service.rcf.outgoing.pdus.RcfSyncNotifyInvocation;
import ccsds.sle.transfer.service.rcf.outgoing.pdus.RcfTransferBuffer;
import ccsds.sle.transfer.service.rcf.outgoing.pdus.RcfTransferDataInvocation;
import ccsds.sle.transfer.service.rcf.structures.RcfParameterName;
import ccsds.sle.transfer.service.rcf.structures.LockStatusReport;
import ccsds.sle.transfer.service.rcf.structures.Notification;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 * Implementation for the CCSDS RECOMMENDED STANDARD FOR SLE RAF SERVICE
 * CCSDS 911.1-B-4 August 2016
 * https://public.ccsds.org/Pubs/911x1b4.pdf
 * 

* This is copy and paste from {@link RafServiceUserHandler} because the RAF and RCF are almost the same but slightly so * different (seems like the CCSDS committee was missing from school when the lessons about code reused has been taught). *

* We do however provide one common RAF/RCF interface to our users highlighting the small differences in the API. * @author nm * */ public class RcfServiceUserHandler extends RacfServiceUserHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(RcfServiceUserHandler.class); public RcfServiceUserHandler(Isp1Authentication auth, SleAttributes attr, DeliveryMode deliveryMode, FrameConsumer consumer) { super(auth, attr, deliveryMode, consumer); this.consumer = consumer; } /** * Get the value of an RAF parameter from the provider * * @param parameterId * one of the parameters defined in {@link ParameterName}. Note that not all of them make sense for the * RAF, see the table 3-11 in the standard to see which ones make sense. * @return */ public CompletableFuture getParameter(int parameterId) { CompletableFuture cf = new CompletableFuture<>(); channelHandlerContext.executor().execute(() -> sendGetParameter(parameterId, cf)); return cf; } /** * Request that the SLE service provider starts sending * * @return */ public CompletableFuture start(CcsdsTime startTime, CcsdsTime stopTime, GVCID requestedGvcid) { CompletableFuture cf = new CompletableFuture<>(); channelHandlerContext.executor().execute(() -> sendStart(cf, startTime, stopTime, requestedGvcid)); return cf; } /** * Add a monitor to be notified when events happen. * * @param monitor */ public void addMonitor(RacfSleMonitor monitor) { monitors.add(monitor); } public void removeMonitor(RacfSleMonitor monitor) { monitors.remove(monitor); } /** * Request that the SLE service provider starts sending data * * @return */ public CompletableFuture start(GVCID requestedGvcid) { CompletableFuture cf = new CompletableFuture<>(); channelHandlerContext.executor().execute(() -> sendStart(cf, requestedGvcid)); return cf; } private void sendStart(CompletableFuture cf, GVCID requestedGvcid) { sendStart(cf, null, null, requestedGvcid); } protected void processData(BerTag berTag, InputStream is) throws IOException { if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 8)) { RcfTransferBuffer rafTransferBuffer = new RcfTransferBuffer(); rafTransferBuffer.decode(is, false); processTransferBuffer(rafTransferBuffer); } else if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { RcfStartReturn rafStartReturn = new RcfStartReturn(); rafStartReturn.decode(is, false); processStartReturn(rafStartReturn); } else if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 9)) { RcfStatusReportInvocation rafStatusReportInvocation = new RcfStatusReportInvocation(); rafStatusReportInvocation.decode(is, false); processStatusReportInvocation(rafStatusReportInvocation); } else if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 7)) { RcfGetParameterReturn rafGetParameterReturn = new RcfGetParameterReturn(); rafGetParameterReturn.decode(is, false); processGetParameterReturn(rafGetParameterReturn); } else { logger.warn("Unexpected state berTag: {} ", berTag); throw new IllegalStateException(); } } private void sendGetParameter(int parameterId, CompletableFuture cf) { RcfUserToProviderPdu rutp = new RcfUserToProviderPdu(); RcfGetParameterInvocation cgpi = new RcfGetParameterInvocation(); cgpi.setInvokeId(getInvokeId(cf)); cgpi.setInvokerCredentials(getNonBindCredentials()); cgpi.setRcfParameter(new RcfParameterName(parameterId)); rutp.setRcfGetParameterInvocation(cgpi); channelHandlerContext.writeAndFlush(rutp); } protected void sendStart(CompletableFuture cf, CcsdsTime start, CcsdsTime stop, GVCID requestedGvcid) { if (state != State.READY) { cf.completeExceptionally(new SleException("Cannot call start while in state " + state)); return; } changeState(State.STARTING); this.startingCf = cf; RcfUserToProviderPdu rutp = new RcfUserToProviderPdu(); RcfStartInvocation rsi = new RcfStartInvocation(); rsi.setInvokeId(new InvokeId(1)); rsi.setStartTime(CcsdsTime.toSleConditional(start, sleVersion)); rsi.setStopTime(CcsdsTime.toSleConditional(stop, sleVersion)); rsi.setRequestedGvcId(requestedGvcid.toRcf()); rsi.setInvokerCredentials(getNonBindCredentials()); rutp.setRcfStartInvocation(rsi); channelHandlerContext.writeAndFlush(rutp); } private void processStartReturn(RcfStartReturn rcfStartReturn) { verifyNonBindCredentials(rcfStartReturn.getPerformerCredentials()); if (state != State.STARTING) { peerAbort(); return; } ccsds.sle.transfer.service.rcf.outgoing.pdus.RcfStartReturn.Result r = rcfStartReturn.getResult(); if (r.getNegativeResult() != null) { changeState(State.READY); startingCf.completeExceptionally(new SleException("received negative result to start request: "+StringConverter.toString(r.getNegativeResult()))); } else { changeState(State.ACTIVE); startingCf.complete(null); } } private void processGetParameterReturn(RcfGetParameterReturn rcfGetParameterReturn) { verifyNonBindCredentials(rcfGetParameterReturn.getPerformerCredentials()); CompletableFuture cf = getFuture(rcfGetParameterReturn.getInvokeId()); RcfGetParameterReturn.Result r = rcfGetParameterReturn.getResult(); if (r.getNegativeResult() != null) { cf.completeExceptionally(new SleException("error getting parameter", r.getNegativeResult())); } else { cf.complete(new SleParameter(r.getPositiveResult())); } } private void processStatusReportInvocation(RcfStatusReportInvocation rafStatusReportInvocation) { verifyNonBindCredentials(rafStatusReportInvocation.getInvokerCredentials()); if (logger.isTraceEnabled()) { logger.trace("Received statusReport {}", rafStatusReportInvocation); } monitors.forEach(m -> ((RacfSleMonitor)m).onStatusReport(new RacfStatusReport(rafStatusReportInvocation))); } private void processTransferBuffer(RcfTransferBuffer rcfTransferBuffer) { for (FrameOrNotification fon : rcfTransferBuffer.getFrameOrNotification()) { RcfTransferDataInvocation rtdi = fon.getAnnotatedFrame(); if (rtdi != null) { verifyNonBindCredentials(rtdi.getInvokerCredentials()); CcsdsTime ert = CcsdsTime.fromSle(rtdi.getEarthReceiveTime()); int dlc = rtdi.getDataLinkContinuity().intValue(); PrivateAnnotation pa =rtdi.getPrivateAnnotation(); byte[] privAnn = pa.getNotNull()==null?null:pa.getNotNull().value; byte[] data = rtdi.getData().value; AntennaId antId = new AntennaId(rtdi.getAntennaId()); consumer.acceptFrame(ert, antId, dlc, FrameQuality.good, privAnn, data); } RcfSyncNotifyInvocation rsi = fon.getSyncNotification(); if (rsi != null) { try { verifyNonBindCredentials(rsi.getInvokerCredentials()); Notification notif = rsi.getNotification(); if (notif.getLossFrameSync() != null) { LockStatusReport lsr = notif.getLossFrameSync(); consumer.onLossFrameSync(CcsdsTime.fromSle(lsr.getTime()), LockStatus.byId(lsr.getCarrierLockStatus().intValue()), LockStatus.byId(lsr.getSubcarrierLockStatus().intValue()), LockStatus.byId(lsr.getSymbolSyncLockStatus().intValue())); } else if (notif.getProductionStatusChange() != null) { consumer.onProductionStatusChange( ProductionStatus.byId(notif.getProductionStatusChange().intValue())); } else if (notif.getExcessiveDataBacklog() != null) { consumer.onExcessiveDataBacklog(); } else if (notif.getEndOfData() != null) { consumer.onEndOfData(); } } catch (IllegalArgumentException e) { logger.warn("Invalid notification received ", e); peerAbort(); } } } } @Override protected ApplicationIdentifier getApplicationIdentifier() { return Constants.ApplicationIdentifier.rtnChFrames; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy