Event loop with serial and MUI events on Arexx
  • Order of the Butterfly
    Order of the Butterfly
    asrael22
    Posts: 404 from 2014/6/11
    From: Germany
    Hi.

    I'm developing a small tool using Arexx on MorphOS.
    It has a MUI GUI using RxMUI and it should receive and send data using the serial device using RxSerial.
    The GUI works as well as the serial communication.
    However there are some strange hangs where i.e. the GUI only reacts when something is sent via serial.
    Or that only something can be received by serial when something is sent.

    The event loop doesn't use the RxMUI NewHandle() but the Handle() method and checks on signals using Wait() function whcih look like this:
    Code:
    Wait(or(serial.Signal, h.Signals, ctrl_c)

    Where h.Signals are MUI signals.
    But yeah, this doesn't seem to work reliable. The send and receive serial code pretty much is the same as in the RxSerial examples.

    What is going wrong here. How can I troubleshoot this further on where the hanging occurs?


    Manfred
  • »03.01.17 - 15:41
    Profile
  • Order of the Butterfly
    Order of the Butterfly
    asrael22
    Posts: 404 from 2014/6/11
    From: Germany
    Is there maybe C example code that does this? MUI plus serial?


    Manfred
  • »05.01.17 - 12:24
    Profile
  • MorphOS Developer
    jacadcaps
    Posts: 2972 from 2003/3/5
    From: Canada
    Quote:

    asrael22 wrote:
    Is there maybe C example code that does this? MUI plus serial?
    Manfred


    I will look something up. Still, if you want any help, a slightly longer snippet of the code is necessary. It seems unlikely the problem is in the Wait() call.
  • »05.01.17 - 13:51
    Profile Visit Website
  • Order of the Butterfly
    Order of the Butterfly
    asrael22
    Posts: 404 from 2014/6/11
    From: Germany
    Right. So here is the event loop:
    Code:

    appMainLoop: procedure expose serial. eta.
    ctrl_c = 2**12
    waitSignal = serial.Signal

    logDebug("Forever loop")
    do forever

    call Handle("app", "h", waitSignal)
    do i = 0 to h.Num-1
    logDebug("Signal: " h.i)
    if h.i = "QUIT" then call halt()
    if h.i = "INIT_SERIAL" then call serialInit()
    if h.i = "CLOSE_SERIAL" then call serialClose()
    if h.i = "SEND_SERIAL_HELLO" then do
    call logDebug('Sending "Hello World"')
    call logGUI('Sending "Hello World"')
    serialWrite("Hello World")
    end
    /* etc */
    end

    waitSignal = Wait(or(serial.Signal, h.Signals, ctrl_c))

    if and(waitSignal, ctrl_c) ~= 0 then do
    logDebug("Handling CTRL-C")
    call halt()
    end

    if and(waitSignal, serial.Signal) > 0 then do
    logDebug("Handling serial...")
    r = serialRead()
    if r ~= '' then do
    logDebug('Received (hex): 'string2HexString(r))
    call processEtaPackage(r)
    end
    end
    end

    return

    Where processEtaPackage(r) just processes/parses the data read from serialRead(). No further reading from serial there.

    Here the code in serialRead(). Pretty much the same as in the RxSerial example:
    Code:

    serialRead: procedure expose serial.
    if serial.Id = 0 then do
    msg = "ERROR: Serial not initialized!"
    logDebug(msg)
    return
    end

    /* isn't it the first time we are here ... */
    if serial.Post then do

    /* ... there is something on the air */
    call SERWaitIO(serial.Id, "b1")

    /* let's see if something else is available */
    call SERQuery(serial.Id, "q")
    if q.BreakReceived then exit
    if q.Actual > 0 then do
    call SERRead(serial.Id, q.Actual)
    call SERWaitIO(serial.Id, "b2")
    end
    else b2 = ""

    /* restart a read request */
    call SERRead(serial.Id, 1)

    return b1 || b2
    end
    else do
    serial.Post=1
    call SERRead(serial.Id, 1)
    return ""
    end


    And, for completness serialWrite():
    Code:

    serialWrite: procedure expose serial.
    parse arg data

    if serial.Id = 0 then do
    msg = "ERROR: Serial not initialized!"
    logDebug(msg)
    return
    end

    res = SERWrite(serial.Id, data)

    if res > 0 then say "Error on send"; return 1
    else return 0


    The Wait() call doesn't seem to block. This "do forever" loop really loops all the time where on each iteration the signals are checked.
    So I don't really know where the hangs are coming from.
    Interesstingly, when upon a MUI button click something is sent via serial the serial.Signal is raised so that on the next iteration the serial handler is called.
    So I'm a little bit lost where those hangs are coming from that either a MUI button does nothing or nothing is received or sent by serial.

    Manfred
  • »05.01.17 - 18:14
    Profile
  • MorphOS Developer
    jacadcaps
    Posts: 2972 from 2003/3/5
    From: Canada
    Try removing

    Code:

    /* ... there is something on the air */
    call SERWaitIO(serial.Id, "b1")


    from serialRead and see if this helps. I don't know exact specifics, but it looks as though you're trying to wait for IO that hasn't started yet.
  • »05.01.17 - 18:30
    Profile Visit Website
  • Order of the Butterfly
    Order of the Butterfly
    asrael22
    Posts: 404 from 2014/6/11
    From: Germany
    Quote:

    jacadcaps wrote:
    Try removing

    Code:

    /* ... there is something on the air */
    call SERWaitIO(serial.Id, "b1")


    from serialRead and see if this helps. I don't know exact specifics, but it looks as though you're trying to wait for IO that hasn't started yet.


    That helps in so far that it doesn't hang anymore. Button clicks work receive and send also.
    The problem is now that one byte of the receive seems to be discarded.
    Probably the one from:
    Code:

    serial.Post=1
    call SERRead(serial.Id, 1)
    return ""

    Where the SERWaitIO was waiting for.
  • »05.01.17 - 18:54
    Profile
  • MorphOS Developer
    jacadcaps
    Posts: 2972 from 2003/3/5
    From: Canada
    OK, sorry, I've dl'ed the rxSerial docs and it's clear you need to call SERWait there. Another thing you could do is to add echo's before each SERWait, SERWrite, SERQuery to try to determine where it stalls.
  • »05.01.17 - 19:44
    Profile Visit Website
  • Order of the Butterfly
    Order of the Butterfly
    asrael22
    Posts: 404 from 2014/6/11
    From: Germany
    Yep, thanks. I did that.
    It's weird.
    When I run this against a terminal program on the other side where I type one character after another it works perfectly.
    No stalling.
    However, when I send a bunch of characters at once it hangs.
    The difference is that with the bunch of characters the number of available characters is read from the serial.
    Which is this code:
    Code:

    if q.Actual > 0 then do
    call SERRead(serial.Id, q.Actual)
    call SERWaitIO(serial.Id, "b2")
    end

    And it seems that for some reason a serial signal is raised after reading everything available so that the serial handler runs into the SERWaitIO() call in the next event loop iteration even though there is nothing anymore available on the serial.
    This signal doesn't seem to be raised when character by character is sent from the terminal.

    I've tried checking the available bytes in the serial buffer before the SERWaitIO() to avoid hanging there.
    Code:

    if serial.Post then do
    /* ... there is something on the air */
    SERQuery(serial.Id, "q")
    if q.Actual > 0 then do
    call SERWaitIO(serial.Id, "b1")
    ...
    end

    But then sending one character only doesn't work anymore. It seems to get swallowed because q.Actual is 0.

    The question now is why is the serial signal raised (again) after receiving >1 character.


    [ Edited by asrael22 06.01.2017 - 16:19 ]
  • »06.01.17 - 16:17
    Profile
  • Order of the Butterfly
    Order of the Butterfly
    asrael22
    Posts: 404 from 2014/6/11
    From: Germany
    Ok, I don't know where the problem is there.
    I've implemented this now in C where it works fine and I think I'll continue there and convert what have to C.

    It was a nice excourse into Arexx though.
  • »07.01.17 - 16:14
    Profile