Serial help

22 Mar 2011

What I'm attempting has already been done here >>http://mbed.org/users/jarkman/programs/ucam/gpdz4b. I'm fairly new to programming and even newer to C/C++ so I can only wrap my head around so much of what his code is doing.

As an exercise I've attempted to reinvent this wheel using baby steps at a time while using his code as reference sometimes. I send the 6 sync bytes I should be getting 12 response bytes back, which I am. I intentionally made the bytes_rcv array just hold 6 elements at a time. My problem lies in the fact that after first 3 receives(or 2nd depending on how you look at it) the response gets offset and I have no idea why. Please advise.

#include "mbed.h"

Serial uCamSerial(p13, p14);
Serial pcSerial(USBTX, USBRX);

int main() {
    
    pcSerial.baud(115200);
    uCamSerial.baud(115200);
    unsigned char sync[6] = {0xAA, 0x0D, 0x00, 0x00, 0x00, 0x00};//SYNC Send/Response
    unsigned char bytes_rcv[6];
     
    while(true){
        for(int i = 0; i < 6; i++){
            uCamSerial.putc(sync[i]);//Send whole sync command
        }
                
        if(uCamSerial.readable()){
            for(int i = 0; i < 6; i++){
                bytes_rcv[i] = uCamSerial.getc();//Store incoming response into array
                pcSerial.printf("%.2X", bytes_rcv[i]);
            }
                        
            pcSerial.printf("\r\n");
        }
        else pcSerial.printf("camera is returning nothing\r\n");
        wait(1);
    }

/media/uploads/Clory/camdocs.png/media/uploads/Clory/_scaled_comscrn.png

22 Mar 2011

You are probably dropping bytes due to the amount of time spent formatting the output via printf() and then sending it over the wire back to the PC.

Maybe you could make the output less verbose by printing a single character to indicate when certain things happen. This code shows an example of what I mean but I haven't tested it:

#include "mbed.h"

Serial uCamSerial(p13, p14);
Serial pcSerial(USBTX, USBRX);

int main() 
{
    pcSerial.baud(115200);
    uCamSerial.baud(115200);
    unsigned char sync[6] = {0xAA, 0x0D, 0x00, 0x00, 0x00, 0x00};//SYNC Send/Response
    unsigned char bytes_rcv[6];
     
    while(true)
    {
        for(int i = 0; i < 6; i++)
        {
            uCamSerial.putc(sync[i]);//Send whole sync command
        }
                
        if(uCamSerial.readable())
        {
            for(int i = 0; i < 6; i++)
            {
                bytes_rcv[i] = uCamSerial.getc();//Store incoming response into array
            }

            static const unsigned char ack[6] =  { 0xAA, 0x0E, 0x0D, 0x00, 0x00, 0x00 };
            
            if (0 == memcmp(bytes_rcv, sync, sizeof(sync)))
            {
                pcSerial.printf("S");
            }
            else if (0 == memcmp(bytes_rcv, ack, sizeof(ack)))
            {
                pcSerial.printf("A");
            }
            else
            {
                pcSerial.printf("?");
            }                        
        }
        else
        { 
            pcSerial.printf("-");
        }
        wait(1);
    }
}
22 Mar 2011

There are some issues that I would take up but, with the Uarts having a 16byte fifo they shouldn't be an issue with your simple program. However, for high baud rates like 115200 I would always use a buffer scheme. Something like this:-

Import libraryMODSERIAL

Bug fix release

#include "mbed.h"
#include "MODSERIAL.h"

#define STATE_IDLE 0
#define STATE_SEND_SYNC 1
#define STATE_WAITING_FOR_RESPONSE 2

MODSERIAL uCamSerial(p13, p14);
MODSERIAL pcSerial(USBTX, USBRX);
Ticker	  tsync;
Timeout   tout;
volatile bool timedOut;

volatile int state;

const char sync[6] = { 0xAA, 0x0D, 0x00, 0x00, 0x00, 0x00 }; //SYNC Send/Response

char bytes_rcv[6]; // ARM char is unsigned anyway.

// Called if 6 bytes are not received with 500ms.
void cbTimeout(void) {
	timedOut = true;
}

// Called once every second by the ticker tsync.
void cbTicker(void) {
	if (state == STATE_IDLE) {
		state = STATE_SEND_SYNC;
	}
}

// Send a const buffer to the camera.
void sendSync(void) {
        uCamSerial.rxBufferFlush(); 
	for (int i = 0; i < 6; i++) {
		uCamSerial.putc(sync[i]);	
	}
        // Begin a timeout timer to test for no response/timeout.
	tout.attach_us(&cbTimeout, 500000); // 500ms
}

int main() {
	pcSerial.baud(115200);
	uCamSerial.baud(115200);
    
	state = STATE_IDLE;

        timedOut = false;

	tsync.attach(&cbTicker, 1.0); // Send sync once every second.

	while(1) {
		if (state == STATE_SEND_SYNC) {
			state = STATE_WAITING_FOR_RESPONSE;
			sendSync();
		}

                // Have we received 6 bytes in return?
		if (state == STATE_WAITING_FOR_RESPONSE && uCamSerial.rxBufferGetCount() == 6) {
			tout.detach(); // Disable timeout timer.
                        // Get the bytes into the buffer first
			for (int i = 0; i < 6; i++) {
				bytes_rcv[i] = uCamSerial.getc();
			}
                        // then printf them to pcSerial
                        for (int i = 0; i < 6; i++) {
				pcSerial.printf("%02x", bytes_rcv[i]);
			}
			pcSerial.printf("\n\r");
			state = STATE_IDLE;
		}

		if (timedOut) {
			timedOut = false;
			pcSerial.printf("Timed out waiting for Camera\n");
			state = STATE_IDLE;
		}

		// Don't wait() in code, use timers/tickers to trigger an event instead.
		// Waiting around measn you are not doing anything and can miss/drop data.
		// wait(1);	
    	}
}
22 Mar 2011

Btw, further to what Adam said above about printf() have a read of this article to understand more about what printf() brings to the party and about how wait() can be evil if used incorrectly.

23 Mar 2011

Hey thanks a lot you guys.

@Adam, your code was giving the same results as mine, -ASA???? and so forth.

@Andy, your code worked but not the way I was expecting. I wanted the whole buffer 6 bytes at a time, not just the first 6 bytes. I have rewritten the code using MODSERIAL but I'm not sure exactly how the buffer works. After I get bytes from the buffer and store it in an array is the buffer "drained" and the remaining bytes shifted to the front or do I have to manually shift to the next 6 bytes the buffer to get the remaining bytes?

23 Mar 2011

Modserial implements a circular buffer system. getc() will get the next char from the buffer so effectivly "drains" (as you put it) it by one byte.

If you look at Modserial's API you'll see if offers lots of methods. One use in the example was to see how many bytes are in the buffer. I used that to wait until it had 6bytes in it before moving the buffer to your local array.

23 Mar 2011

Thanks for the quick response Andy. I'm trying to keep it simple without getting into tickers and timers so I came up with this code. It's still only giving me 6 bytes though, aren't there supposed to be 6 bytes left in the buffer?

#include "mbed.h"
#include "MODSERIAL.h"
MODSERIAL uCamSerial(p13, p14);
MODSERIAL pcSerial(USBTX, USBRX);


char sync[6] = {0xAA, 0x0D, 0x00, 0x00, 0x00, 0x00};
char bytes_rcvd[6];

int main()
{
    pcSerial.baud(115200);
    uCamSerial.baud(115200);
    
    int i;
    for(i = 0; i < sizeof(sync); i++)
    {
        uCamSerial.putc(sync[i]);
    }
    
    while(!uCamSerial.txBufferEmpty())
    {
        for(i = 0; i < 6; i++)
        {
        bytes_rcvd[i] = uCamSerial.getc();
        }
        
        for(i = 0; i < sizeof(bytes_rcvd); i++)
        {
            pcSerial.printf("%02X",bytes_rcvd[i]);
        }
        pcSerial.printf("\n\r");
    }   
}
24 Mar 2011

You've broken your while(1) loop by adding a test condition that means the process can end thus ending your program. Timers and Tickers are simple and you really should be using them. Trying to design a system by starting at main() and doing in one big linear set of code will become totally unmanagable when you get beyond a 100 lines or so!

24 Mar 2011

I definitely appreciate your guidance and understand where you're coming from but I wasn't trying to do it in one big chuck, I'm just trying to understand what everything does one piece at a time.

I thought the while loop accepted a boolean or boolean logic? The only thing I could think of why it wouldn't work was that there was nothing in the buffer when it got to the loop. Again, I'm fairly new at this, thank you.

24 Mar 2011

The problem is in your program if the while() evaluates false your loop will terminate ending your program. It's normal to do while(1) { ... } and loop forever.

It may help if you describe in words rather than code what you are trying to do.

24 Mar 2011

txBufferEmpty() is supposed to return true if there is nothing being held in the buffer from the camera right?

So my logic was that if there is something in the camera -> mbed buffer, txBufferEmpty() would return false and but while loop needs a true statement to keep running so just invert the response.

Earlier on you agreed with me that getc() "drains" the buffer so by storing the first 6 byes in the bytes_rcvd array the txBuffer of the camera would be minus 6 bytes down to 6 remaining bytes which would get printed to my console.

Then since there were still bytes remaining and the while loop was still running it would go back to the top draining the remaining 6 bytes, giving me the second expected response and then jumping out of the while loop because the txBuffer would now be empty and !txBufferEmpty() would return false.

24 Mar 2011

You're logic is flawed. Put that code away and don't return to it! Just try writing in words what you are trying to do. Eg:

  1. Send string top camera.
  2. Wait until we have received N number of bytes from camera.
  3. Do something with those bytes.

etc etc

24 Mar 2011

I laughed so hard at that slap in the face. But here we go...

  1. Send sync.
  2. Print first 6 of 12 received bytes.
  3. Print remaining 6 bytes.
  4. Repeat.

That's all I wanted initially then you introduced me to MODSERIAL and I decided to try things out.

24 Mar 2011

lol!

Then, just change my previous program like this:-

                // Have we received 12 bytes in return?
		if (state == STATE_WAITING_FOR_RESPONSE && uCamSerial.rxBufferGetCount() == 12) {
			tout.detach(); // Disable timeout timer.

                        // Get the first 6 bytes into the local buffer
			for (int i = 0; i < 6; i++) { bytes_rcv[i] = uCamSerial.getc();	}
                        // then printf them to pcSerial
                        for (int i = 0; i < 6; i++) { pcSerial.printf("%02x", bytes_rcv[i]); }
			pcSerial.printf("\n\r");

                        // Get the next 6 bytes into the local buffer
			for (int i = 0; i < 6; i++) { bytes_rcv[i] = uCamSerial.getc();	}
                        // then printf them to pcSerial
                        for (int i = 0; i < 6; i++) { pcSerial.printf("%02x", bytes_rcv[i]); }
			pcSerial.printf("\n\r");

			state = STATE_IDLE;
		}

Notice we wait for 12 bytes in the serial buffer. Once we have 12 we read the first 6 out, print them and then get the next 6 and do the same :)

24 Mar 2011

Believe it or not Andy I actually did rip your code apart and got it to do what I wanted (almost exactly like that) I'm just having a hard time figuring out why I can't do it much simpler. Thats when I started checking out what was going on with the buffers.

And I just noticed something, the uCamSerial.rxBuffer is whats holding information FROM the camera?

24 Mar 2011

rx means "receive". The camera "sends" so the mbed "receives". So yes, rx buffer is the byte stream coming from the camera to you.

24 Mar 2011

Cliff Henry wrote:

...why I can't do it much simpler...

Trust me. Without a buffer to hold the data your life would be MUCH more complex! It's doing all the hard work for you. All you have to do is ask it how many bytes it has received. Without that you would have to capture each of those bytes and count them. At 115200 you would need to get them using interrupts to make sure you don't miss any, etc etc. Trust me, MODSERIAL is doing all the complex work for you ;)