WEBVTT

00:00.000 --> 00:11.760
Okay, I'm Martin Taichmann. I'm coming from the European

00:11.760 --> 00:18.720
expert. Yeah. We are running the world's largest x-ray laser. Why does it think

00:18.720 --> 00:25.800
go so fast? Yeah, I just use the other keys. So we are running the world's largest x-ray

00:25.800 --> 00:30.680
laser. So most of us is in tunnels. So it's three and a half kilometers long that's quite

00:30.680 --> 00:36.840
some big size. We are publicly refunded research facility in Hamburg, Germany. And as you all

00:36.840 --> 00:42.360
can kind of imagine in a large x-ray facility like that, we certainly need an electron

00:42.360 --> 00:52.040
bio-fingent polarization focus, EVPS. I've put up a picture of that. So it's actually

00:52.040 --> 00:56.440
down here. You can actually see it, but well, I just put a picture anyway. What you're seeing

00:56.440 --> 01:02.600
here is just some bunch of electronics. And that bunch of electronics controlling those

01:02.600 --> 01:10.920
motors, which you see up here, which is a motion. And this electronics is using the EVP either

01:10.920 --> 01:18.040
cut protocol, which is a very versatile bus system that they use throughout every area throughout

01:18.120 --> 01:23.720
the facility. We have a huge number of installations from that. It's effectively enough

01:24.360 --> 01:30.840
hardware-wise to just control everything we need. Unfortunately, the software is just awful

01:30.840 --> 01:37.320
and it's close source. So we try to replace that with the nice open source software.

01:38.520 --> 01:44.760
Okay. How does this protocol work? Well, in that protocol, you just have a just a normal computer

01:44.840 --> 01:50.360
that sends out either net packets, with two of those terminals, which you just saw on the picture

01:50.360 --> 01:56.040
before. And that easy change shows the packet to the first one, which is set to the second one,

01:56.040 --> 02:02.040
and so on. And the last one just sends it back to the computer. And so reading from the

02:02.040 --> 02:06.760
terminals, by the way, you do by those packets being modified on the fly by those terminals,

02:06.760 --> 02:13.240
and you're just other stuff coming back than you sent. And now you might immediately see the

02:13.320 --> 02:20.600
application for EVP F, because what I'm not doing is, well, EVP F is running in the

02:20.600 --> 02:26.360
in the lowest corner, and it's running pretty fast, and it has direct access to the network via

02:27.800 --> 02:33.720
XTP programs, with the program type XTP. And so what we are just doing, we just are just within

02:33.720 --> 02:38.280
this loop. So the packet we send out a packet, it goes through all the terminals, comes back, goes through

02:38.440 --> 02:45.720
our EVP F, and send out again, and so on just in a circle, there's a nice loop. And on a high

02:45.720 --> 02:50.600
level, all the flows, so this is the fast stuff, and all the slow stuff we can just do in the

02:50.600 --> 03:00.200
user space, from Python. So what I want to talk about this in this talk, just after this fast introduction.

03:01.320 --> 03:07.960
So I want to show how you can use EVP F cap to make XTP programs with some simple examples.

03:08.680 --> 03:15.000
XTP, as a reminder, is just the program type and EVP F for network transport. Then I show

03:15.000 --> 03:21.560
it actually works. Then it goes through some EVP features that are already supported. And as promised,

03:21.560 --> 03:27.800
it shows some cool motion stuff from as an application for EVP F. But we are all constraints

03:27.800 --> 03:36.600
from developing this software, well, we need to be highly dynamic. And so we only get the hardware

03:36.600 --> 03:42.120
set up at runtime. We read out the terminals, we read out what's going on, how they are set up

03:42.120 --> 03:48.680
at runtime. So you have no clue about how to send out data before we have actually seen it.

03:49.240 --> 03:56.680
Even the actual logic inside might be not clear at compile time, so we just, it's just discovered

03:56.680 --> 04:01.960
always at runtime. We also have, as I said, many installations of those, and we would like to be

04:02.040 --> 04:10.680
able to just run several installations on one computer. And so we wanted several IPBF programs programs

04:10.680 --> 04:16.520
to run in parallel. And those programs must be replaceable at runtime, because we want to be able

04:16.520 --> 04:21.800
to replace hardware at runtime and then just change the accordingly. So simplicity is another

04:21.800 --> 04:26.440
important thing. Most of the programs, most of our programming is done by scientists,

04:26.520 --> 04:32.760
and not by programmers, and those scientists. There are no Python. Python is huge in our community,

04:33.480 --> 04:38.440
but they might not be the best programmers out there, and that's not really their jobs.

04:38.440 --> 04:44.040
I should be simply enough that they can deal with it. Also flexibility, I did not want to write

04:44.040 --> 04:49.160
a thing which just solves my problem. I just wanted it to be usable for many other purposes.

04:49.800 --> 04:55.720
My ideas that EVP F can be used as a speed boost in Python programs, so they can just offload

04:56.680 --> 05:04.680
the inner loop of your Python program into the Linux channel. Okay, let's just jump directly

05:04.680 --> 05:14.680
in and give a full example. Here we have one. This is an entire code. Well, no. It doesn't

05:14.680 --> 05:20.520
like me here. This is an entire program. This is not just a code snippet. This is really the

05:20.520 --> 05:26.280
entirety of the program. You can just like that Python and it will do it. It's a very

05:26.280 --> 05:32.440
simple example of just accounts, the number of packages that are coming in. It looks like no,

05:32.440 --> 05:40.200
a Python code. You might not even notice anything special, but this is actually EVP F from.

05:40.200 --> 05:44.840
How do you see? So let me just go through it. The EVP F part is this part here.

05:45.800 --> 05:50.040
You only see from the fact that it inherits from XDP, so then XDP program.

05:51.160 --> 05:56.600
We like always the Linux kind of after for which license we use, we are at first them. So

05:56.600 --> 06:04.520
obviously that's GPL. We can declare a clear and airy map for a communication with user space

06:04.520 --> 06:12.040
and then also declare a variable that lives in that airy map. This here is now my EVP F program.

06:13.000 --> 06:17.080
Then comes the user space part. And what we do here, we just

06:18.520 --> 06:26.760
insensiate this class here. Say run. Then it gets attached to this network port. And while it

06:26.760 --> 06:34.840
while the EVP F is running in the kernel, we can just talk to it. And now the interesting parts of it.

06:35.080 --> 06:43.160
So this part here generates EVP F. And I will repeat that probably 10 times during this talk.

06:43.160 --> 06:49.000
This is not the code that is actually executed in the kernel, but this code is only executed

06:49.000 --> 06:53.880
once at the very beginning. And generates code that then is injected into the external,

06:53.880 --> 06:58.520
and runs then in the external, the result of that. That's the first thing.

06:59.640 --> 07:04.360
The second thing is you might notice that this variable here, and this variable there,

07:04.360 --> 07:09.800
is the same. And they look the same. It's the EVP F care that in the background

07:09.800 --> 07:15.560
to make them the same. And so you can access the same variables from EVP F and from user space

07:15.560 --> 07:27.800
without even feeling it. Yes. XDP doesn't really make sense if you want to see the packet.

07:27.800 --> 07:33.640
Do you want to see the data that is coming in? So for that as a first thing, we need to declare

07:33.720 --> 07:38.200
a minimum packet size so that the verify analysis, otherwise we just drop the packets or do

07:38.200 --> 07:44.680
something else. Does matter here. Then we can declare a packet variable, so a variable that

07:44.680 --> 07:51.560
lives in the space of the packet. And if you know either an protocol by heart, you know that

07:51.560 --> 07:57.800
a position 12, you have the either type. And the either type is actually unsigned to 16 bit

07:57.800 --> 08:05.560
in a network byte order. And we are following the Python's struct package convention,

08:05.560 --> 08:11.240
very just H, which is unsigned to 16 bit, and the summation mark means a network byte order,

08:11.240 --> 08:16.840
just Python programmers. They all know that don't they. And so you keep our user spaces

08:16.840 --> 08:21.880
stuff the same. We have our program. And now we can just filter for either type equals is 0,

08:22.760 --> 08:29.960
that is by the way IPv4. And as I said, already this code is executed only once,

08:30.680 --> 08:36.200
and you better execute all the code. So this is why we cannot have if statements. Because if

08:36.200 --> 08:40.760
you have an if statement, you do not execute all the execute all the code. So what you do we just

08:40.760 --> 08:48.440
abuse the Python with statement, which in the beginning looks a bit awkward. You get used to it.

08:48.440 --> 08:54.440
So now it's the next thing you might want to have more than more than one test for example

08:54.440 --> 08:59.440
we could check how many want to know how many FPV6 pay packets are passing through.

08:59.440 --> 09:01.440
How do you do that?

09:01.440 --> 09:02.440
That is how you do it.

09:02.440 --> 09:05.440
We just make another user space variable.

09:05.440 --> 09:09.440
And test is nice with condition as else.

09:09.440 --> 09:15.440
And with else, comma is nothing else than what you normally read as illiff.

09:15.440 --> 09:19.440
And yes, it looks a bit unused.

09:19.440 --> 09:26.440
It's strange, but it's not too far of a normal programming.

09:26.440 --> 09:28.440
So how does it actually work?

09:28.440 --> 09:33.440
Well, as you might have noticed, those declarations appear.

09:33.440 --> 09:35.440
They are Python descriptors.

09:35.440 --> 09:38.440
And in Python descriptors, you can have,

09:38.440 --> 09:40.440
don't get and don't set methods.

09:40.440 --> 09:44.440
And those don't get and set methods can do whatever you like.

09:44.440 --> 09:48.440
Usually, they set the value of your variables somehow.

09:48.440 --> 09:52.440
But you can also just make them generate ebps code.

09:52.440 --> 09:53.440
And so it happens.

09:53.440 --> 09:56.440
So it just sees there's just self that speed.

09:56.440 --> 09:57.440
Speed knows it's okay.

09:57.440 --> 09:59.440
It's a packet variable in the background.

09:59.440 --> 10:03.440
ebps can't have set up that the packet.

10:03.440 --> 10:05.440
Start with the packet point.

10:05.440 --> 10:07.440
I will be in register eight here.

10:07.440 --> 10:11.440
We know that in offset of 12, we just put the 12th in.

10:11.440 --> 10:16.440
At the same time, we have our area map, which if you path in the background,

10:16.440 --> 10:20.440
put it's a base pointer to register nine.

10:20.440 --> 10:26.440
Set up some, laid out some, the user space variables so that they are at position 16.

10:26.440 --> 10:28.440
You put that into registers.

10:28.440 --> 10:36.440
And then the rest statement will just generate a jump that jumps over that code.

10:36.440 --> 10:40.440
If the condition is not met.

10:40.440 --> 10:42.440
Okay.

10:42.440 --> 10:48.440
So the advantage of all of that is that I don't have any dependencies.

10:48.440 --> 10:50.440
So technically, it's written in Python.

10:50.440 --> 10:52.440
So yes, Python is a dependency.

10:52.440 --> 10:55.440
And yes, Linux is a dependency.

10:55.440 --> 10:59.440
No, I will not plot that to Windows just in case you're wondering.

10:59.440 --> 11:02.440
And yes, lib c is actually a dependency.

11:02.440 --> 11:06.440
So I think you will have a hard time running that in Alpine Linux.

11:06.440 --> 11:07.440
But okay.

11:07.440 --> 11:10.440
So it's just to pip install the ebps can't.

11:10.440 --> 11:11.440
And it's there.

11:11.440 --> 11:15.440
It doesn't even do not in dependencies because it has no dependencies.

11:15.440 --> 11:17.440
And I think that's very useful, especially for beginners.

11:17.440 --> 11:20.440
You can just start working.

11:20.440 --> 11:25.440
Some features that we already have.

11:25.440 --> 11:26.440
Why does that jump go?

11:26.440 --> 11:28.440
Is this a no?

11:28.440 --> 11:30.440
What I call permanent local programs.

11:30.440 --> 11:33.440
So what I showed you until now.

11:33.440 --> 11:38.440
Always the program was running while the Python program was running.

11:38.440 --> 11:40.440
So this is this example here.

11:40.440 --> 11:42.440
If you program, we insensiate it.

11:42.440 --> 11:43.440
You say program that run.

11:43.440 --> 11:45.440
It's within a viz block.

11:45.440 --> 11:49.440
And within the viz block, your ebps code is running.

11:49.440 --> 11:52.440
And you can do whatever a business logic you want.

11:52.440 --> 11:57.440
But you also want my might want to have that the program is running all the time.

11:57.440 --> 11:59.440
Even after your Python program has finished.

11:59.440 --> 12:01.440
Well, you can also do that.

12:01.440 --> 12:03.440
You just insens instantiate your Python program.

12:03.440 --> 12:06.440
Then you just attach this to the ebps port.

12:06.440 --> 12:12.440
And what you can then do is you can pin all the maps to the bps file system.

12:12.440 --> 12:15.440
Then you can just do whatever business logic you want to do.

12:15.440 --> 12:17.440
Your program finishes.

12:17.440 --> 12:19.440
The bbps continuous to run.

12:19.440 --> 12:22.440
It still filters all the packets and whatnot.

12:22.440 --> 12:26.440
And in a later time, you can just insert in a new,

12:26.440 --> 12:28.440
newly started Python program.

12:28.440 --> 12:32.440
It can just insensiate that thing again with this nice parameter load maps.

12:32.440 --> 12:34.440
It will just load all the bps maps back.

12:34.440 --> 12:40.440
So this means you can still access all the user space variables from again.

12:40.440 --> 12:43.440
And you do whatever business logic that you want to do.

12:43.440 --> 12:46.440
And in the end, you just detach it and you're done.

12:46.440 --> 12:47.440
OK.

12:47.440 --> 12:51.440
So I promise you to do a show you how to do motion control with the app,

12:51.440 --> 12:53.440
which is something really weird.

12:53.440 --> 12:56.440
So how would you do that first?

12:56.440 --> 12:59.440
The first thing is, what do you prepare to cut does for you?

12:59.440 --> 13:01.440
And you don't need to do that yourself.

13:01.440 --> 13:04.440
It reads all this app's self descriptions of the terminals,

13:04.440 --> 13:08.440
which are on your bus.

13:08.440 --> 13:13.440
And then you create an evened package that contains from that self description.

13:13.440 --> 13:18.440
It knows how the terminals want to be talked to.

13:18.440 --> 13:23.440
Then you generate an evened packet that contains all the interesting information

13:23.440 --> 13:24.440
that sure is in header.

13:24.440 --> 13:27.440
And then in the package, somewhere there's whatever in the encoder positions,

13:27.440 --> 13:31.440
like you're in readout, some motor speed that you want to move your motor build,

13:31.440 --> 13:36.440
some limits which are said, whatever you might be in your hardware that there is.

13:36.440 --> 13:38.440
Can be a lot actually.

13:38.440 --> 13:46.440
Then you have to program all the terminals so that they know how this packet is supposed to look like.

13:46.440 --> 13:52.440
And only then we can generate the EBPF program the same way as I have just shown in

13:52.440 --> 13:56.440
the last example.

13:56.440 --> 14:00.440
Then we just send one of those prepared packages on the network.

14:00.440 --> 14:03.440
It goes through all the terminals, comes back.

14:03.440 --> 14:09.440
Then we process by XDP, get sent out again and all over again in a big circle.

14:09.440 --> 14:12.440
And this is how you do your motion control.

14:12.440 --> 14:17.440
The while there's a slow code at the same time to communicate with the outside world,

14:17.440 --> 14:23.440
they'll just run as is in user space.

14:23.440 --> 14:33.440
One other feature that I need for that is to tell you that we want to be able to address different kinds of hardware at the same time.

14:33.440 --> 14:36.440
Also independently from each other.

14:36.440 --> 14:44.440
The way I do that is that I start some permanent program that has a Pint Prog area map.

14:44.440 --> 14:56.440
And then into the header, I just secretly sneak in some breadcrum, some number from which I know which part of the hardware this packet is supposed to talk to.

14:56.440 --> 15:02.440
And then what I just do is I call tail call into that program area.

15:02.440 --> 15:04.440
So I just know which number it is.

15:04.440 --> 15:08.440
Okay, and then I know which program area to tail call.

15:08.440 --> 15:16.440
And then any program that wants to actually communicate with one part of the hardware can just start.

15:16.440 --> 15:24.440
Well, instead it's even if program into that program area will be called for all the data that it needs.

15:24.440 --> 15:37.440
And once it's done, it just removes itself from the program area and everything continuous at continuous as before.

15:37.440 --> 15:40.440
So Python gives you the large advantage.

15:40.440 --> 15:52.440
This is that you can just go to a much higher level of much higher level of programming of understanding.

15:52.440 --> 16:06.440
And so what you can do in ebf is ebf cat in my library is that you can abstract out all those details about packets or whatever.

16:06.440 --> 16:16.440
And have this kind of programs where it's really focused on this control part of ebf cat.

16:16.440 --> 16:24.440
For example, you have in in a motor device you want to a motor usually has something like a velocity it usually has a position from an encoder.

16:24.440 --> 16:27.440
That is something that you communicate with the hardware.

16:27.440 --> 16:35.440
So and ebf cat sees not just one of those but has probably many of those for all the coaches that you have in your system.

16:35.440 --> 16:43.440
And it will just lay out the packet as it will and then just assigns the where it will be.

16:43.440 --> 16:49.440
Also then you're talking to talking to the user which I hear then call a device law.

16:49.440 --> 16:58.440
It will just then also just take all the motors the communication with the user lay out the map to communicate with user space.

16:58.440 --> 17:04.440
And so that in the ebf program.

17:04.440 --> 17:06.440
Doesn't see anything of that anymore.

17:06.440 --> 17:18.440
And it just for you it's just velocity and entire position if you ever did motion control you can see that this is just kind of the easiest way to do a position control of a motor.

17:18.440 --> 17:30.440
And the nice thing is that you don't you don't really see that this is actual you know ebf code that does a lot of things just going on in the background.

17:30.440 --> 17:42.440
You can do this very high level version of programming and I hope that then even my colleagues will be able to do that.

17:42.440 --> 17:45.440
Okay, I'm already at my summary.

17:45.440 --> 17:50.440
So with ebf cat you can generate ebf code from Python.

17:50.440 --> 18:02.440
It can be used generically to use ebf programs especially exp programs and as a special case it can be used for computer controls of either compatible hardware.

18:02.440 --> 18:15.440
Everything can't be found and get up the documentation here and for those who are super interested to hear are all my motion control things are in this additional really repositories.

18:15.440 --> 18:20.440
I'm thanking my colleagues and to you for your attention.

18:20.440 --> 18:28.440
But just before you get to come up with your questions I want to then show you the result on how it looks like.

18:28.440 --> 18:32.440
Okay, now I would need to know how to get to there it is.

18:33.440 --> 18:37.440
How is such a motion that looks like and.

18:37.440 --> 18:49.440
There is this is a ebbbf moving in sync as you see you two different motors three different motors actually to keep them all in sync.

18:49.440 --> 18:55.440
Questions.

18:56.440 --> 19:01.440
Thanks so very interesting talk so if I just and correctly you are generating.

19:01.440 --> 19:07.440
Bbf instructions directly out of the Python code right you're not using any like L of a more anything.

19:07.440 --> 19:08.440
Exactly.

19:08.440 --> 19:15.440
I can imagine must be a hard task so are there any limitations like I don't know you run out of registers.

19:15.440 --> 19:20.440
Can you store stuff on the stack or you know that must be like it's a hard task.

19:20.440 --> 19:24.440
Absolutely this is a hard task but absolutely I'm not done yet.

19:24.440 --> 19:30.440
I'm kind of always writing as I go and I thought actually that this would be a much bigger problem than it is.

19:30.440 --> 19:32.440
Weirdly so.

19:32.440 --> 19:34.440
I have so.

19:34.440 --> 19:38.440
The entirety of that code is less than 10,000 lines.

19:38.440 --> 19:46.440
So it's not a huge code and two thirds of that code by the way is that either could protocol which is not simple.

19:46.440 --> 19:50.440
So it is until now pretty simple and yes I know I until now it's right.

19:50.440 --> 20:00.440
I have not yet written a proper register allocator and do that very greatly and yes if you need too much register it will just crash until now.

20:00.440 --> 20:06.440
But interestingly I have have actually I've had to have written a rather complicated code.

20:06.440 --> 20:14.440
Already and until now I have not yet been into the limitation and will run into that I will figure out how to fix it.

20:14.440 --> 20:16.440
That's cool.

20:24.440 --> 20:26.440
I think we'll talk.

20:26.440 --> 20:40.440
I'm not that familiar with neither is a cart or BTF but I guess you do so the question is could it be used to implement hard real time communication with is a cart.

20:40.440 --> 20:42.440
Maybe.

20:42.440 --> 20:52.440
If so there is other people doing talks about using EPPF for controlling the scheduler for example.

20:52.440 --> 21:02.440
And there's even I've read somewhere somebody apparently is even working about working using EPPF for the scheduler of the packets going out of the hardware.

21:02.440 --> 21:08.440
And if I have that then then I can do hard real time.

21:08.440 --> 21:14.440
So please just work scheduler for packets outgoing packets please.

21:14.440 --> 21:18.440
Would be really nice for me then I can do a real hard time.

21:18.440 --> 21:22.440
Until now what I'm doing is just I'm just so fast with EPPF.

21:22.440 --> 21:30.440
Then just fast then everything that the normal real time people do is just to blast them just away.

21:30.440 --> 21:34.440
Okay thank you.

21:34.440 --> 21:38.440
Any other questions?

21:38.440 --> 21:52.440
So you mentioned not having any dependencies does it also mean that you do all of the BFF's schools manually instead of using that that's actually pretty challenging as well.

21:52.440 --> 21:56.440
I know I don't experience so.

21:56.440 --> 22:02.440
As I said it's in total less than 10,000 land of code it's the very fires alone is bigger.

22:02.440 --> 22:06.440
And Python is just very very short.

22:06.440 --> 22:08.440
Really impressive.

22:08.440 --> 22:10.440
Cool thing.

22:16.440 --> 22:18.440
Can you talk a bit more?

22:18.440 --> 22:26.440
You've been choosing XTP specifically because of the I guess low latency or are there also lots of packets that are going to.

22:26.440 --> 22:35.440
It's it's really the latency I actually even have I even have the problem that many hardware is optimized for high bandwidth which is usually not good for low latency.

22:35.440 --> 22:46.440
This is why I'm running XTP on a Raspberry Pi because Raspberry Pi's do not have the necessary buffers to do for high bandwidth.

22:46.440 --> 22:52.440
But this way have a pretty low latency.

22:52.440 --> 22:58.440
Did you also use this in combination with busy polling or something?

22:58.440 --> 23:00.440
The busy polling of what.

23:00.440 --> 23:04.440
So kind of what I'm kind of doing is constantly polling yes.

23:04.440 --> 23:12.440
So that the the the packets constantly flowing so usually usually at least 10 kilohertz the packets going in out in out constantly.

23:12.440 --> 23:16.440
So it sucks this cycle goes really the 10 kilohertz if not 20 kilohertz.

23:16.440 --> 23:20.440
That is effectively that's busy polling.

23:20.440 --> 23:24.440
I think that's the thing that's what it is.

23:24.440 --> 23:34.440
I don't think you've been running that in production and what what feedback you get from the other uses of the project like did they stumble on some.

23:34.440 --> 23:39.440
Maybe if stuff somehow like how is the experience.

23:39.440 --> 23:41.440
So I've been working on that since five years.

23:41.440 --> 23:45.440
It started very slowly but it's now taking speed.

23:45.440 --> 23:55.440
My colleagues at the when I switched over from the closed source stuff that used to before to this.

23:55.440 --> 24:01.440
They didn't even notice which I think is a it I think it's a good thing.

24:01.440 --> 24:07.440
So it was just working so I asked them did you notice any problems anything.

24:07.440 --> 24:09.440
They thought I'll find.

24:09.440 --> 24:17.440
I have presented it to scientific conferences to scientists and they were just they were really happy to.

24:17.440 --> 24:21.440
They're the only question that the the meanest question that I got.

24:21.440 --> 24:27.440
I didn't you're just right all of that in C++ and.

24:27.440 --> 24:33.440
So they also loved it so until now I got a lot of positive feedback.

24:33.440 --> 24:35.440
And it's just because it's just working.

24:35.440 --> 24:41.440
Have you heard from the lawyers from the company sitting the proprietary stuff yet.

24:41.440 --> 24:43.440
Until now no.

24:43.440 --> 24:51.440
So the company insists that they have a pattern and all of that but they are very fruit they say that if they only.

24:51.440 --> 24:55.440
They're only interested in the hardware side.

24:55.440 --> 24:59.440
So that's it's an open protocol so everybody can.

24:59.440 --> 25:05.440
Even make hardware like that but I'm softer and they always they say that for softer they have no issues because.

25:05.440 --> 25:09.440
They want to sell the hardware and that you send the sell the software makes software for it.

25:09.440 --> 25:11.440
They're officially state that.

25:11.440 --> 25:12.440
Go for it.

25:12.440 --> 25:13.440
Very good.

25:13.440 --> 25:14.440
Thank you.

25:14.440 --> 25:15.440
Any other question.

25:15.440 --> 25:16.440
Yeah.

25:16.440 --> 25:18.440
Last question.

25:18.440 --> 25:19.440
Yeah.

25:19.440 --> 25:20.440
Thank you.

25:20.440 --> 25:24.440
How is it now if you want to give that to other scientists.

25:24.440 --> 25:28.440
I assume you you probably will need some UI of some form like.

25:28.440 --> 25:32.440
So you have your device view and your health checks and all that stuff that.

25:32.440 --> 25:34.440
Twink and then the others do.

25:34.440 --> 25:36.440
So this certainly this.

25:36.440 --> 25:42.440
The second link on that page is the communication to the communication.

25:42.440 --> 25:46.440
Layer that bridges it to our in-house control system called carbo.

25:46.440 --> 25:52.440
Which then so it gives you all kinds of UIs and whatever you want to have.

25:52.440 --> 25:54.440
It's by the way all open source.

25:54.440 --> 25:55.440
Look at it.

25:55.440 --> 25:57.440
It's actually pretty nice.

25:57.440 --> 26:00.440
Maybe somebody wants to work on that.

26:00.440 --> 26:02.440
Just.

26:02.440 --> 26:03.440
All right.

26:03.440 --> 26:04.440
Thank you.

26:04.440 --> 26:05.440
Thank you.

