I have a clear idea of what I want, and I _think_ I know how I'd like to make it work, but I am getting caught up in the unfamiliar details of writing for multiple threads.
Since my error may be in how things are being divided, I'll begin with a description of the project, and what I hope to accomplish:
I have an XS1-L2 chip, which has hardware for a serial port and a SD card. The serial port is using the fast_uart software, with separate threads for transmit and receive. It's just Tx, Rx, and ground. No handshaking in hardware or software, and it is working well.
The SD card interface is using the SD code from the github, and is wired for the faster "4-bit" mode. I have not tested yet but for this example we will assume that it's working.
There are a few other parts, but I think that's enough info to describe the problem. My goal is to set up a "pipeline" to log all serial input (plain text) to a file on the SD card. Once it's working I intend to raise the baud rate as much as possible, so speed is important.
I currently have a thread receiving the serial into a streaming chanend.
The Disk save routines all use a BYTE array and length as input. I assume that for any reasonable disk write speed, I should work in multiples of 512 bytes.
So the code to connect these must use the incoming serial data to fill a buffer of, say 512 bytes, and when it's full then call disk_write(), passing that buffer.
Since it is likely that more serial data will be arriving while the disk write is in progress, I have set up two buffers, and switching to use one while the other is out to disk_write().
it also will flush a partial buffer after a few seconds of idle time.
Something like this:
Code: Select all
void serialrcv(streaming chanend uartRX, chanend DiskIO)
{
// double buffer streaming input , write buffer
//to SDCard when full or idle for 5 seconds.
unsigned char buffA[512]; // double buffers
unsigned char buffB[512];
unsigned char next;
int aPlace = 0, bPlace = 0; // double placemarkers
int whichbuf = 0;
unsigned time = 0;
timer t;
while(1)
{
select
{ // new character from serial input
case uartRX :> next:
t :> time;
time += FLUSH_DELAY;
if(0 == whichbuf)
{ // add to buffer A, check for buffer full
buffA[aPlace++] = next;
if(512 == aPlace)
{
whichbuf = 1; // switch to other buffer
WriteBuffer(buffA, aPlace, DiskIO);
aPlace = 0;
}
}
else
{ // add to buffer B, check for buffer full
buffB[bPlace++] = next;
if(512 == bPlace)
{
whichbuf = 0; // switch to other buffer
WriteBuffer(buffB, bPlace, DiskIO);
bPlace = 0;
}
}
break;
case t when timerafter(time):> t:
t += FLUSH_DELAY;
// the stream has paused, flush the active buffer.
if(0 == whichbuf)
{
whichbuf = 1;
if(aPlace)
{
WriteBuffer(buffA, aPlace, DiskIO);
aPlace = 0;
}
}
else
{
whichbuf = 0;
if(bPlace)
{
WriteBuffer(buffB, bPlace, DiskIO);
bPlace = 0;
}
}
break;
}
}
}
Now WriteBuffer has to signal a separate thread to actually do the operation.
If we do it on this threads context, then incoming serial will be lost.
I don't want to send a stream of individual characters, as I have it all in an
array, all ready for the disk_write(). Note that the length will NOT always be
512, as partial buffers are written occasionally as well.
I'm not sure how to send "commands" instead of character streams through a channel.
I'm not sure that I'm allowed to send an array by reference.
I fully expect the compiler to complain about data sharing between threads, as I am managing the double-buffers myself, and it doesn't have much faith in my ability to do so. ;)
And finally, I tried to
#define BUF_SIZE 512
and replace all instances of "512" with BUF_SIZE, and it choked on every one.
When defining a simple constant fails, I really begin to wonder if I have lost my mind.
And when that many questions come up at once, I am fairly sure that I'm going about this all wrong. I'm sure that this is just not the "XMOS" way of doing things.
I realize this is a long post, but since you provided a special "Getting Started" forum for beginners, I hope I am within the limits.
Thanks for your suggestions!
LyleHaze