In the end the above routine did not work either, and I have had to stick with the OSTimDly(3) to mainitin the read working.
Here is the code that works but as I need to read 500+ video lines, this takes a long time. On a PC this takes about 15 seconds but this takes about 2 minutes in debug mode.
if(dataavail(U1_FD)) read(U1_FD, message, MAX_REPLY_NUMCHARS); // Flush the incoming buffer
sprintf(text, "SEND %d %d %d\r", 2*MAX_IMAGE_WIDTH/image_width, image_width/(int)cratio, (int)cratio); // Create command
writeall( U1_FD, text, strlen(text) ); // Send command
DiscardEcho(); // Discard the "SEND n m c\r\n" echo
OSTimeDly(3); // Wait for return data
read_nbr = ReadWithTimeout(U1_FD, message, (image_width/(int)cratio+1), 1); // read one line of image data
Any further ideas ?
Thanks
Lachlan
Adjusting serial buffer size
Re: Adjusting serial buffer size
try the code i posted, it does what you are looking to do.
Re: Adjusting serial buffer size
Your code burns between 50 and 75 seconds on 500 reads (assuming a 50 ms tick) and it is still fragile. It relies on a response coming in between 2 and 3 ticks.
Regarding your earlier attempt, it might help you to be aware that calling OSTimeDly(1) will wait between 0 and 1 tick depending on where you are in the current tick. Doing x of these in a loop can delay you a total of less than x ticks. If you want to wait a minimum of x ticks then each call in a loop should use OSTimeDly(2). Then your loop will wait somewhere between x and 2x ticks.
seulater's code seems very robust but his use of OSTimeDly(1) makes the minimum wait time indeterminate but you may not care as long as z is large enough. Changing it to OSTimeDly(2) will make the minimum determinate but may burn more time than you want (but still 1/3 to 2/3 less than you're burning now).
Dan's approach wastes no time but enters a killer loop that may never exit. Nonetheless if you take that as a starting point you should see a vast improvement. Then you can make it safer (this is more like premature pessimization, rather than premature optimization). Don't wait forever for data to come in but wait no more than some reasonable number of ticks (say 5). If the return value is <= 0 bail. If you get some data continue to loop.
If the expected data never comes in you burn a max of 5 ticks. If it comes in really really slowly you could burn more but this is incredibly unlikely. If the data comes in as expected you waste no time doing idle waits and it should be 50-75 seconds faster than your approach.
Regarding your earlier attempt, it might help you to be aware that calling OSTimeDly(1) will wait between 0 and 1 tick depending on where you are in the current tick. Doing x of these in a loop can delay you a total of less than x ticks. If you want to wait a minimum of x ticks then each call in a loop should use OSTimeDly(2). Then your loop will wait somewhere between x and 2x ticks.
seulater's code seems very robust but his use of OSTimeDly(1) makes the minimum wait time indeterminate but you may not care as long as z is large enough. Changing it to OSTimeDly(2) will make the minimum determinate but may burn more time than you want (but still 1/3 to 2/3 less than you're burning now).
Dan's approach wastes no time but enters a killer loop that may never exit. Nonetheless if you take that as a starting point you should see a vast improvement. Then you can make it safer (this is more like premature pessimization, rather than premature optimization). Don't wait forever for data to come in but wait no more than some reasonable number of ticks (say 5). If the return value is <= 0 bail. If you get some data continue to loop.
If the expected data never comes in you burn a max of 5 ticks. If it comes in really really slowly you could burn more but this is incredibly unlikely. If the data comes in as expected you waste no time doing idle waits and it should be 50-75 seconds faster than your approach.
Last edited by tod on Fri Mar 29, 2013 1:11 pm, edited 1 time in total.
Re: Adjusting serial buffer size
In seulater's code, he waits until some data is ready and then reads the data, but I don't see this being much different than the default routine, except that there is some delay prior to the read. However, if all the data has not come in as yet, there is no dealt to wait for it to come in.
I am reading 361 bytes at a time at 115,200 baud, and assuming about 10 bits per byte that works out to be around 32ms for the ranger, plus any overhead for the video processor turn-around. Therefore there is no problem putting a permanent delay of at least 1 tick ( even though it may be less than 1 tick), but after that, if all the data is not yet in ( because the tick was less than a full tick or the video processor turnaround was longer), then if the data buffer is empty and the data has not yet fully arrived, then I need a delay after the first read.
That's what i tried to do with my alternative ReadTimeout code that I posted, but it also did not work correctly. I will try seulater's code tomorrow and see how that works. Maybe I use dans code with a delay And a counter, but then that looks like my alternative ReadTimeout again.
I'll try the different alternatives tomorrow.
Thanks or your input.
Regards
Lachlan
I am reading 361 bytes at a time at 115,200 baud, and assuming about 10 bits per byte that works out to be around 32ms for the ranger, plus any overhead for the video processor turn-around. Therefore there is no problem putting a permanent delay of at least 1 tick ( even though it may be less than 1 tick), but after that, if all the data is not yet in ( because the tick was less than a full tick or the video processor turnaround was longer), then if the data buffer is empty and the data has not yet fully arrived, then I need a delay after the first read.
That's what i tried to do with my alternative ReadTimeout code that I posted, but it also did not work correctly. I will try seulater's code tomorrow and see how that works. Maybe I use dans code with a delay And a counter, but then that looks like my alternative ReadTimeout again.
I'll try the different alternatives tomorrow.
Thanks or your input.
Regards
Lachlan
Re: Adjusting serial buffer size
Just to clarify.
When you use ReadWithTimeout, it will NOT return when the buffer hits the level you set it to.
for example: num = ReadWithTimeout(U1_FD, (char *)& &message[total], 361 ,TICKS_PER_SECOND);
It will not hang here until the 3'rd parameter of 361 is satisfied, or the time of the 4'th parameter has been exceeded.
the 3'rd parameter means that if there was more than 361 it would return and put more data into the 2'nd parameter to over fill it.
This being the case, if you have data there even one byte worth, when your coded executes this line of code it will return with a 1 for num.
So that being said. you can tackle this a few different ways. You can put ReadWithTimeout into a while loop until you receive the desired bytes you need, but that is not good practice. If you never get that amount you are stuck there. You always want a way out of something.
What i did was take advantage of the time expire feature of ReadWithTimeout. i stay in a while loop and wait for x time. if no data was ever returned then we will receive 0 for num. Being that we waited one second that should be long enough to see if there was any data.
When it returns 0, we know we have or should have it all. The reason why i have the loop before this ReadWithTimeout, is because without knowing exactly what you are doing i dont know from the point when you call ReadWithTimeout, if you device has already sent the data yet. So if i just used ReadWithTimeout alone it might expire before your device even sent the data. So to be safe i used the previous loop.
What that does is sit there and wait for at least one byte to be in the buffer. As soon as we see one byte that probably means that more is coming, so lets fall out of that loop and now sit in the ReadWithTimeout loop to capture the rest of the data.
When you use ReadWithTimeout, it will NOT return when the buffer hits the level you set it to.
for example: num = ReadWithTimeout(U1_FD, (char *)& &message[total], 361 ,TICKS_PER_SECOND);
It will not hang here until the 3'rd parameter of 361 is satisfied, or the time of the 4'th parameter has been exceeded.
the 3'rd parameter means that if there was more than 361 it would return and put more data into the 2'nd parameter to over fill it.
This being the case, if you have data there even one byte worth, when your coded executes this line of code it will return with a 1 for num.
So that being said. you can tackle this a few different ways. You can put ReadWithTimeout into a while loop until you receive the desired bytes you need, but that is not good practice. If you never get that amount you are stuck there. You always want a way out of something.
What i did was take advantage of the time expire feature of ReadWithTimeout. i stay in a while loop and wait for x time. if no data was ever returned then we will receive 0 for num. Being that we waited one second that should be long enough to see if there was any data.
When it returns 0, we know we have or should have it all. The reason why i have the loop before this ReadWithTimeout, is because without knowing exactly what you are doing i dont know from the point when you call ReadWithTimeout, if you device has already sent the data yet. So if i just used ReadWithTimeout alone it might expire before your device even sent the data. So to be safe i used the previous loop.
What that does is sit there and wait for at least one byte to be in the buffer. As soon as we see one byte that probably means that more is coming, so lets fall out of that loop and now sit in the ReadWithTimeout loop to capture the rest of the data.
Re: Adjusting serial buffer size
Here's some sample code on gist I wrote, compiled and tested that will read X bytes without any additional delays. If you're data doesn't arrive within the tick timeout parameter it just prints out the error and returns. I sent 500 lines of 361 characters from a large text file. It took under 20 seconds on the 54415.
Re: Adjusting serial buffer size
Hi Tod,
Used your code but had to modify it slightly but it seems to work. Here is my version of your code. Please check it for bugs.
int ReadTimeout(int port, char * read_buffer, int messageLength, int timeoutTicks){
int read_status = 0;
int bytes_read = read_status;
while (bytes_read < messageLength) {
read_status = ReadWithTimeout(port, &read_buffer[bytes_read], messageLength - bytes_read, timeoutTicks);
if (read_status <= 0)
return bytes_read;
bytes_read += read_status;
} //do something with read_buffer - no guarantee it ends with \0 if it filled the entire buffer
return bytes_read;
}
It interesting to note that if I put the following line inside the loop I get 'pass' printed 6 times
iprintf("pass\r\n");
Thanks
Lachlan
Used your code but had to modify it slightly but it seems to work. Here is my version of your code. Please check it for bugs.
int ReadTimeout(int port, char * read_buffer, int messageLength, int timeoutTicks){
int read_status = 0;
int bytes_read = read_status;
while (bytes_read < messageLength) {
read_status = ReadWithTimeout(port, &read_buffer[bytes_read], messageLength - bytes_read, timeoutTicks);
if (read_status <= 0)
return bytes_read;
bytes_read += read_status;
} //do something with read_buffer - no guarantee it ends with \0 if it filled the entire buffer
return bytes_read;
}
It interesting to note that if I put the following line inside the loop I get 'pass' printed 6 times
iprintf("pass\r\n");
Thanks
Lachlan
Re: Adjusting serial buffer size
You adaptation seems OK to me. You lost the test for the explicit serial port error (value < 0 returned for the status) but I assume your calling code recognizes that the number of bytes read is not what was expected so you just handle the error somehow and you don't really care if the error was caused by lost data or a serial port failure of some sort.
I would guess the reason you see "pass" only six times is because the iprintf takes so long. If you put a counter inside the loop and then print out the value of the counter before the final return you will probably see a much larger number. On the processor I'm using I get close to one loop per byte being read. This makes sense to me, the NB can read a byte faster than a 115KB serial line can receive it.
I would guess the reason you see "pass" only six times is because the iprintf takes so long. If you put a counter inside the loop and then print out the value of the counter before the final return you will probably see a much larger number. On the processor I'm using I get close to one loop per byte being read. This makes sense to me, the NB can read a byte faster than a 115KB serial line can receive it.
Re: Adjusting serial buffer size
For my purposes I discard the packet if it is not full length, but I like you idea of putting the error code back in to make it a general purpose routine.
Thanks
Lachlan
Thanks
Lachlan