Exemplo n.º 1
0
/**
 * Sends the picture currently in the pixbuf over serial
 */
int send_picture_msg(lua_State *_l) {
	uint32_t x, y;
  	uint32_t size_x, size_y;

    // only send if we're in debug mode
    if (debug_on) {
        init_packet();
        // First the header
        // first the ID we have to put it in two bytes
        // big endian
        put_slip_char(get_msg_id_most_repr(PPM_MSG_ID));
        put_slip_char(get_msg_id_least_repr(PPM_MSG_ID));
        
        // now the param count. 1 bytes
        put_slip_char(1);
        
        cc3_pixbuf_rewind(); // just in case
        uint8_t *row = cc3_malloc_rows(1);
        
        // now parameters
        size_x = cc3_g_pixbuf_frame.width;
        size_y = cc3_g_pixbuf_frame.height;
        char* head = malloc(20);
        sprintf(head,"P6\n%d %d\n255\n",size_x,size_y );
        uint32_t size = strlen(head)+size_x*size_y*3;
        
        // size is 3 bytes, so we first get
        // rid of most representative byte
        put_slip_char(get_size_most_repr(size));
        put_slip_char(get_size_middle_repr(size));
        put_slip_char(get_size_least_repr(size));
        put_slip_string(head);
        free(head);
        
		bool led_on = false;
        for (y = 0; y < size_y; y++) {
            cc3_pixbuf_read_rows(row, 1);
        	cc3_led_set_state(0, led_on=!led_on);
            for (x = 0; x < size_x * 3U; x++) {
                /* Sleep to prevent byte-loss. Seems a bit extreme, but 
                   I saw problems with even 1000 and 500 as intervals. */
                if (x % 100 == 0) {
                    cc3_timer_wait_ms (5);
                }
                put_slip_char(row[x]);
            }
        }
        cc3_led_set_state(0, false);
        free(row);
        finish_packet();
    }    
    return 0;
}
Exemplo n.º 2
0
/**
 * Make the led passed in as parameter blink for ms
 * milliseconds.
 * The LED will be turned OFF as the last step of this function
 */
void blink_led( uint8_t led, uint32_t ms ) {
  	uint32_t INTERVAL = 40;
  	uint_least32_t start_time = cc3_timer_get_current_ms ();
  	bool led_on = true;
  	cc3_led_set_state(led, led_on);
	do {
		led_on = !led_on;
		cc3_led_set_state(led, led_on);
		cc3_timer_wait_ms(INTERVAL);
	} while (cc3_timer_get_current_ms () < (start_time + ms));
  	cc3_led_set_state(led, false);
}
Exemplo n.º 3
0
int main(void) {
  cc3_color_info_pkt_t s_pkt;


  cc3_uart_init (0, 
		 CC3_UART_RATE_115200,
		 CC3_UART_MODE_8N1,
		 CC3_UART_BINMODE_TEXT);

  cc3_camera_init ();


  //cc3_camera_set_colorspace(CC3_COLORSPACE_YCRCB);
  cc3_camera_set_resolution(CC3_CAMERA_RESOLUTION_LOW);
  //cc3_pixbuf_frame_set_subsample(CC3_SUBSAMPLE_NEAREST, 2, 2);
  cc3_camera_set_auto_exposure (true);
  cc3_camera_set_auto_white_balance (true);

  cc3_led_set_state (0, false);
  printf ("Waiting for image to stabilize\n");
  cc3_timer_wait_ms (2000);
  cc3_led_set_state (0, true);
  cc3_camera_set_auto_exposure (false);
  cc3_camera_set_auto_white_balance (false);
  
  while(true) {
    simple_get_mean(&s_pkt);
    printf( "min = [%d,%d,%d] mean = [%d,%d,%d] max = [%d,%d,%d] deviation = [%d,%d,%d]\n",
		    s_pkt.min.channel[0],
		    s_pkt.min.channel[1],
		    s_pkt.min.channel[2],
		    s_pkt.mean.channel[0],
		    s_pkt.mean.channel[1],
		    s_pkt.mean.channel[2],
		    s_pkt.max.channel[0],
		    s_pkt.max.channel[1],
		    s_pkt.max.channel[2],
		    s_pkt.deviation.channel[0],
		    s_pkt.deviation.channel[1],
		    s_pkt.deviation.channel[2]
		    );

   }
  
}
Exemplo n.º 4
0
int main(void) {
  int i;

  cc3_uart_init (0,
		 CC3_UART_RATE_115200,
		 CC3_UART_MODE_8N1,
		 CC3_UART_BINMODE_TEXT);

  cc3_camera_init ();

  // ready camera
  cc3_camera_set_auto_exposure (true);
  cc3_camera_set_auto_white_balance (true);
  cc3_camera_set_resolution(CC3_CAMERA_RESOLUTION_HIGH);
  cc3_camera_set_colorspace(CC3_COLORSPACE_YCRCB);
  //cc3_camera_set_colorspace(CC3_COLORSPACE_RGB);
  cc3_timer_wait_ms(1000);

  // init
  cc3_led_set_state(0, false);
  cc3_led_set_state(2, true);
  i = 0;
  while(true) {
    
    printf("Ready to go... waiting the button\n");
    while(!cc3_button_get_state());
    printf("Go\n");

	  i++;
    if (i%2==0) {
      cc3_led_set_state (2, true);
    } else {
      cc3_led_set_state (2, false);
    }
    compute_frm(i);
  }

  return 0;
}
Exemplo n.º 5
0
void get_gps_data()
{
	// gps buffer
	char* gps_buff = (char*)malloc(sizeof(char)*100);

	// scan for data from the gps
	scanf("%s",gps_buff);
#ifdef LOG_GPS
	snprintf(log_str, 100, "\r\nGetting GPS Data: %s\r\n",gps_buff);
	write_log();
#endif

	// now try to parst the gps string
	if(parse_GPS(gps_buff))
	{
#ifdef LOG_GPS
		snprintf(log_str, 100, "Lat - %d\tLon - %d\tTime - %02d:%02d:%02d\r\n",
			(int)(gps->lat*1000000),
			(int)(gps->lon*1000000),
			gps->hour,gps->minute,gps->second);
		write_log();
#endif
		// turn on 'Good GPS LED'
		cc3_led_set_state (1, true);
	}
	else
	{
#ifdef LOG_GPS
		snprintf(log_str, 100, "INVALID\r\n");
		write_log();
#endif
		// turn off 'Good GPS LED'
		cc3_led_set_state (1, false);
	}

	free(gps_buff);
}
Exemplo n.º 6
0
void takePict()
{
#ifdef LOG
	snprintf(log_str, 100, "\r\nTaking Picture:\n\r");
	write_log();
#endif

	// Take picture
	char filename[24];
	snprintf(filename, 24, "c:/%d/img%.5d.jpg", gps->hour, picNum);

	// print file that you are going to write to stderr
	fprintf(stderr,"%s\r\n", filename);
	memory = fopen(filename, "w");
	if(memory==NULL)
	{
		cc3_led_set_state(3, true);
#ifdef LOG
		snprintf(log_str, 100, "Error: Can't open file\r\n" );
		write_log();
#endif
		while(1);
	}
	capture_current_jpeg(memory);
	fclose(memory);
	if ( fclose (memory) == EOF) {
		perror ("fclose failed");
		while(1);
	}

	picNum++;
	// save the picture number just in case the camera is turned
	// off it will start naming with that number
	memory = fopen("c:/picNum.txt", "w");
	if (memory == NULL) {
		perror ("fopen failed");
		while(1);
	}
	fprintf(memory, "%d", picNum);
	if ( fclose (memory) == EOF) {
		perror ("fclose failed");
		while(1);
	}
}
Exemplo n.º 7
0
/**
 * Turns LED led on for ms milliseconds. LED led is turned off
 * after that.
 */
void turn_on_led_for( uint8_t led, uint32_t ms ) {
  	cc3_led_set_state(led, true);
	cc3_timer_wait_ms(ms);
  	cc3_led_set_state(led, false);
}
Exemplo n.º 8
0
/**
 * Wrapper of cc_3_led_set_state to turn off LED
 */
int turn_off_led(lua_State *_l) {
	uint8_t led = luaL_checkinteger(_l, 1); // make sure it's an integer
	luaL_argcheck(_l, (led == 0 || led == 1 || led == 2), 1, "LED must be either 0, 1 or 2.");
    cc3_led_set_state(led, false);
    return 0; // no return parameters
}
Exemplo n.º 9
0
bool initialize()
{	
	char* config_buff = (char*)malloc(sizeof(char)*100);

	// init some variables
	prevTime = 0;
	deltaTime = 0;
	deltaDist = 0;
	power_save = false;
	cam_focus_delay = 8000;

	// init parser structures for gps and config
	parse_init();

	// turn on leds so we know it started working
	cc3_led_set_state (1, true);
	cc3_led_set_state (2, true);

	// configure uart for gps serial communication
	cc3_uart_init (0, CC3_UART_RATE_4800, CC3_UART_MODE_8N1,
		CC3_UART_BINMODE_BINARY);

	// init the camera and file system
	cc3_camera_init ();
	cc3_filesystem_init();

#ifdef LOG
	snprintf(log_str, 100, "**********\n\rNew Session\n\r");
	write_log();
	snprintf(log_str, 100, "\n\rReading config file\r\n");
	write_log();
#endif

	// read config file from MMC
	memory = fopen ("c:/config.txt", "r");
	if (memory == NULL) {
		perror ("fopen failed\r\n");
		return false;
	}
	// get config file
	fscanf(memory, "%s", config_buff);
	if (fclose (memory) == EOF) {
		perror ("fclose failed\r\n");
		return false;
	}
	// parse config file
	parse_Config(config_buff);

	// if the config is not good then quit
	if(!config->good)
	{
#ifdef LOG
		snprintf(log_str, 100, "\n\rconfig.txt INVALID\r\n");
		write_log();
#endif
		return false;
	}

#ifdef LOG
	snprintf(log_str, 100, "\r\nConfig File:\n\rDelay(ms) - %d\tMin Dist(mm) - %d",(int)config->delay,(int)(config->min_dist*1000));
	write_log();
	if(config->halo)
	{
		snprintf(log_str, 100, "\tHalo - true\r\n");
		write_log();
		snprintf(log_str, 100, "\tHalo %s:\t Lat*1000000 - %d\tLon*1000000 - %d\tRange(mm) - %d\r\n",
			config->halo_info->name,
			(int)(config->halo_info->lat*1000000),
			(int)(config->halo_info->lon*1000000),
			(int)(config->halo_info->range*1000) );
		write_log();
	}
	else
	{
		snprintf(log_str, 100, "\tHalo - false\r\n");
		write_log();
	}
#endif

	//configure camera
	cc3_camera_set_colorspace (CC3_COLORSPACE_RGB);
	cc3_camera_set_resolution (CC3_CAMERA_RESOLUTION_HIGH);
	cc3_camera_set_auto_white_balance (true);
	cc3_camera_set_auto_exposure (true);

	// init pixbuf with width and height and JPEG compression
	cc3_pixbuf_load();
	init_jpeg();

	// try to open picNum.txt if exist that will be the 
	// picture number we will start with if not start at 0
#ifdef LOG
	snprintf(log_str, 100, "\n\rReading picNum file\r\n");
	write_log();
#endif
	memory = fopen ("c:/picNum.txt", "r");
	if (memory == NULL) {
		picNum = 0;
	}
	else
	{
		char* picNum_buff = (char*)malloc(sizeof(char)*100);
		fscanf(memory, "%s", picNum_buff);
		picNum = atoi(picNum_buff);
		free(picNum_buff);
	}
	if (fclose (memory) == EOF) {
		perror ("fclose failed\r\n");
		return false;
	}
#ifdef LOG
	snprintf(log_str, 100, "Starting picture numbering at: %d\r\n",picNum);
	write_log();
#endif

	// starts out awake with no gps signal
	cc3_led_set_state (1, false);
	cc3_led_set_state (2, true);

	cc3_timer_wait_ms(1000);
	free(config_buff);
	return true;
}
Exemplo n.º 10
0
Arquivo: main.c Projeto: rcrowder/Burt
int main(void) {
  int i;
  int result;
  FILE *f;
  bool light_on = true;

  cc3_uart_init (0,
		 CC3_UART_RATE_115200,
		 CC3_UART_MODE_8N1,
		 CC3_UART_BINMODE_TEXT);

  cc3_camera_init ();

  // use MMC
  cc3_filesystem_init();

  cc3_camera_set_resolution(CC3_CAMERA_RESOLUTION_HIGH);
  cc3_timer_wait_ms(1000);

  // init
  cc3_led_set_state(0, false);
  i = 0;
  while(!cc3_button_get_state());
  while(true) {
    char filename[16];

    // Check if files exist, if they do then skip over them
    do {
      snprintf(filename, 16, "c:/img%.5d.ppm", i);
      //snprintf(filename, 16, "img%.5d.ppm", i);
      f = fopen(filename, "r");
      if (f != NULL) {
	printf( "%s already exists...\n",filename );
	i++;
	result = fclose(f);
	if (result) {
	  perror("first fclose failed");
	}
      }
    } while(f != NULL);

    // print file that you are going to write to stderr
    fprintf(stderr,"%s ", filename);
    fflush(stderr);
    f = fopen(filename, "w");

    if (f == NULL || i > 512) {
      if (f == NULL) {
	perror("crap");
      } else {
	fprintf(stderr, "full\n");
      }

      while (true) {
	cc3_led_set_state(0, true);
	cc3_led_set_state(2, true);
	cc3_timer_wait_ms(500);
	cc3_led_set_state(0, false);
	cc3_led_set_state(2, false);
	cc3_timer_wait_ms(500);
      }
    }


    if (light_on) {
      cc3_led_set_state (2, true);
    } else {
      cc3_led_set_state (2, false);
    }
    light_on = !light_on;
    capture_ppm(f);

    result = fclose(f);
    if (result) {
      perror("second fclose failed");
    }
    fprintf(stderr, "\r\n");

    i++;
  }

  return 0;
}
Exemplo n.º 11
0
Arquivo: main.c Projeto: rcrowder/Burt
int main (void)
{
	cc3_histogram_pkt_t my_hist;
	cc3_color_info_pkt_t s_pkt;
	cc3_frame_diff_pkt_t fd_pkt;

	cc3_timer_wait_ms (500);

	cc3_gpio_set_mode (0, CC3_GPIO_MODE_SERVO);
	cc3_gpio_set_mode (1, CC3_GPIO_MODE_SERVO);
	cc3_gpio_set_mode (2, CC3_GPIO_MODE_SERVO);
	cc3_gpio_set_mode (3, CC3_GPIO_MODE_SERVO);

	// configure uarts
	cc3_uart_init (0, 
		CC3_UART_RATE_115200, 
		CC3_UART_MODE_8N1,
		CC3_UART_BINMODE_TEXT);

	cc3_uart_init (1, 
		CC3_UART_RATE_38400,//CC3_UART_RATE_115200, 
		CC3_UART_MODE_8N1,
		CC3_UART_BINMODE_BINARY);

	// Make it so that stdout and stdin are not buffered
	setvbuf (stdout, NULL, _IONBF, 0);
	setvbuf (stdin, NULL, _IONBF, 0);

	printf( "Opening UART1 file pointer\n" );
	FILE *fp = cc3_uart_fopen(1, "r");
	if (fp)
	{
		printf("Success");
		int i = 0;
		while (1)
		{
			fprintf(fp, "i = %08d\n", i++);
		}
	}

	printf( "Calling camera init\n" );
	cc3_camera_init ();
	cc3_camera_set_colorspace (CAM_COLOURS);
	cc3_camera_set_resolution (CAM_FORMAT);
	cc3_pixbuf_frame_set_coi (CC3_CHANNEL_ALL);//for full 'colour_info'

	//cc3_camera_set_colorspace (CC3_COLORSPACE_YCRCB);?All switches handled?
	//cc3_camera_set_resolution (CC3_CAMERA_RESOLUTION_HIGH);// 352, 288
	//cc3_pixbuf_frame_set_subsample(CC3_SUBSAMPLE_RANDOM, 2, 2);

	printf( "Camera init done\n%d x %d\n", 
		cc3_g_pixbuf_frame.raw_width, cc3_g_pixbuf_frame.raw_height );

	// frame difference
	fd_pkt.coi = CC3_CHANNEL_ALL;
	fd_pkt.template_width = 16;//8;
	fd_pkt.template_height = 16;//8;
	fd_pkt.total_x = cc3_g_pixbuf_frame.width;
    fd_pkt.total_y = cc3_g_pixbuf_frame.height;
    fd_pkt.load_frame = 1;  // load a new frame

	fd_pkt.previous_template = malloc (fd_pkt.template_width * fd_pkt.template_height * sizeof (uint32_t));
	if (fd_pkt.previous_template == NULL)
		printf ("Malloc FD startup error!\r");

	cc3_camera_set_auto_white_balance (true);
	cc3_camera_set_auto_exposure (true);

	// The LED test masks the stabilization delays (~2000ms)
	printf ("Waiting for image to stabilize\n");
	led_test ();

	cc3_camera_set_auto_white_balance (false);
	cc3_camera_set_auto_exposure (false);

//	printf ("\nPush button on camera back to continue\n");
//	while (!cc3_button_get_state ())
//		;

	cc3_led_set_state (0, true);

	cc3_pixbuf_load ();

	my_hist.channel = CC3_CHANNEL_ALL;
	my_hist.bins = 24;
	my_hist.hist = malloc (my_hist.bins * sizeof (uint32_t));

	while (true) {
		
        printf ("<3 EE\n   0x%02X\n   ", (unsigned int)cc3_timer_get_current_ms());

		// Grab an image and take a frame difference of it
		cc3_pixbuf_load ();
        frame_diff (&fd_pkt);

		// Rewind and take a histogram of it
		cc3_pixbuf_rewind ();
		//get_histogram (&my_hist);

		// Rewind and get some stats
		cc3_pixbuf_rewind ();
		get_mean(&s_pkt);

		printf( "min = [%d,%d,%d] mean = [%d,%d,%d] max = [%d,%d,%d] deviation = [%d,%d,%d] ",
				s_pkt.min.channel[0],s_pkt.min.channel[1],s_pkt.min.channel[2],
				s_pkt.mean.channel[0],s_pkt.mean.channel[1],s_pkt.mean.channel[2],
				s_pkt.max.channel[0],s_pkt.max.channel[1],s_pkt.max.channel[2],
				s_pkt.deviation.channel[0],s_pkt.deviation.channel[1],s_pkt.deviation.channel[2]
				);

/*		printf ("hist[%d] = ", my_hist.bins);
		for (uint32_t i = 0; i < my_hist.bins; i++)
		{
			printf ("%08X ", my_hist.hist[i]);

			// sample non-blocking serial routine
			if (!cc3_uart_has_data (1))
			{
				cc3_gpio_set_servo_position (0, SERVO_MID);
				cc3_gpio_set_servo_position (1, SERVO_MID);
			}
		}
*/
		printf ("\n");
		cc3_timer_wait_ms(400);

	//	if (cc3_button_get_state())
	//		break;
	}

	printf("\n\nAll done!\n");
	return 0;
}
Exemplo n.º 12
0
Arquivo: main.c Projeto: rcrowder/Burt
void led_test (void)
{
	for (int i = 0; i < 8; i++)
	{
		if (i & 1) {
			cc3_led_set_state(0, true);
		} else {
			cc3_led_set_state(0, false);
		}

		if (i & 2) {
			cc3_led_set_state(1, true);
		} else {
			cc3_led_set_state(1, false);
		}

		if (i & 4) {
			cc3_led_set_state(2, true);
		} else {
			cc3_led_set_state(2, false);
		}

		cc3_timer_wait_ms(200);
	}

	cc3_led_set_state (0, true);
	cc3_led_set_state (1, true);
	cc3_led_set_state (2, true);
	cc3_timer_wait_ms(400);

	cc3_led_set_state (0, false);
	cc3_led_set_state (1, false);
	cc3_led_set_state (2, false);
	cc3_timer_wait_ms(400);

}
Exemplo n.º 13
0
/* simple hello world, showing features and compiling*/
int main (void)
{
  uint32_t start_time, end_time, val;
  char c;
  FILE *fp;
  cc3_image_t img;

  // init filesystem driver
  cc3_filesystem_init ();

  // configure uarts
  cc3_uart_init (0, CC3_UART_RATE_115200, CC3_UART_MODE_8N1,
                 CC3_UART_BINMODE_TEXT);
  // Make it so that stdout and stdin are not buffered
  val = setvbuf (stdout, NULL, _IONBF, 0);
  val = setvbuf (stdin, NULL, _IONBF, 0);

  printf( "Calling camera init\n" );
  cc3_camera_init ();
  printf( "Camera init done\n" );

  cc3_camera_set_colorspace (CC3_COLORSPACE_RGB);
  cc3_camera_set_resolution (CC3_CAMERA_RESOLUTION_LOW);
  cc3_camera_set_auto_white_balance (true);
  cc3_camera_set_auto_exposure (true);

  printf ("Hello World...\n");

  cc3_led_set_state (0, false);
  cc3_led_set_state (1, false);
  cc3_led_set_state (2, false);

  // sample wait command in ms
  cc3_timer_wait_ms (1000);
  cc3_led_set_state (0, true);


  // sample showing how to write to the MMC card
  printf ("Type y to test MMC card, type n if you do not have the card\n");
  c = getchar ();
  if (c == 'y' || c == 'Y') {
    int result;
    printf ("\nMMC test...\n");
    fp = fopen ("c:/test.txt", "w");
    if (fp == NULL) {
      perror ("fopen failed");
    }
    fprintf (fp, "This will be written to the MMC...\n");

    result = fclose (fp);
    if (result == EOF) {
      perror ("fclose failed");
    }
    printf ("A string was written to test.txt on the mmc card.\n");
  }

  // sample showing how to read button
  printf ("push button on camera back to continue\n");
  start_time = cc3_timer_get_current_ms ();
  while (!cc3_button_get_state ());
  cc3_led_set_state (1, true);
  // sample showing how to use timer
  printf ("It took you %dms to press the button\n",
          cc3_timer_get_current_ms () - start_time);



  // setup an image structure
  cc3_pixbuf_load ();
  img.channels = 3;
  img.width = cc3_g_pixbuf_frame.width;
  img.height = 1;               // image will hold just 1 row for scanline processing
  img.pix = cc3_malloc_rows (1);

  printf ("Now we will use image data...\n");
  val = 0;
  /*
   * Track the brightest red spot on the image
   */
  while (1) {
    int y;
    uint16_t my_x, my_y;
    uint8_t max_red;
    cc3_pixel_t my_pix;

    if (val & 0x1)
      cc3_led_set_state (0, true);
    else
      cc3_led_set_state (0, false);
    if (val & 0x2)
      cc3_led_set_state (1, true);
    else
      cc3_led_set_state (1, false);
    if (val & 0x3)
      cc3_led_set_state (2, true);
    else
      cc3_led_set_state (2, false);
    if (val & 0x4)
      cc3_led_set_state (3, true);
    else
      cc3_led_set_state (3, false);
    val++;

    // This tells the camera to grab a new frame into the fifo and reset
    // any internal location information.
    cc3_pixbuf_frame_set_coi(CC3_CHANNEL_ALL);
    cc3_pixbuf_load ();


    // red search!

    // *** slow method for red search
    start_time = cc3_timer_get_current_ms();
    max_red = 0;
    my_x = 0;
    my_y = 0;
    y = 0;
    while (cc3_pixbuf_read_rows (img.pix, 1)) {
      // read a row into the image picture memory from the camera
      for (uint16_t x = 0; x < img.width; x++) {
        // get a pixel from the img row memory
        cc3_get_pixel (&img, x, 0, &my_pix);
        if (my_pix.channel[CC3_CHANNEL_RED] > max_red) {
          max_red = my_pix.channel[CC3_CHANNEL_RED];
          my_x = x;
          my_y = y;
        }
      }
      y++;
    }
    end_time = cc3_timer_get_current_ms();

    printf ("Found max red value %d at %d, %d\n", max_red, my_x, my_y);
    printf (" cc3_get_pixel version took %d ms to complete\n",
	    end_time - start_time);

    // *** faster method for red search
    cc3_pixbuf_rewind();  // use exactly the same pixbuf contents
    start_time = cc3_timer_get_current_ms();
    max_red = 0;
    my_x = 0;
    my_y = 0;
    y = 0;
    while (cc3_pixbuf_read_rows (img.pix, 1)) {
      // read a row into the image picture memory from the camera
      for (uint16_t x = 0; x < img.width * 3; x+=3) {
	uint8_t red = ((uint8_t *) img.pix)[x + CC3_CHANNEL_RED];
        if (red > max_red) {
          max_red = red;
          my_x = x;
          my_y = y;
        }
      }
      y++;
    }
    my_x /= 3; // correct channel offset
    end_time = cc3_timer_get_current_ms();

    printf ("Found max red value %d at %d, %d\n", max_red, my_x, my_y);
    printf (" faster version took %d ms to complete\n",
	    end_time - start_time);

    // *** even faster method for red search
    cc3_pixbuf_rewind();  // use exactly the same pixbuf contents
    cc3_pixbuf_frame_set_coi(CC3_CHANNEL_RED);
    start_time = cc3_timer_get_current_ms();
    max_red = 0;
    my_x = 0;
    my_y = 0;
    y = 0;
    while (cc3_pixbuf_read_rows (img.pix, 1)) {
      // read a row into the image picture memory from the camera
      for (uint16_t x = 0; x < img.width; x++) {
	uint8_t red = ((uint8_t *) img.pix)[x];
        if (red > max_red) {
          max_red = red;
          my_x = x;
          my_y = y;
        }
      }
      y++;
    }
    end_time = cc3_timer_get_current_ms();

    printf ("Found max red value %d at %d, %d\n", max_red, my_x, my_y);
    printf (" even faster version took %d ms to complete\n",
	    end_time - start_time);

    printf("\n");
    // sample non-blocking serial routine
    if (!cc3_uart_has_data (0))
      break;
  }
  free (img.pix);               // don't forget to free!
  printf ("You pressed %c to escape\n", fgetc (stdin));

  // stdio actually works...
  printf ("Type in a number followed by return to test scanf: ");
  scanf ("%d", &val);
  printf ("You typed %d\n", val);

  printf ("Good work, now try something on your own...\n");
  while (1);

  return 0;
}