Problem implementing Pycyphal server with Serial

My application is including a board that talks with a host linux computer using Cyphal Serial.

Everything seems to work properly (Including publishers/subscribers/clients) but the servers do not seem to work.
Right now I am trying to develop firmware updates over Cyphal.

I am sending ExecCommand to the board with COMMAND_BEGIN_SOFTWARE_UPDATE, the board responds and then tries to use ReadFile to start reading the update file from the host but the ReadFile server never triggers.

Up to now I have tried in my Cyphal Class:
To set up a callback

self._node.get_server(uavcan.file.Read_1).serve_in_background(self._serve_file_read) 

@staticmethod
async def _serve_file_read(
    request: uavcan.file.Read_1.Request,
    metadata: pycyphal.presentation.ServiceRequestMetadata,
) -> uavcan.file.Read_1.Response:
    logging.info(" <-- Execute file read request %s from node %d", request, metadata.client_node_id)
    if request.command == uavcan.file.Read_1.Request:
        try:
            path = request.patha
            offset = request.offset
            data = Path(path).read_bytes()
            logging.info("Reading file: ")
            logging.info(data)
        except Exception as e:  # Do nothing if already removed.
            logging.error(e)
            pass
        return uavcan.file.Read_1.Response()
    return uavcan.file.Read_1.Response()

To setup a file server

roots = [Path(), Path() ...]
self.fs = FileServer(self._node, roots) 

I also tried yakut -v file-server --update-software NODE_ID which hangs after the following log while the boards keeps sending ReadFile requests.

 INF yakut.cmd.file_server: Node NODE_ID confirmed software update command uavcan.node.ExecuteCommand.Request.1.1(command=65533, parameter='PATH')

Do I need to set up any environmental variable for ReadFile? I guessed not since its a fixed port.

Is there any documentation for servers except the standard pycyphal demo ? (opencyphal-tutorial/docs/1-pc-demo/pycyphal.md at main · maksimdrachov/opencyphal-tutorial · GitHub)

Any help is appreciated :slight_smile:

The most comprehensive demo is here:

https://pycyphal.readthedocs.io/en/stable/pages/demo.html

Your code looks correct (except for the condition if request.command == uavcan.file.Read_1.Request: – it doesn’t make sense but it’s not related to your issues).

You need to enable verbose logging in PyCyphal (e.g., via the PYCYPHAL_LOGLEVEL environment variable) to see what is happening at the time of request arrival. There will be a lot of output, so you will need to sift through that carefully (LLMs are usually helpful with that).

I also recommend dumping all serial port exchanges into a file, and then feeding that file into an analyzer tool like this: Postmortem dump analyzer tool. It does not support Cyphal Serial out of the box though, but the support is easy to add using CandumpCaptureLoader as a reference – there is a todo comment about that on line 267. Let me know if you need practical help with that.

The point of using the analyzer tool is to see whether the request actually makes it to the server.

Hello Pavel, thanks for your response and your help.

I did not go into the postmortem tool, it was easier to inspect the packets raw.
Found the error which on my case was the PORT id.

I did not know that when calling a service I need to manually add 16384 to the PORT id but when i reply to a service I don’t.

Not sure if this documented somewhere but I was under the impression that is was the same for request/reply.
Maybe you could add a comment about this in the serial header example of the cyphal specification to make it clear.

Best Regards

Ah right its there, my bad thanks!