Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

TCP Socket and Serial Port

by FlyingEagle (Initiate)
on Jan 09, 2012 at 12:57 UTC ( #946999=perlquestion: print w/ replies, xml ) Need Help??
FlyingEagle has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

i've a problem run this script.

What should it do:
Run under Linux and v5.10.0 built for arm-linux-gnueabi-thread-multi. I'll like to make a TCP-socket-server to which some clients could connect. If connected the client send a string which is directly sended to serial port and a connected AVR. The AVR sends an answer which is sended back to the clients. later on i'll build this up to save data in a database and much more.

Where are my problems:
I start the server, the socket is open, clients connect(ed). ok. but if a client closes its connection, the server script wend mad, i got an Error #9 on Serialport with Ressource unavailable at this time. but i could not recognize a connection between closing client an unavailable serialport.

second if i do $serialin = $serialport->lookfor() or $errorwithserial = 1; instead of $serialin = $serialport->lookfor();, i got the error #9 directly after starting the script and send the first serial_writes.

did i mad mistakes in threading or serialport?

Regards Fly


#!/usr/bin/perl use warnings; use strict; use IO::Socket; use threads; use threads::shared; use Device::SerialPort; sub serial_open(); sub serial_get(); sub serial_write($); sub process_clients(); system("/usr/bin/clear"); $|++; print "$$ Server started\n";; our @clients : shared; @clients = (); my $serialdevice = "/dev/ttyUSB0"; my $server = new IO::Socket::INET ( Timeout => 7200, Proto => "tcp", LocalPort => 8000, Reuse => 1, Listen => 3 ); my $num_of_client = -1; my $serialport = ""; my $serialin : shared = ""; my $count = 0; our $errorwithserial : shared = 0; serial_open; my $serialthread = threads->new( \&serial_get )->detach(); serial_write("#.lcdinit.#"); serial_write("#.v.#"); while (1 && $serialport ne "" && $errorwithserial == 0) { my $client; do { $client = $server->accept; } until ( defined($client) ); my $peerhost = $client->peerhost(); print "Connected: $client, $peerhost, Nummer = ", ++$num_of_client +, "\n"; my $fileno = fileno $client; push (@clients, $fileno); my $thr = threads->new( \&process_clients, $client, $fileno, $peer +host )->detach(); } # end of main thread sub serial_get() { while (1 && $errorwithserial == 0) { my $gotData = 1; $serialin = $serialport->lookfor(); # $serialin = $serialport->lookfor() or $errorwithserial = 1; if ($gotData == 1 && $errorwithserial == 0) { if ($serialin) { $serialin =~ s/^\s+$//m; $serialin =~ s/^\r+$//m; $serialin =~ s/^\n+$//m; $serialin =~ s/\s+$//m; $serialin =~ s/\r+$//m; $serialin =~ s/\n+$//m; print "UART in.: " . $serialin . " \n\r"; foreach my $fn (@clients) { my $fh; open $fh, ">&=$fn\r" or warn $! and die("tod"); } } } elsif ($errorwithserial == 1) { print "Error Serialport: " . $serialport . " -> " . $! . " +\n\r"; exit; } sleep 1; } } sub serial_write($) { my $cmd = $_[0]; $cmd =~ s/\s+$//m; $cmd =~ s/\r+$//m; $cmd =~ s/\n+$//m; if ($serialport) { if (substr($cmd, 0, 2) eq "#." && substr($cmd, length($cmd) - +2, 2) eq ".#") { $cmd = substr($cmd, 2, length($cmd) - 4); my $count_out = "0"; $serialport->write("$cmd\r"); print "UART out: $cmd\n\r"; } else { print "Unknown -> " . $cmd . " -> " . substr($cmd, 0, 2) . + " & " . substr($cmd, length($cmd) - 2, 2) . "\n\r"; } } } sub process_clients() { my ($lclient, $lfileno, $lpeer) = @_; if ($lclient->connected) { print $lclient "$lpeer -> Welcome -> " . localtime . "\n\r"; +# is sendet to client serial_write("#.v.#\r"); while(<$lclient> && $errorwithserial == 0) { my $command = $_; print $lclient "$command\r"; serial_write ($_); } print $lclient "$lpeer -> Welcome\n\r"; # it will never be se +nded! if ($errorwithserial == 0) { print $lclient "$lpeer -> Good Bye\n\r"; # it will never +be sended! } else { print $lclient "$lpeer -> Good Bye with Error -> " . $! . +"\n\r"; # it will never be sended! } } close ($lclient); @clients = grep {$_ !~ $lfileno} @clients; } sub serial_open() { $serialport = Device::SerialPort->new($serialdevice) or die "(new) +!"; $serialport->databits(8) or die "(databits)!"; $serialport->baudrate(115200) or die "(baudrate)!"; $serialport->parity("none") or die "(parity)!"; $serialport->stopbits(1) or die "(stopbits)!"; $serialport->read_char_time(5) or die "(read_char_time)!"; $serialport->read_const_time(500) or die "(read_const_time)!"; print "($serialport) $serialdevice open\n\r"; } __END__

Comment on TCP Socket and Serial Port
Download Code
Replies are listed 'Best First'.
Re: TCP Socket and Serial Port
by zwon (Monsignor) on Jan 09, 2012 at 15:11 UTC

    Your description of the problem is not especially clear for me, but I see that you're accessing single serial port from multiple threads without any synchronization, so I'm not surprised you have a problem. Only one client may write into serial port at a time, so I'd recommend you rewrite this script without threads, it would be much less code to debug then. Also, if you would add error checks after IO operations, it could help to find the problem too. E.g. instead of:

    print $lclient "$lpeer -> Welcome\n\r"; # it will never be sended!
    you can write
    print $lclient "$lpeer -> Welcome\n\r" or die "Send failed because: $! +";
      ok, but this is not my biggest problem at this time. my problem is the error by using lookfor ... did u mean with "synchronizing" that i've to use 2 booleans to lock each write and lookfor? regards
Re: TCP Socket and Serial Port
by BrowserUk (Pope) on Jan 10, 2012 at 00:56 UTC

    Your code is fundamentally flawed.

    It is flawed in many ways -- for example: what do you think you are achieving by having 1 && in your while loops?:

    while( 1 && $serialport ne "" && $errorwithserial == 0 ) { ... while( 1 && $errorwithserial == 0 ) {
    .

    -- but the fundamental error is the concept of having multiple, concurrent clients holding two-way conversations with a single serial port. That simply cannot work.

    It is possible to envisage having a thread that polls all possible information from the serial port connected device and caching that information in shared memory. And then having multiple, concurrent clients connect and query (subsets of) that information from the shared cache.

    Whether that makes sense really depends upon:

      the volume of information

      ie. number of possible commands or distinct queries?

    1. the 'shelf-life' of that information.

      Does the queried information change hourly? Or every microsecond?

    2. the volume of traffic.

      ie. the number and frequency of the client connects and the number of commands per connection.

    A little more information regarding the overall aims of the program -- eg. what is an "AVR"? I looked it up and two possibilities stood out: 1) Audio/video receiver; 2) AVR reactor, a German prototype pebble bed reactor.

    With the former, I cannot see the point of multiple clients connection to my HiFi.

    With the latter, I terrifies me that any one would allow multiple connections to a "reactor". Even if it is not of the nuclear variety.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      None of the two options. He is trying to send commands to an AR Drone. AVR is part of the hardware. BTW, you should note that the AR Drone software has already opened the serial port. So It is also adviseable to kill the drone control software before trying to run this script.
      Everytime you omit 'use strict;' a $kitetn becomes undef.
        He is trying to send commands to an AR Drone. AVR is part of the hardware.

        Hm. Couldn't he have told us that?

        That probably just makes my point. What is going to happen if you have multiple pilots trying to concurrently control a UAV?

        If this is related to Occupy Wall Street protestor Tim Pool has configured one that he calls an occucopter, for citizen-surveillance of police. "We are trying to get a stable live feed so you can have 50 people controlling it in series. If the cops see you controlling it from a computer they can shut you down, but then control could automatically switch to someone else." , the the keywords in there are "in series" which are completely missing from the OP.

        In that case, you'd want a queue of in-bound clients ready to take over when the current client 'drops off'. Emminently doable, but not the way the OP is approaching the problem.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

      None of it, it's an Atmel Risc Microcontroller (ÁC). It's connected via UART and i'll send data to it and the ÁC answers. I couldn't tell u anything about the traffic it depends on the count of TCP-clients and the count of commands they send to the ÁC. In some situations the ÁC send a lot of data in a short time and in others some little packets in 1 hour.

        The problem remains: if you have two clients that each send a command to the uC in quick succession, how do you know which client to send what output to?

        If you can answer that question, then what you are trying to do may be possible.

        If not, the best you could do is serialise the communications. Ie. a) Accept one client connection; b) read its command; c) send it to the uC; d) retrieve the results; e) send them back to the client; f) disconnect that client; loop back to a.

        More fundamentally, will the uC even look for a second command before it has returned all the output from the first command? If not, there is no point trying and no point in using threads.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

Re: TCP Socket and Serial Port
by Xiong (Hermit) on Jan 09, 2012 at 23:08 UTC

    Please, in future, enclose lengthy parts of your post within <readmore> tags. Here's a demo:

    I'm not the guy you kill, I'm the guy you buy. —Michael Clayton
      ok. thx.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://946999]
Approved by Corion
Front-paged by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (8)
As of 2016-05-28 12:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?