Troubles with scanf()

21 Dec 2011

I am working with a CMUcam2+, and I'm trying to parse some packets it's sending containing color tracking information. Each packet is all ASCII characters, and so must be either brought into a char array/string and acted upon with atoi() or stripped apart with scanf(). My problem is, scanf() isn't even working!! I'm getting only the first value in the packet, only SOMETIMES...

Here's what a packet looks like:

T *** *** *** *** *** *** *** *** \r

Where each '*' represents a number (up to 240) in character form. Each is separated by white space. For example, here's what I'm getting:

T 42 0 0 0 104 251 0 0     where this is the actual camera output:     T 42 71 37 59 46 84 19 147

I'm using a little USB<->serial adapter to look in on the output from the CMUcam, and I'm just repeating what I get using the mbed's extra UARTs. Here's the code:

#include "mbed.h"
#include <string>

/*********************************************************************
TODO:
~Implement TW in beginning of setup, capture RGB values (calibrate
 in maze), then store in nonvolatile FLASH to be used later with
 TC mode (call TC w/o params to use same value as with TW). 
~

**********************************************************************/
void sendCommand(char data[]);
//void getResponse(void); 
void parseBuff(char, char&, char&, char&, char&, char&, char&, char&, char&);

DigitalOut myled(LED1);

#define PAN  0
#define TILT 1

char trackCMD[] = {"TC 240 240 240 240 240 240"};           // [Rmin Rmax Gmin Gmax Bmin Bmax] CMOS Color camera value range: 16-240
char trackWindow[] = {"TW"};
char getTrackColors[] = {"GT"};
char stopCMD[] = {"SL active"};
char getVersionCMD[] = {"GV"};
char enableLED[] = {"L0 1"};
char disableLED[] = {"L0 0"};
char highResolution[] = {"HR 1"};
char lowResolution[] = {"HR 0"};
char ycrcbAwbOff[] = {"CR 18 32 19 32"};                    // Tell registers: YCrCb Auto White Balance -OFF-, Auto gain OFF
char ycrcbAwbOn[] = {"CR 18 36 19 33"};
char enableServos[] = {"SM 3"};                             // Also refered to as "auto servo"
char setServoParams[] = {"SP "};                            // NOTE: Needs args 
char setServo[] = {"SV "};                                  // NOTE: Needs args "[servo # (0-3)] [value (46-210)]" 
                                                            // ...Pulse increments by 8.68us covering 400us to 1820us                                             
char buff[50];
                                    
Serial cmucam(p9, p10);
Serial pc(USBTX, USBRX);
Timer t;                                                    // General-purpose timer

int main() {
  char x, y, x1, y1, x2, y2, area, conf;
  
  cmucam.baud(9600);
  pc.baud(9600);
  pc.printf("Starting up...");
  sendCommand("RS");   
  wait_ms(100);                                             // Reset and wait to stabilize
  
  sendCommand(lowResolution);
  sendCommand(enableLED);                                   // Not sure why, but moving this enable command breaks the program...
  sendCommand(enableServos);
  sendCommand("SV 0 135");
  sendCommand("SV 1 100");
  wait_ms(2500);
  
  sendCommand(trackCMD);
  //sendCommand(trackWindow);

  pc.printf("Ready\n");
  for(;;) {
     //getResponse();
     parseBuff(0, x, y, x1, y1, x2, y2, area, conf);
     wait_ms(100);
     pc.printf("T %u %u %u %u %u %u %u %u\n", x,y,x1,y1,x2,y2,area,conf);     // Print for debugging
  }
}

void sendCommand(char data[]){
        cmucam.printf(data);
        cmucam.printf("\r");
        //getResponse();
}
//void getResponse() {              // Not used (raw data only)
//    int i=0;
//    bool done = false;
//    do {
//        int c = cmucam.getc();
//        if (c == '\r') {
//            done = true;
//            c = '\0';
//        }
//        buff[i++] = c;  
//    } while (!done);
//    //string buffer(buff);
//    //pc.printf("%s \n", buffer);
//}
void parseBuff(char packettype, char& massx, char& massy, char& x1, char& y1, char& x2, char& y2, char& pixels, char& confidence) {
    //pc.printf(buff);
    //pc.printf("\n");
    char pchar;
    switch(packettype) {
        case 0:             // Tracking (TC) Packet
            cmucam.scanf("\n%c %u, &u, %u, %u, %u, %u, %u, %u\r\n", &pchar, &massx, &massy, &x1, &y1, &x2, &y2, &pixels, &confidence);
            break;
        case 1:             // Servo Position (GS) Packet (not used yet)
            break;
    }
}

I did start to write some code for doing all the hard work manually before I realized like a dummy that I had scanf() at my disposal. I really don't know where to go at this point, and I'm pretty frustrated!! I'll try anything, so any suggestions are a huge help!

21 Dec 2011

I don't think you want the commas in the scanf format specification string since they don't exist in your data stream. I would expect %u specifiers to be associated with "unsigned int*" and not "char*". You might want to try "unsigned int' instead of "char" for the parameters passed into parseBuff().

21 Dec 2011

Hmm...ok, so I removed the commas (good point, thanks), and I tried different variable types (unsigned int and unsigned char), but that didn't work either. Still the same behavior (sometimes receiving the first number in the packet, most of the time, not).

Any other suggestions?

21 Dec 2011

Shouldn't the format parameter in scanf look like this? "%c %u, %u, %u, %u, %u, %u, %u, %u\r\n"

22 Dec 2011

Rene, I tried that as well, but no luck. I'm really lost as to what to do here...I'm thinking about just biting the bullet and writing the code for parsing the ASCII strings, but I'd really like to accomplish this with scanf if I can...

22 Dec 2011

I wonder about your query string in scanf(). Your packet format doesn't show a \n but in scanf you use it. Anyway writing a custom parser shouldn't need >5 lines of code and will be faster.