Page 2 of 2
Re: Is there a good way to pipe two serial devices?
Posted: Fri Mar 03, 2017 7:26 pm
by carldong
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.
Re: Is there a good way to pipe two serial devices?
Posted: Fri Mar 03, 2017 8:06 pm
by Giovanni
Hi,
You need two listeners, that object is a link 1 to 1. It links one source to one thread.
Giovanni
Re: Is there a good way to pipe two serial devices?
Posted: Fri Mar 03, 2017 9:35 pm
by carldong
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?
Re: Is there a good way to pipe two serial devices?
Posted: Fri Mar 03, 2017 11:36 pm
by skute
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.
Re: Is there a good way to pipe two serial devices?
Posted: Sat Mar 04, 2017 4:01 am
by carldong
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.
Re: Is there a good way to pipe two serial devices?
Posted: Sat Mar 04, 2017 6:03 am
by carldong
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.
Re: Is there a good way to pipe two serial devices?
Posted: Sat Mar 04, 2017 6:37 am
by carldong
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...
Re: Is there a good way to pipe two serial devices?
Posted: Mon Mar 06, 2017 12:11 am
by carldong
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;
}
Re: Is there a good way to pipe two serial devices?
Posted: Mon Mar 06, 2017 8:27 am
by Giovanni
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
Re: Is there a good way to pipe two serial devices?
Posted: Tue Mar 07, 2017 1:51 am
by DeusExMachina
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);
}
}
}