robertobucher / pysimCoder

Block diagram editor and real time code generator for Python
GNU General Public License v3.0
142 stars 31 forks source link

(feat) posix - allow TCP client to read data from server #47

Closed Chiff closed 2 years ago

Chiff commented 2 years ago

TCP protocol allows sending data back to the client which would be useful in @Chiff/pysimCoder-socketserver. This would extend TcpSockTx with optional settable outputs as in the image below (updated version of pysimCoder-socketserver/schemas/x13_rcregulator.dgm).

The main goal is that we will be able to control pysimCoder through any interface in real-time through the network.

image (can be found here pysimCoder-socketserver/schemas/x13_rcregulator_v2.dgm)

Implementation was tested and seems to be working just fine. However, in the schema above I need to feed TCP RX outputs back to the server, which produces an Algebraic Loop exception.

I thought of creating single blocks for TX/RX but there would be a need for some kind of mechanism to share file descriptors between (theoretically) multiple TX/RX blocks.

Do you guys have any take on how should I proceed?

Note: This requires updating .dgm, which will be done in PR for @robertobucher/pysimCoder-examples

robertobucher commented 2 years ago

Michal is right! It's better to initialize a thread to receive the data.

Roberto

On 5/7/22 21:05, Michal Lenc wrote:

@.**** commented on this pull request.


In CodeGen/Common/posix/TCPsocketTxRx.c https://github.com/robertobucher/pysimCoder/pull/47#discussion_r867384606:

 }
  • send(s, data, sizeof(data) , 0);
  • send(socketFd, dataSend, sizeof(dataSend) , 0);
  • / Receive data from the server /
  • if (block->nout > 0) {
  • double *y;
  • double dataRead[block->nout];
  • read(socketFd, dataRead, sizeof(dataRead));

I think we should have read() in a separate thread as it is in UDPsocketRX https://github.com/robertobucher/pysimCoder/blob/master/CodeGen/Common/posix/UDPsocketRx.c#L28. Otherwise the control application could stall when data send back by the server are delayed.

— Reply to this email directly, view it on GitHub https://github.com/robertobucher/pysimCoder/pull/47#pullrequestreview-965356498, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB7WD7X6TAZORERLKHV67NDVI25HVANCNFSM5VKYOC4Q. You are receiving this because you are subscribed to this thread.Web Bug from https://github.com/notifications/beacon/AB7WD7S5CP3EV4HON22G7U3VI25HVA5CNFSM5VKYOC42YY3PNVWWK3TUL52HS4DFWFIHK3DMKJSXC5LFON2FEZLWNFSXPKTDN5WW2ZLOORPWSZGOHGFCXUQ.gifMessage ID: @.***>

Chiff commented 2 years ago

I will move the read() function into a separate thread as suggested by Michal.

I have given some thought to the algebraic loop exception and it occurred to me to create a separate rx block. Both tx/rx blocks will have a new intPar named id defaulted to 0. The first initialized socket (rx or tx) will supply its file descriptor to a global array of TCP file descriptors to share file descriptors between one socket.

In that way, we can use tx/rx in separate blocks while having one connection to the TCP server. And also, it will support multiple connections.

What do you think about that?

Also, I won't be able to do this soon as I'm finishing my thesis right now.

robertobucher commented 2 years ago

Thanks Martin

Let me analyze your proposal. But, why you can't use the already provided TCP/IP Tx and Rx blocks?

Chiff commented 2 years ago

Hi Roberto, currently pysimCoder does not provide TCP Rx block (at least I was not able to find it in the library) and that's the reason why I created this PR. Is there something I missed?

ppisa commented 2 years ago

The idea of TCP Rx and Tx together in one block is reasonable, when both direction should go through same socket. It would be probably quite messy to connect two blocks to one descriptor (need to use some aliases allows locate and join blocks together) . So I agree with option to have one block for both directions. As for algebraic loop, if you mark block as without direct input to output propagation uy = 0, then it should not be a problem.

def genericBlk(pin, pout, nx, uy, rP, iP, strP, fname):

The separate receive thread is an question, if the mode has to be delivered with one sample for each input, ie pass signal through some external filter, then it should sen data and then receive reply, but in this case it has uy = 1 property and cannot be in algebraic loop. If the receive is asynchronous receive of the set-points and waits for all vector matching output count receive and then does atomic update, then receive should run in separate thread and uy = 0 should be set.

For TCP there is an another option when generated model is not client which connect to the another host but it binds to specified ports and runs server on the model side which listens for some other client connection.

So there are more valuable options for TCP case...

ppisa commented 2 years ago

May it be for setpoints etc. you can consider silicon-heaven way.

For data processing inserted inside actual control, loop synchronous TCP connection has value.

For slow models even this functionality can be resolved over silicon-heaven method invocation but latency and complexity would be high.

I have still interest in DDS (ROS2) compatible publication and subscriptions for processing variables.