Is there a good way to pipe two serial devices?

Discussions and support about ChibiOS/RT, the free embedded RTOS.
carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Is there a good way to pipe two serial devices?

Postby carldong » Fri Mar 03, 2017 7:26 pm

Now I am throwing away my dumb solution, and I am trying to implement a event solution. However, I run into a strange problem:

Code: Select all

#define debugU(...) chprintf((BaseSequentialStream*)&SDU1, __VA_ARGS__)

..snip..

  uint32_t evt;
  const eventmask_t RX_USB = EVENT_MASK(1);
  const eventmask_t RX_SD1 = EVENT_MASK(2);
  chprintf(chp, "[Serial Console] BAUD set to %d\r\n", baud);
  sd1cfg.speed = baud;
  sdStart(&SD1, &sd1cfg);

  chEvtRegisterMaskWithFlags((event_source_t *)chnGetEventSource(&SDU1),
    &elRxTx, RX_USB, CHN_INPUT_AVAILABLE);
  chEvtRegisterMaskWithFlags((event_source_t *)chnGetEventSource(&SD1), // <-- This Line
    &elRxTx, RX_SD1, CHN_INPUT_AVAILABLE);
  while (1) {
    debugU(","); // <-- Debug outputs
    evt = chEvtWaitAny(RX_USB | RX_SD1);
    debugU("."); // <-- Debug outputs
    chEvtGetAndClearFlags(&elRxTx);
    if (evt == RX_USB) {
        from = chpu;
        to = chp1;
    }
    else if (evt == RX_SD1) {
      from = chp1;
      to = chpu;
    }
    else {
      cbuf = Q_RESET;
    }

    while (cbuf != Q_TIMEOUT && cbuf != Q_RESET) {
      cbuf = chnGetTimeout(from, TIME_IMMEDIATE);
      chnPutTimeout(to, cbuf, TIME_IMMEDIATE);
    }
    cbuf = 0;
  }



The line marked with comment is somewhat problematic. If I comment out that line, I can receive events when typing in serial console. No problem -- the debug shows "," and ".". However, if I put in that line(i.e. listening to both serial devices), the program seems to block at event waiting -- only "," is displayed, no matter what I type in the console. I tried chEvtRegister, but it is the same.

The block of code is snipped from a shell function.

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: Is there a good way to pipe two serial devices?

Postby Giovanni » Fri Mar 03, 2017 8:06 pm

Hi,

You need two listeners, that object is a link 1 to 1. It links one source to one thread.

Giovanni

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Is there a good way to pipe two serial devices?

Postby carldong » Fri Mar 03, 2017 9:35 pm

OK, so that seems to be some misunderstanding on my part. Then what are event masks used for? You mentioned that <something> can register up to 32 sources, but why then I need more than one listener? Is that <something> not listener objects, but the thread which the objects are in? Or does that mean 32 events system wise?

skute
Posts: 64
Joined: Wed Aug 29, 2012 10:17 pm

Re: Is there a good way to pipe two serial devices?

Postby skute » Fri Mar 03, 2017 11:36 pm

Each thread can listen for up to 32 events or you can register up to 32 event listeners for a particular thread. An unique event listener is required for each event source to which you are registering.

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Is there a good way to pipe two serial devices?

Postby carldong » Sat Mar 04, 2017 4:01 am

I have switched to two listeners. However, the program still blocks at the same place, so I am not quite sure what is the reason.

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Is there a good way to pipe two serial devices?

Postby carldong » Sat Mar 04, 2017 6:03 am

carldong wrote:I have switched to two listeners. However, the program still blocks at the same place, so I am not quite sure what is the reason.


Ahh, how nice. It looks like ST-Link Utility either blocks the write to ch.bin, or it caches the old file. I cleaned everything, restarted ST-Link Util, and it worked... Up to the point of receiving events. I didn't get it to actually pipe anything, yet.

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Is there a good way to pipe two serial devices?

Postby carldong » Sat Mar 04, 2017 6:37 am

Progress, but still some strange things:

Code: Select all

  chEvtRegisterMaskWithFlags((event_source_t *)chnGetEventSource(&SDU1),
                             &elU2S, RX_USB, CHN_INPUT_AVAILABLE);
  chEvtRegisterMaskWithFlags((event_source_t *)chnGetEventSource(&SD1),
                             &elS2U, RX_SD1, CHN_INPUT_AVAILABLE);

  while (1) {
    evt = chEvtWaitAny(RX_USB | RX_SD1);
    if (evt & RX_USB) {
      chEvtGetAndClearFlags(&elU2S);
      from = chpu;
      to = chp1;
    }
    else if (evt & RX_SD1) {
      chEvtGetAndClearFlags(&elS2U);
      from = chp1;
      to = chpu;
    }

    do {
      cbuf = chnGetTimeout(from, TIME_IMMEDIATE);
      chnPutTimeout(to, cbuf, TIME_IMMEDIATE);
    } while (cbuf != Q_TIMEOUT && cbuf != Q_RESET);
  }
 


Here, events are received normally. Also, apparently I do get correct character from cbuf. However, when using a loopback wire on SD1(The serial port I used), nothing is transmitted back. Using debug statements printung cbuf, I found that somehow on SD1, some sort of "space" is received, but not the correct character. I don't know what is its cause. I think the hardware serial USART1 should be full duplex, so receiving via a loopback should not pose a problem, but it seems to be faulty...

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Is there a good way to pipe two serial devices?

Postby carldong » Mon Mar 06, 2017 12:11 am

I cannot seem to solve the problem. Even with my 'dumb" pipebyte solution which simply polls the queues and sends them, I can't get information back from the loop. Somehow if I just connect Rx and Tx, the transmitted data does not appear in the input queue. In my knowledge, STM32 should have full-duplex serial ports, so I don't know what's wrong about my code.

Just so you know, this is pipeByte:

Code: Select all

static uint8_t pipeByte(BaseChannel *chp1, BaseChannel *chp2) {
  int8_t b;
  b = chnGetTimeout(chp1, TIME_IMMEDIATE);
  if (b != Q_RESET && b != Q_TIMEOUT) {
    debugU("Received %c\r\n",b); // <-- this line does not affect the behavior. Loopback also doesn't work without it.
    chnPutTimeout(chp2, b, TIME_INFINITE);
  }
  /* ETX.*/
  if (b == 0x03) {
    return 1;
  }
  return 0;
}

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: Is there a good way to pipe two serial devices?

Postby Giovanni » Mon Mar 06, 2017 8:27 am

Hi,

That snippet of code does not tell me much except that TIME_INFINITE would prevent you to empty the input queue.

I recommend that you first design your pipe under form of a state machine then you proceed with implementation. This method almost always work for me. Use events and timeouts as triggers for the SM state transitions.

Giovanni

User avatar
DeusExMachina
Posts: 223
Joined: Tue Apr 03, 2012 5:08 am
Location: South Korea
Has thanked: 3 times
Been thanked: 3 times

Re: Is there a good way to pipe two serial devices?

Postby DeusExMachina » Tue Mar 07, 2017 1:51 am

I have done this task pretty strait-forward, but it works fine for me (230 400 b/s)

Code: Select all

/*
 * UART->USB sender thread
 */
static THD_WORKING_AREA(waUART2USB, 256);
static __attribute__((noreturn)) THD_FUNCTION(uart2usb, arg)
{
  (void)arg;
  chRegSetThreadName("uart2usb");
  while (true)
  {
    char c;
    int bytes;
    /* serving USB events and data */
    bytes = chnReadTimeout(&SD1, (uint8_t *)&c, 1, MS2ST(10));
    if (bytes != 0)
    {
      streamPut(&SDU1, c);
    }
  }
}


/*
 * USB->UART sender thread
 */

static THD_WORKING_AREA(waUSB2UART, 256);
static __attribute__((noreturn)) THD_FUNCTION(usb2uart, arg)
{
  (void)arg;
  chRegSetThreadName("usb2uart");

  while (true)
  {
    char c;
    int bytes;
    /* serving USB events and data */
    bytes = chnRead((BaseSequentialStream * )&SDU1, (uint8_t *)&c, 1);
    if (bytes != 0)
    {
      streamPut(&SD1, c);
    }
  }
}



Return to “ChibiOS/RT”

Who is online

Users browsing this forum: No registered users and 38 guests