libcsp icon indicating copy to clipboard operation
libcsp copied to clipboard

Multi-Interface, Single-Device Configuration (CSP 1.x)

Open jeffstjean opened this issue 2 years ago • 9 comments

I'm looking at writing an application that can communicate with the same device over both CAN and UART. I've seen a few mentione (#342, #331) of CSP 2.x supporting sending a single message to multiple interfaces for the sake of redundancy.

We were hoping to implement something similar but the device we're using only supports CSP 1.x. The device in question is connected to the main processor via both CAN and UART. We were hoping to implement a fail-safe where the main processor could switch between the two interfaces in the event that the main interface fails.

Is there a standard / recommended way to accomplish this in CSP 1.x? I don't necessarily need both to be active at the same time (and I'm not sure if it even has de-duplication enabled), so would the best option to use csp_rtable_set() to switch as needed? I'm not sure if this would introduce a race condition or otherwise cause issues by modifying the routing table at run time (after calling csp_route_start_task().

jeffstjean avatar Aug 09 '23 22:08 jeffstjean

Honestly, I've never done that. And I don't know a standard way. I'm sure there are many developers and users who has much more experience than me, so hope them to jump in.

The following is not a standard way or a recommended way.

Just looking at v1 code base, routing table is not protected by any mutex or semaphore, there could be a race. https://github.com/libcsp/libcsp/blob/53d740adbdf6c269a33ab68c2f548b03590dad8f/src/rtable/csp_rtable_static.c#L49-L51

Locking aside, if you are working on FreeRTOS or other OS with a single process, make sure to note that there is only one address in the libcsp, and libcsp checks incoming packets against it.

Now I'm assuming that you have two connections between a v1.0 device and v2.x OBC (or anything you can program with). I also assume that you want some telemetry form your v1.0 device. I'm assuming your OBC is v2.x because it's hard to do this if you are using v1.0. Note that with "v1.0" I'm refering to the version of libcsp, not the packet format.

For your device to send, csp_route.c in v1.0 routes a packet to a found destination. So, make sure to have two addresses on your OBC so that in your your device's view, it's sending to two different endpoint. libcsp v2.x can handle receiving it.

For your device to receive, you have to send each packet with the same destination address via different interface. I don't think the stock router does this.

As you noted, if your device enabled dedup, you need to work around it.

yashi avatar Aug 10 '23 01:08 yashi

Thanks for the response!

Note that with "v1.0" I'm refering to the version of libcsp, not the packet format.

I was under the impression that v1.x of libcsp was v1.x of the packet format. Is there somewhere I can look to see the changes between different versions of libcsp and when/how the packet format was changed? In the develop branch, I can see that csp_packet_t has changed substantially but I wasn't sure if the packet format (serialized) was backwards compatible.

For your device to receive, you have to send each packet with the same destination address via different interface. I don't think the stock router does this.

That's what I had gathered as well. I saw some discussions about future developments (may be complete now but not included in v1.6) to support multiple addresses like this. Figured it wasn't possible with the router out-of-the-box.

jeffstjean avatar Aug 10 '23 16:08 jeffstjean

Just thinking aloud here, I could use a thread that my application manages to call csp_route_work() instead of letting csp manage it with csp_route_start_task(). When the application wants to switch interfaces, it just stops doing routing work to make the switch.

The application would have to reconfigure the device's routing table, restart it, and then switch over its own routing table. Since the whole idea is to add a redundant interface, and this solution requires using one interface to switch over to the secondary, it doesn't really work.

If I include your idea of treating the OBC as two separate locations with two CSP IDs, then the application would just need to switch its routing table and its local CSP ID. I'm not sure if this is possible as calling csp_init() more than once would cause a memory leak. I'm not opposed to freeing with csp_free_resources() and then re-init afterwards, would there be any issues with that? It's running on Linux so memory fragmentation is less of a concern.

jeffstjean avatar Aug 10 '23 17:08 jeffstjean

I was under the impression that v1.x of libcsp was v1.x of the packet format.

Yes, that's right.

libcsp v2.x, however, supports v1 and v2 packet format.

yashi avatar Aug 10 '23 23:08 yashi

Is there somewhere I can look to see the changes between different versions

https://en.wikipedia.org/wiki/Cubesat_Space_Protocol#Protocol_header

yashi avatar Aug 10 '23 23:08 yashi

If I include your idea of treating the OBC as two separate locations with two CSP IDs, then the application would just need to switch its routing table and its local CSP ID. I'm not sure if this is possible as calling csp_init() more than once

With libcsp v2, you can have a csp address per interface. Your application, which is running on linux and having two interfaces with a uniq address for each, can decide which interface you want to send from. Then, call csp_send_direct_iface()?

yashi avatar Aug 11 '23 09:08 yashi

With libcsp v2, you can have a csp address per interface.

I was unaware libcsp v2 could send v1 packets while still using all the features of v2. That sounds exactly what I'm looking for.

I've primarily been using the v1.4 and v1.6 tags in previous projects. Could you point me in the right direction for finding the latest stable release for v2? Is the libcsp-2-0 branch the latest tested for v2?

jeffstjean avatar Aug 11 '23 16:08 jeffstjean

We haven't tagged v2.0, #433. But the branch libcsp-2-0 will be v2.0.

yashi avatar Aug 11 '23 17:08 yashi

Hello.

You will need to run the latest develop release or 2.0 when that is finally released. When configured correctly this will duplicate packets to multiple interfaces if they are within the same network segment. Two interfaces can even have the same address on the same segment. For example:

can0: addr = 100, netmask 8 can1: addr = 100, netmask 8

All packets going to the segment 64/8 (64 to 127) would be transmitted on both interfaces.

You can set csp.version = 1, before calling csp_init(csp_conf_t * conf) this means the outgoing packets will be in csp 1.x compatiable header format.

Your older legacy product will then receive the packets on both incoming interfaces. But since its a litteral version 1.6 or 1.4 even, it will not support responding on both interfaces. So this will need to be updated to get the full benefit of redundant links.

We use this in practice on multiple satellites.

johandc avatar Sep 09 '23 10:09 johandc