machinekit-hal icon indicating copy to clipboard operation
machinekit-hal copied to clipboard

MachinekitFS based access to HAL Layer

Open cerna opened this issue 6 years ago • 3 comments

For some time now, I have been thinking about how to communicate with Machinekit_HAL instance from the context of local machine and from remote. One of the ways is to use the HAL remote and Machinetalk. Which is viable, but I have a feeling that it was never really finished (the NOTYET code is still present) and that the whole system was geared towards remote GUI operation, not towards one system consisting of multiple RTAPI_APP instances acting together (in non-realtime way) to form functioning unit. For example CNC mill in XYZ planes and ATC.

I would like to have something which would allow me to implement the Machinekit Machinetalk part for HAL layer as separate module (program not part of RTAPI_APP) in non-realtime way, but also to secure real-time capable communication between two components on one system (be it two or more RTAPI_APP instances, or Machinekit and arbitrary other real-time capable software) and also communicate with HAL layer from other programs written in programming languages other than Python. Because there are Python Cython bindings, which is great if you are using Python. But I am not using Python, I do not like Python, I would like to use C# dot NET Core. And for this I would have to implement the P/INVOKE wrappers around every HAL function. This is something I would rather not do. Because then somebody else, who does not like to use C#, but who does like Go, would have to do the same.

So I was thinking if it could be done in some glibc compatible way and I ended up with idea of MachinekitFS and character device based HAL layer and modules. (As the HAL is acting as a sort of driver abstraction and whatnot.) That way I could just connect to control character device for HAL Layer or character devices for HAL components and by way of read/write/IOCTL/other operations directly access the HAL in Linux like way. It would be best if the FUSE/CUSE libraries would be capable enough to support this part of HAL from userspace. But it could be possible to implement it also in the kernel space.

But what I am interested at this stage is if somebody before me though about it and if it is even possible? (There might be some problems I do not realize at the moment.)

The post about eventfd was inspirational (#82).

I think that it is also connected to the #161 in that the V2 accessor functions for this would be necessary.

cerna avatar Aug 07 '19 01:08 cerna

@cerna I have made a component some time ago that encodes pins in a sample protobuf message, and puts that message in a record of a ringbuffer. That ringbuffer you can read from a user program. In my example just python, but you can do that with C or C++ (or maybe another language if you know your way around) if you want. https://github.com/machinekit/machinekit-hal/tree/master/src/hal/sample_channel

In your situation the program reading the hal ringbuffer then has to pick the record from the ringbuffer and it's up to that program what to do with the information. You can send it via whatever communication layer (zmq for example, but you're free to use anything else) and decode the protobuf message on the receiving side. So if you're working with C# in a windows environment, there's probably a library for whatever communication library you use.

Realtime communications between 2 components on different threads can be done (i have not touched this though) via irings iirc. https://github.com/machinekit/machinekit-hal/tree/master/src/hal/iring-example this passes a message (no protobuf, but struct) between components on different threads via a ring.

luminize avatar Oct 04 '19 10:10 luminize

@luminize

I have made a component some time ago that encodes pins in a sample protobuf message, and puts that message in a record of a ringbuffer. That ringbuffer you can read from a user program. In my example just python, but you can do that with C or C++ (or maybe another language if you know your way around) if you want. https://github.com/machinekit/machinekit-hal/tree/master/src/hal/sample_channel.

I think that it is a little bit different use case than what I have in mind. The ringbuffer element is useful for messaging between components (HAL and otherwise) with higher level of information abstraction. I was thinking about direct access to HAL components by way of standard Linux kernel techniques. Something like the current Foreign Function Interface (FFI) for Python language, only more universal. I of course can create P/INVOKE wrappers around the C HALlib code, but that would mean that I will have to keep them updated the same way now Python interface functions have to be. However, if I were to implement HAL access as a file, then I can use what somebody else (Tmds.LibC) implemented.

The ringbuffer example also suffers from bottlenech of task loop processing. So ideally you would need whole CPU core isolated only for copying data from one process to another spinning all the time. And if I am not mistaken , given that the Python process still has to somehow access the ringbuffer, it uses the FFI and so the whole process has still access to whole HAL instance memory block, right? There is no permission separation which would allow access only to the one specific ringbuffer and nothing else?

So if you're working with C# in a windows environment, there's probably a library for whatever communication library you use.

Not exactly, you can use the C# in Linux with the .NET Core (version 3 was shipped recently, it is quite nice). The whole idea is not targeted at remote access. The non-realtime remote could be implemented as an abstraction layer on top of this (for example from separate user group with severely restricted access rights). It is targeted for simple IPC on the same machine without the need for each process to include the whole ZeroMQ library when open/write/close would suffice. (By closely following the electrical world, the HAL datatype prototypes are in itself trivial.)

For example, now to start the work threads, you have to use halcmd, which is another process. Wouldn't it be simpler to just programmatically write TRUE to /machinekit/0/status/running? That could be implemented by FUSE easily.

Realtime communications between 2 components on different threads can be done (i have not touched this though) via irings iirc.

I actually meant the communication between two programs, Machinekit and some arbitrary other, which both use the backend RTOS (Preempt_RT/Xenomai/whatever), but otherwise have nothing in common (in programming terms).

Thank you for comment.

cerna avatar Oct 23 '19 23:10 cerna

@cerna

The entire ringbuffer idea was exactly about having communication between realtime and non-realtime. So components are not exclusive here. iirc there's a zero copy mechanism, and the ringbuffer is thread safe. The fact that the example python script polls the ringbuffer continuously is just my way of implementing such a thing. Because the hal component is streaming samples, if the buffer is full, the samples will be dropped. Choice of implementation.

I'm afraid I can't answer your other questions. I'm not into the code deep enough for that. Sorry.

Here's another example where data is read from a ringbuffer by a component (realtime, inside). It's put there by a python script (non realtime, outside). https://github.com/machinekit/machinekit-hal/blob/376af880f2bd8e2d51f7d0519d5bd2678ec90631/src/hal/interpolator/interpolate.c#L118 https://github.com/machinekit/machinekit-hal/blob/376af880f2bd8e2d51f7d0519d5bd2678ec90631/src/hal/interpolator/feed-interpolator.py

The iring ringbuffer example shows the sharing information between components on separate realtime threads. https://github.com/machinekit/machinekit-hal/tree/376af880f2bd8e2d51f7d0519d5bd2678ec90631/src/hal/iring-example

luminize avatar Oct 24 '19 06:10 luminize