dariol83 / ccsds

Open source Java implementation of publicly available CCSDS standards: SLE, TM/TC, AOS, Space Packets, COP-1, time formats, CFDP, Encapsulation Packets.
Apache License 2.0
93 stars 29 forks source link

Space packet frames to SLE #21

Closed maqnico closed 1 month ago

maqnico commented 5 months ago

Hi @dariol83, i am currently working on a Validation for Uplink and Downlink for a small, scientific, environmental monitoring Satellite. For that i need to convert output from a Software Radio to SLE format. The Radio i currently have set up is qRadio from Kratos, but that can be changed if need be. The output from qRadio is provided as CCSDS Space Packets with either Raw or T501 Data Header Type. I was thinking your TM/TC and SLE Packages might be of great help, since your repository seems to be quite complete, well documented and maintained. Since it is my first time working with TT&C and i´m only moderately proficient with Java i was hoping maybe you could give me some pointers on how to get started. What general architecture might work, which objects from your packages might be useful or maybe if you know someone, who has already built a similar application. If it interests you, i could share my repository for the project with you to keep you updated on progress. Also let me know, should you prefer to message privately. I´d be really grateful for your help and look forward to your answer. Yours Sincerely, Nicolas

dariol83 commented 5 months ago

Hello @maqnico (Nicolas) First of all, thank you for reaching out and for checking this repository :) I will be happy to give you some entry points for your task. I also have some remarks and comments, since I do not know the qRadio software and I don't know anyone who tried to implement an SLE provider using my library with qRadio as backend.

If I understand correctly, you need to write a piece of software that:

First of all, let me clarify that the SLE protocol is meant to deliver CCSDS transfer frames (TM frames, AOS frames) and not CCSDS space packets, which are encoded inside the transfer frames. Therefore, you have two options:

Once you know how to receive frames from qRadio, you need to instantiate a RAF SLE provider, configure it and provide it with some information, e.g. when qRadio is locked on the carrier, if the qRadio bit synchroniser is locked, if the frame synchroniser is locked.

To help you to understand how to use my library to achieve the above, I took the opportunity of your request to quickly wrote a simple example, which you can find in the examples module. The application, called SleDataProvision, connects to a server providing plain TM frames in binary format, and forwards such frames to anyone that connects to its RAF SLE service instance. This SLE service instance is configurable using an external configuration file. The application code is quite short (177 lines of code in total, including imports, comments and formatting lines) and it should give you a decent entry point to code a simple proof of concept for your purposes.

You can try out the whole chain:

If you want to cover the uplink, the approach will be similar, but clearly the direction is reverted: the CLTU service instance will receive CLTUs, that you will have to forward to qRadio and notify back when they are radiated. I did not write an example for this but, if you can get the telemetry part working, I am sure you can also implement the telecommand one :)

Two final points:

Best regards, Dario

maqnico commented 5 months ago

Hi Dario, thank you for your quick reply! It seems i can configure qRadio to deliver a stream of TM-Transfer Frames without Attaching a header (Which it calls Header Type: RAW) so approach 1 should work fine. For TC i may have to attach a 16-Bit header, according to the T501 format, so qRadio can work with the frames. I´ve done some more in depth reading on CCSDS and will now try out and hopefully be capable of understanding your example. Much appreciated, Nicolas

dariol83 commented 5 months ago

Hi Nicolas, Glad to hear that qRadio allows you to receive plain TM transfer frames. It should put you in a good position to build a simple SLE TM provider interfacing qRadio.

Concerning the telecommands: using SLE CLTU, they are delivered to the SLE provider already in a CLTU encoded format, e.g.: EB90.......C5C5C5C5C5C5C579 (or similar trailer). I expect that qRadio will modulates the bits of the telecommand as delivered, over the space link. If that is the case, it is enough to provide to qRadio the CLTU as-is, but of course you might need to comply with the qRadio-specific interface/protocol for doing that. I don't know the details.

If you have further questions about my implementation, please let me know.

Cheers, Dario

Il giorno mar 26 mar 2024 alle ore 15:08 maqnico @.***> ha scritto:

Hi Dario, thank you for your quick reply! It seems i can configure qRadio to deliver a stream of TM-Transfer Frames without Attaching a header (Which it calls Header Type: RAW) so approach 1 should work fine. For TC i may have to attach a 16-Bit header, according to the T501 format, so qRadio can work with the frames. I´ve done some more in depth reading on CCSDS and will now try out and hopefully be capable of understanding your example. Much appreciated, Nicolas

— Reply to this email directly, view it on GitHub https://github.com/dariol83/ccsds/issues/21#issuecomment-2020529533, or unsubscribe https://github.com/notifications/unsubscribe-auth/AME24BGEE4H2ERFXQCKOILLY2FXNZAVCNFSM6AAAAABFGS4LA2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRQGUZDSNJTGM . You are receiving this because you were mentioned.Message ID: @.***>

maqnico commented 4 months ago

Hi Dario, so far i managed to implement and deploy the RAF side just fine and am working on finishing the CLTU side. Validation with the mission is still pending for external reasons, but i am quite optimistic for the TM side to work.

There is one thing missing though, that would be the authentication. I am currently relying on my firewall only, which is not ideal, but working on that as well. Am i right in assuming it would be sensible to compare initiators and passwords when receiving a START operation? Or do you have an inbuilt method for authentication? If so, I haven´t ben able to find it yet.

Cheers, Nicolas

PS: Let me know, if i should open this as a separate Issue.

maqnico commented 4 months ago

Hi Dario,

i think i found it. The authentication is already built in, but needs to be enabled with: <peer id="someID" auth-mode="ALL" auth-hash="SHA_1" password="even-digits-hex-number" /> in the config XMLs. This will check authentication for all operations, which should not make it necessary to change anything about the Start Invocation behaviour. Is this correct?

Cheers, Nicolas

dariol83 commented 4 months ago

Hi Nicolas,

that is correct. In order to activate the authentication (which you can have only for the BIND operation, or for all operations), you have to select a password, which must be the same configured on the peer and the one in the attribute "password" of the tag. The auth-hash algorithm should be SHA_1 for old SLE versions (I think up to version 3), and SHA_256 for the newer versions 4 and 5. If you enable the authentication on all PDUs, the START operation will reach your code only if it goes through the authentication.

I hope it is clear. If you are interested in the details, you can find some additional information here:

I hope it helps. Please let me know if you manage to achieve a connection with authentication, as soon as you can test it.

Cheers, Dario

maqnico commented 4 months ago

Hi Dario, thank you for being so interested in this and also for answering my many questions. :) Currently i am testing with your SleFxTestTool and getting BIND-RETURNs for both RAF and CLTU instances with Authentication. Screenshot 2024-05-07 172952 Screenshot 2024-05-07 173308 I am also looking forward to testing this with another SLE-Client, for which i will be getting access soon.

However i´m not quite done with the Data Transfer for the CLTU instance. I am currently getting the return: START-RETURN result: negativeResult: specific: 1

Is my understanding correct, that i need to create a Socket (defining the target Host and target Port), then read a frame from my instance (What method have you intended for this?) and write the output the Socket?

Cheers, Nicolas

dariol83 commented 4 months ago

Hi Nicolas,

I am glad to see you are doing progresses with this, very good!

About the CLTU instance: your question is a bit unclear to me. From what I understand, you have difficulties to understand how to interface/use a CltuProvider against qRadio. I don't know how you can practically implement such interface, because I don't know qRadio. In any case, though, I would suspect that qRadio has an interface with a protocol similar to the TM one, with the difference that you have to write to the socket (and perhaps read some updates/acks... it depends on the protocol).

If you are checking instead an example on how to use/implement your CLTU Service Instance, then you have an example in the package eu.dariolucia.ccsds.sle.utl.provider inside the test folder of the sle.utl module.

When using the CltuServiceInstanceProvider class, it is fundamental to understand its usage pattern (the example will show you):

  1. Create the CltuServiceInstanceProvider with the correct configuration objects;
  2. Call the configure() method;
  3. If you need to register a subscriber (and I would do it, to be able to monitor what the provider will do), then you add a subscriber now, with the method register(...)

Then you have do configure the special handlers: this is not needed for the TM-based service instances, but you have to do it for the CLTU.

  1. setStartOperationHandler((o) -> CltuStartResult.noError()); is a typical way to indicate that the START should be always OK, but the behaviour can vary. For instance, you might want to connect to qRadio at this stage, and return a positive, no-error response only if qRadio is available.
  2. setUnbindReturnBehaviour(true); is a typical behaviour
  3. setThrowEventOperationHandler(this::throwEventHandler); this is the handler that is called when the service instance receives a THROW-EVENT invocation
  4. setTransferDataOperationHandler(this::transferDataHandler); this is the handler that will be called when the service instance receives a TRANSFER-DATA

In the test code, I also call this method: updateProductionStatus(CltuProductionStatusEnum.OPERATIONAL, CltuUplinkStatusEnum.NOMINAL, availableBuffer); It is important that the production status is set to OPERATIONAL, otherwise the user will not be able to send CLTUs and not even capable to receive a positive START-RETURN! When this should be set to OPERATIONAL is up to you, you might decide several approaches, but my recommendation, at least at the beginning, is to set it OPERATIONAL as soon as you have a connection to the qRadio interface, which you can establish at CLTU provider service instance creation time, or at BIND time. In your test, you receive back the code 1, which means "unable to comply" and this is set when the production status is INTERRUPTED.

If you want to check the internals of the START handling for the CLTU, try to read the code in the CltuServiceInstanceProvider class, method handleCltuStartInvocation: it is not very difficult.

Please check my answer, hoping that I guessed what your original question was :) If not, please clarify the context a bit more, I will happily help you.

Best regards, Dario

maqnico commented 3 months ago

Hi Dario, i think i have the CLTU side working, after setting the correct handlers and some fiddling. I am now getting the cltu with byte[] cltu = cltuTransferDataInvocation.getCltuData().value; then opening a new TimerTask and writing the cltu to a Socket which connects to qRadio. I still have a number of things to improve and a couple of questions though:

Raf side: 1) If i read N bytes from Socket this does not guarantee the frame i´m getting starts at the correct position, right? I would need to identify the FrameSync word that marks the beginning of a SpacePacket and start reading from there. 2) If i want to output the real frame Quality i´d need to read the checksum of the SpacePacket and perform the check myself, right?

Cltu side: 3) Does the service instance check that cltu-IDs are sequential? I wrote a method to check this but wanted to know if it is redundant.

As always thank you for being so nice and helpful, Cheers, Nicolas

dariol83 commented 3 months ago

Hi Nicolas,

Always nice to hear that you are progressing, very good! Let's see if I can help a bit.

On your way of dealing with CLTUs: the approach you implement is correct, the CLTU (EB90....C5C5C5...) is delivered in the value field of the object returned by the getCltuData() method. I don't know why you need a timer task after that, to send the CLTU to qRadio, but this is linked to the way your application works. What I would do is, to put the CLTU (and some related information such as the CLTU ID) into a sort of FIFO buffer and have a separate thread that removes CLTUs from this buffer and sends them to qRadio. This thread should also inform the CLTU provider object when the CLTU is actually sent to qRadio for radiation, in case the notification of radiation was requested in the cltuTransferDataInvocation operation. But as I said: I don't know how you designed your code, so your solution could be perfectly fine.

Before answering to your other questions, I would need to fix some terminology, so that we can speak the same language, and understand each other:

I don't know the qRadio protocol, but I would assume that such protocol delivers to you probably transfer frames (TF) or CADU (i.e. TF with synch marker attached), plus some information. All receivers I know deliver always some ancillary information such as:

Said the above, related to the RAF/CLTU questions: 1) RAF Question: If i read N bytes from Socket this does not guarantee the frame i´m getting starts at the correct position, right? I would need to identify the FrameSync word that marks the beginning of a SpacePacket and start reading from there. Answer: assuming that you are referring to the qRadio protocol, then it depends on the protocol defined by qRadio to deliver transfer frames or CADU to a client (your RAF provider application). For sure, in your RAF provider application you do not need to extract space packets from transfer frames or CADU, because SLE RAF foresees the delivery of Transfer Frames only, and of CADUs only in specific circumstances. Based on one of your previous answers: if qRadio delivers only Transfer Frames, without the sync marker, then they all have fixed length and I believe you can safely assume that, upon connection, you can read N bytes from the socket every time (with N = length of the transfer frame) and be sure you have a transfer frame. But again, I am sure that qRadio comes with the specification of its protocol, so you should refer to what the protocol says, or you do some sort of reverse engineering: you connect to the qRadio TM TCP-IP port and you dump all the data that you get and you check if you see the sync marker somewhere, or if you receive transfer frames directly. It would be easier for me to help, if I could get the protocol specification, but... I guess this is proprietary information from Kratos and cannot be disclosed without agreement. 2) RAF Question: If i want to output the real frame Quality i´d need to read the checksum of the SpacePacket and perform the check myself, right? Answer: check the qRadio protocol if the quality information is somehow delivered when qRadio provides you the transfer frames or CADUs. In such case, you just have to map this information to the corresponding argument of transferData(byte[] spaceDataUnit, int quality,...). The int quality is, for instance, ReturnServiceInstanceProvider.FRAME_QUALITY_GOOD, if the quality is good. If your satellite is configured to have the Frame Error Control Field, and if qRadio does not check this field, then you can check it yourself. For this purpose, I recommend using my other module eu.dariolucia.ccsds.tmtc, and check the class TmTransferFrame or AosTransferFrame. By constructing an object like these, and check the isValid() method afterwords, you will know easily if the frame has errors or not. If qRadio instead delivers you the CADUs as they are, without making any check/error correction using the Reed Solomon codeblock, my module eu.dariolucia.ccsds.tmtc also has a Reed Solomon checker that tells you if a CADU has errors or not (but it does not fix these), and a way to extract the transfer frame from the CADU (which is very simple to do anyway). 3) CLTU Question: Does the service instance check that cltu-IDs are sequential? I wrote a method to check this but wanted to know if it is redundant Answer: yes, it does. In the CltuServiceInstanceProvider.java, you can see

        // Validate the request
        CltuTransferDataResult tdResult = CltuTransferDataResult.noError(0);
        boolean permittedOk = true;
        // Expected CLTU identification
        if(invocation.getCltuIdentification().intValue() != this.cltuIdentification) {
            permittedOk = false;
            tdResult = CltuTransferDataResult.errorSpecific(CltuTransferDataDiagnosticsEnum.OUT_OF_SEQUENCE);
        }

The field this.cltuIdentification is set by the START invocation, and incremented every time a good CLTU is received. So there is no need to check the sequence in your code.

I hope that the above will help you to progress. If you have further doubts or questions, let me know.

Cheers, Dario