Example #1
0
int main(int argc, char *argv[])
{
#if !DISABLE_IMU
	#if SIMULATE_ALTITUDE
		#error No se puede simular altura con la IMU activada!
	#endif
#endif


   /// mensajes al usuario
#if PC_TEST
   printf("----------------------\n  WARN: Modo 'PC test' - Ver common/quadcop_config.h  \n----------------------\n");
   sleep_ms(500);
#endif
#if SIMULATE_GPS
   printf("----------------------\n  WARN: GPS simulado - Ver common/quadcop_config.h  \n----------------------\n");
   sleep_ms(500);
#endif
#if DISABLE_UAVTALK
   printf("----------------------\n  WARN: UAVTalk desabilitado - Ver common/quadcop_config.h  \n----------------------\n");
   sleep_ms(500);
#endif
#if DISABLE_IMU
   printf("----------------------\n  WARN: IMU desabilitada - Ver common/quadcop_config.h  \n----------------------\n");
   sleep_ms(500);
#endif

   /// Init socket comm
#if SOCKET_TEST
   socket_comm_init();
#endif

   int retval;
   
  
   int err_imu = 0;		//Aumenta si no hay datos nuevos de imu
   int err_count_no_data = 0; 	//si no tengo datos nuevos varias veces es peligroso
   int no_gps_data = 0;

   // Para log
   char* log_name;
   char buff_log[512]; 		//TODO determinar valor
   char buff_log_aux[512];	//TODO determinar valor
   int buff_log_len;

   bool first_time = true; // para saber cuando es la primer ejecucion del loop
   int8_t count_50 = 1; // controla tiempo de loop 100ms

   if(argc<3)
   {
	err_log("USAGE: ./auto_pilot log_name thrust_hovering");
	exit(1);
   }
   else
   {
	log_name = argv[1];
	thrust_hovering = atoi(argv[2]);
	if( thrust_hovering < 16 || thrust_hovering > 40) {
	   puts("Con este throttle dudo que hagas hovering, cerrando");
	   //exit(0);
	}
	printf("Throttle hovering: %u\n", (uint16_t) (thrust_hovering*17.41+1212.53) );
    }

    // Configurar pin de uart1 tx
#if !PC_TEST
   retval = system("echo 2 > /sys/kernel/debug/omap_mux/dss_data6");
   if (retval < 0)
   {
      err_log("system() failed - UART1 mux config");
      exit(0);
   }
#endif

   //setea senales y mascara
   set_signals();

   // Control de tiempos
   struct timeval tv_in_loop,
		  tv_out_loop, tv_out_last_loop,
                  tv_start_main,
                  tv_diff;
#if DEBUG
   struct timeval dt;
#endif

   // -- -- -- -- -- -- -- -- --
   // Inicializacion
   // -- -- -- -- -- -- -- -- --

   /// Tiempo
   set_main_start_time();
   tv_start_main = get_main_start_time(); //uquad_aux_time.h

#if SOCKET_TEST
   if (socket_comm_wait_client() == -1)
	exit(0);
#endif

   /// Path planning & Following
   // init lista path
   lista_path = (Lista_path *)malloc(sizeof(struct ListaIdentificar_path));
   inicializacion_path(lista_path);

   // init lista wp
   lista_way_point = (Lista_wp *)malloc(sizeof(struct ListaIdentificar_wp));
   inicializacion_wp(lista_way_point);
   retval = way_points_input(lista_way_point); //carga waypoints en la lista desde un archivo de texto
   if (retval < 0) {
	puts("No se pudo cargar lista de waypoints, cerrando");
	exit(0);
   }

   // Generacion de trayectoria
   path_planning(lista_way_point, lista_path);

   log_trayectoria(lista_path);    //dbg
   //visualizacion_path(lista_path); // dbg

#if SOCKET_TEST
   if (socket_comm_send_path(lista_path) == -1)
	exit(0);
#endif

   /// Control yaw
#if CONTROL_YAW_ADD_DERIVATIVE
   control_yaw_init_error_buff();
#endif

   /// Control velocidad
   // TODO

   // Se calcula el valor de pitch necesario para alcanzar la velocidad deseada.
   // El signo negativo es para que sea coherente con el sentido de giro de la cc3d (angulo positivo = giro horario)
   pitch = -atan(B_ROZ*VEL_DESIRED/MASA/G);
   //printf("pitch: %lf\n", pitch*180/M_PI); //dbg

   /// Control altura
   control_alt_init_error_buff();
   //thrust_hovering = throttle_hovering*0.0694-88.81;
   printf("Thrust hovering: %lf\n", thrust_hovering);

   /// Log
   log_fd = open(log_name, O_RDWR | O_CREAT | O_NONBLOCK );
   if(log_fd < 0)
   {
      err_log_stderr("Failed to open log file!");
      exit(0);
   }
   bool log_writeOK;

   ///GPS config - Envia comandos al gps a traves del puerto serie - //
#if !SIMULATE_GPS
   retval = preconfigure_gps();
   if(retval < 0) 
   {
      err_log("Failed to preconfigure gps!");
      exit(0);
   } 
     
   /// Ejecuta GPS daemon - proceso independiente
   gpsd_child_pid = init_gps();
   if(gpsd_child_pid == -1)
   {
      err_log_stderr("Failed to init gps!");
      exit(0);
   }
#endif //!SIMULATE_GPS

   /// Ejecuta Demonio S-BUS - proceso independiente
   sbusd_child_pid = futaba_sbus_start_daemon(); 
   if(sbusd_child_pid == -1)
   {
      err_log_stderr("Failed to start child process (sbusd)!"); 
      quit(1);  
   }

   /// inicializa kernel messages queues - para comunicacion con sbusd
   kmsgq = uquad_kmsgq_init(SERVER_KEY, DRIVER_KEY);
   if(kmsgq == NULL)
   {
      quit_log_if(ERROR_FAIL,"Failed to start message queue!");
   }

   //Doy tiempo a que inicien bien los procesos secundarios
   sleep_ms(500); //TODO verificar cuanto es necesario


   /// inicializa UAVTalk
#if !DISABLE_UAVTALK
   uavtalk_child_pid = uavtalk_parser_start(tv_start_main);
   if(uavtalk_child_pid == -1)
   {
      err_log_stderr("Failed to start child process (uavtalk)!"); 
      quit(3);  
   }
#endif

   /// init IMU
#if !DISABLE_IMU
   fd_IMU = imu_comm_init(IMU_DEVICE);
   if(fd_IMU < 0) 
   {
      err_log("Failed to init IMU!");
      quit(0);  
   } 
   //imu_data_alloc(&imu_data);
   //magn_calib_init();
   int bytes_avail = 0; // Para obener bytes disponibles en el RX buffer de IMU
#endif
   
#if !DISABLE_IMU
   // Clean IMU serial buffer
   err_log("Clearing IMU input buffer...");
   serial_flush(fd_IMU);
   sleep_ms(40);
#endif

#if !DISABLE_UAVTALK 
   retval = uavtalk_init_shm();
   if (retval < 0) {
	puts("Error al inicializar shm, cerrando");
	quit(0);
   }
#endif //!DISABLE_UAVTALK 

   printf("----------------------\n  Entrando al loop  \n----------------------\n");
   // -- -- -- -- -- -- -- -- -- 
   // Loop
   // -- -- -- -- -- -- -- -- -- 
   for(;;)
   {
	//para tener tiempo de entrada en cada loop
	gettimeofday(&tv_in_loop,NULL);
	
	//TODO Mejorar control de errores
	if(err_count_no_data > 10)
	{
	   err_log("mas de 10 errores en recepcion de datos!");
	   // TODO que hago? me quedo en hovering hasta obtener datos?
	   err_count_no_data = 0; //por ahora...
	}

#if !DISABLE_IMU
	/// Lectura de datos de la IMU
//--------------------------------------------------------------------------------------------------------
	leer_imu: // Vuelvo a leer si es necesario

	if(err_imu > 2) {
		err_log("No hay datos nuevos de IMU, cerrando.");
		quit(0);
	} 

	// Reviso si tengo una trama de datos completa antes de leer
	ioctl(fd_IMU, FIONREAD, &bytes_avail);
	if(bytes_avail < 34) {
		//puts("datos no completos IMU!"); //dbg
		sleep_ms(5);
		err_imu++;
		goto leer_imu;
	}

	IMU_readOK = check_read_locks(fd_IMU);
	if (IMU_readOK) {

            // Leo datos
	    retval = imu_comm_read(fd_IMU);            
 	    if (retval < 0 ) {
		puts("WARN: unable to read IMU data!");
	    }
            // Paso los datos del buffer RX a imu_raw.
            imu_comm_parse_frame_binary(&imu_raw);
	    //print_imu_raw(&imu_raw); // dbg

	    // Si no estoy calibrando convierto datos para usarlos
	    if (baro_calibrated) {
		imu_raw2data(&imu_raw, &imu_data);
		//print_imu_data(&imu_data); //dbg
	    }

	    imu_updated = true;
            IMU_readOK = false;
	    err_imu = 0;

        } else {
	   err_log("IMU: read NOT ok");
	}

/*	/// Reviso si quedan datos para no atrasarme
	IMU_readOK = check_read_locks(fd_IMU);
	if (IMU_readOK) {
		printf("todavia quedan datos IMU!\n");
		IMU_readOK = false;
		ioctl(fd_IMU, FIONREAD, &bytes_avail);
		//printf("%d\n ",bytes_avail);
		if(bytes_avail > 33) goto leer_imu; //continue;
	}*/

	// Reviso si tengo una trama de datos completa atrasada
	retval = ioctl(fd_IMU, FIONREAD, &bytes_avail);
	if (retval == ERROR_OK) {
		if(bytes_avail > 33) {
			//puts("todavia quedan datos IMU!"); //dbg
			goto leer_imu;
		}	
	} else puts("FIONREAD failed!");

	if (!baro_calibrated) {
		if(imu_updated) {		
			po += imu_raw.pres;
			baro_calib_cont++;
			if (baro_calib_cont == BARO_CALIB_SAMPLES) {
			   pres_calib_init(po/BARO_CALIB_SAMPLES);
			   baro_calibrated = true;
			   puts("Barometro calibrado!");
		}	}
		goto end_loop; //si estoy calibrando no hago nada mas!
	}
//--------------------------------------------------------------------------------------------------------
#endif

	/** loop 50 ms **/

#if !DISABLE_UAVTALK
	/// Leo datos de CC3D
	retval = uavtalk_read(&act);
	if(retval < 0) {
		err_log("No hay datos nuevos de actitud, cerrando.");
		quit(0);
	}
	uavtalk_updated = true;
	//uav_talk_print_attitude(act); //dbg
#endif

	// Calcula diferencia respecto a cero
	act.yaw = act.yaw - get_yaw_zero();

	++count_50; // control de loop 100ms

	/// Check stdin
	stdin_readOK = check_read_locks(STDIN_FILENO);
	if (stdin_readOK) {
	   read_from_stdin();
	}

	/** loop 100 ms **/
	if(count_50 > 1)
	{ 
#if !SIMULATE_GPS
	   /// Obener datos del GPS
	   retval = get_gps_data(&gps);
	   if (retval < 0 )
	   {  
		//que hago si NO hay datos!?
		err_log("No hay datos de gps");
	   } else {
		//que hago si SI hay datos!?
		printf("%lf\t%lf\t%lf\t%lf\t%lf\n",   \
			gps.latitude,gps.longitude,gps.altitude,gps.speed,gps.track);
		gps_updated = true;
	   }
#else //GPS SIMULADO
	   if(control_status == STARTED && !first_time)
	      gps_simulate_position(&position, &velocity, act.yaw, pitch);
	   gps_updated = true;
#endif //!SIMULATE_GPS

	   count_50 = 0;
	} /** end loop 100 ms **/


	if(control_status == STARTED)
        {
	   if (first_time)	
		first_time = false;

//#if 0
           /// Con datos de actitud hago control de yaw y path following (si tengo gps)
	   if(uavtalk_updated)
	   {

	      /// Path Follower - si hay datos de gps y de yaw hago carrot chase	      
	      if(gps_updated) {
#if !SIMULATE_GPS
	        /* guardo en waypoint p los valores de (x,y) hallados mediante el gps.
	         * primero deberia hacer convert_gps2utm(&utm, gps) y restarle la utm inicial
	         */
	         //convert_gps2waypoint(&wp, gps); // TODO no implementado!!
	         wp.angulo = act.yaw;
#else
                 wp.x = position.x;
	         wp.y = position.y;
	         wp.z = position.z;
	         wp.angulo = act.yaw;
#endif //!SIMULATE_GPS
	      
	         //carrot chase
	         retval = path_following(wp, lista_path, &yaw_d);
	         if (retval == -1) {
		     control_status = FINISHED;
		     puts("¡¡ Trayectoria finalizada !!");
		     ch_buff[THROTTLE_CH_INDEX] = THROTTLE_NEUTRAL; // detengo los motores
	         }
		 
		 no_gps_data = 0;

	      } else {
		 no_gps_data++;
		 if (no_gps_data > 1) { // Debo tener datos del gps cada 2 loops de 50 ms
		    err_count_no_data++;
		    no_gps_data = 0;
		    err_log("No tengo datos de gps para seguimiento de trayectorias");
		 }
	      }

	      /// Control Yaw - necesito solo medida de yaw
	      u_yaw = control_yaw_calc_input(yaw_d, act.yaw);
	      //printf("senal de control: %lf\n", u); // dbg

	      //Convertir velocidad en comando
	      ch_buff[YAW_CH_INDEX] = (uint16_t) (u_yaw*25/11 + 1500);
	      //printf("  %u\n", ch_buff[YAW_CH_INDEX]); // dbg

              if (err_count_no_data > 0)
	            err_count_no_data--;

	   } else {
	      err_log("No tengo datos para control de yaw");
	      err_count_no_data++;
	   }
	
	   /// Control de Velocidad
	   if(gps_updated) {
	      //TODO...

	   }
//#endif //if 0

	   /// Despegue
	   if (takeoff == 1) {
		retval = control_altitude_takeoff(&h_d);
		if (retval > 0)
		   takeoff = 0;		
	   }

	   /// Aterrizaje
	   if (takeoff == -1) {
		retval = control_altitude_land(&h_d);
		if (retval > 0) {
		   takeoff = 0;
		   //ch_buff[THROTTLE_CH_INDEX] = THROTTLE_NEUTRAL;
	    	   puts("Pronto para aterrizar!");
            	   //control_status = STOPPED;
		}	
	   }

#if SIMULATE_ALTITUDE
	   /// Control de Altura
	   u_h = control_alt_calc_input(h_d, h);
	   //U_h = u_h + 18.1485;
	   U_h = u_h + thrust_hovering + control_alt_integral(h_d, h);

	   //sim 
	   imu_simulate_altitude(&h, U_h, 0, 0);

	   //Convertir empuje en comando
	   if (U_h <= 0) {
	  	ch_buff[THROTTLE_CH_INDEX] = THROTTLE_NEUTRAL;
	   } else if (U_h > 43.6) {
	   	ch_buff[THROTTLE_CH_INDEX] = MAX_COMMAND;
	   } else {
	   	ch_buff[THROTTLE_CH_INDEX] = (uint16_t) (-0.2984*pow(U_h,2) + 26.0289*U_h + 1168.8);
	   }
	   

	   //printf("h: %lf\th_d: %lf\tu_h: %lf\tU_h: %lf\tThrot: %u\n",h,h_d,u_h,U_h,ch_buff[THROTTLE_CH_INDEX]); // dbg
#endif

#if !DISABLE_IMU
	   /// Control de Altura
	   u_h = control_alt_calc_input(h_d, imu_data.us_altitude);
	   //U_h = u_h + 18.1485;
	   U_h = u_h + thrust_hovering + control_alt_integral(h_d, imu_data.us_altitude);
	   
	   //Convertir empuje en comando
	   if (U_h <= 0) {
	  	ch_buff[THROTTLE_CH_INDEX] = THROTTLE_NEUTRAL;
	   } else if (U_h > 22) {
	   	ch_buff[THROTTLE_CH_INDEX] = (uint16_t) (17.41*U_h+1212.53);
	   } else {
	   	ch_buff[THROTTLE_CH_INDEX] = (uint16_t) (-0.2984*pow(U_h,2) + 26.0289*U_h + 1168.8);
	   }
#endif

	   // Luego de finalizados los controles reseteo flags
	   uavtalk_updated = false;
	   gps_updated = false;
	   imu_updated = false;
	
	} // end if(control_started)


	// Envia actitud y throttle deseados a sbusd (a traves de mensajes de kernel)
	retval = uquad_kmsgq_send(kmsgq, buff_out, MSGSZ);
	if(retval != ERROR_OK)
	{
	   quit_log_if(ERROR_FAIL,"Failed to send message!");
	}

#if SOCKET_TEST
       if (socket_comm_update_position(position) == -1)
	  quit(1);
#endif

	/** Log - T_s_act/T_us_act/roll/pitch/yaw/C_roll/C_pitch/C_yaw/C_throt/T_s_main/T_us_main/pos.x/pos.y/pos.z/yaw_d **/
	
	//Timestamp main
	uquad_timeval_substract(&tv_diff, tv_in_loop, tv_start_main);

	// Duracion del main
	gettimeofday(&tv_out_loop,NULL);
	uquad_timeval_substract(&dt, tv_out_loop, tv_out_last_loop);

	//datos de CC3D para log
	buff_log_len = uavtalk_to_str(buff_log, act);

	//otros logs
	buff_log_len += sprintf(buff_log_aux, "%u %u %u %u %lu %lu %lf %lf %lf %lf %lf %lf %lf",
				ch_buff[ROLL_CH_INDEX],
				ch_buff[PITCH_CH_INDEX],
				ch_buff[YAW_CH_INDEX],
				ch_buff[THROTTLE_CH_INDEX],
				tv_diff.tv_sec,
				tv_diff.tv_usec,
				position.x,
				position.y,
				position.z,
				yaw_d,
				u_yaw,
				h_d,
				U_h);

	strcat(buff_log, buff_log_aux);
	
	//datos de IMU para log
	buff_log_len += imu_to_str(buff_log_aux, imu_data);

	strcat(buff_log, buff_log_aux);

	log_writeOK = check_write_locks(log_fd);
	if (log_writeOK) {
	   retval = write(log_fd, buff_log, buff_log_len);
	   if(retval < 0)
		err_log_stderr("Failed to write to log file!");
	}

	end_loop:

/*#if DEBUG 
	// checkeo de tiempos del main
	gettimeofday(&tv_out_loop,NULL);
	retval = uquad_timeval_substract(&dt, tv_out_loop, tv_in_loop);
	if(retval > 0) {
	   if(dt.tv_usec > 50000) {
		err_log("WARN: se atraso main");
           }
	} else {
	   err_log("WARN: Main absurd timing!");
	}
#endif // DEBUG*/

	/// Control de tiempos del loop
	wait_loop_T_US(MAIN_LOOP_50_MS,tv_in_loop);

   } // for(;;)

   return 0; //nunca llego aca

} //FIN MAIN
int main(int argc, char *argv[]){
    int retval;
    char * device_imu;
    char * device_file;
    FILE * file;

    if(argc<3){
	fprintf(stderr,IO_TEST_HOW_TO);
	exit(1);
    }else{
	device_imu = argv[1];
	device_file = argv[2];
    }

    io_t * io = io_init();
    if(io==NULL){
	err_check(ERROR_FAIL,"io test failed");
    }

    // Lets add the IMU and some random file
    // The plan is to have the constant stream of data from the imu, a
    // sporadic data from the file, which would represent the diff in
    // update rate from the GPS and the IMU.

    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    /// Init
    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    // Init IMU
    imu_t * imu = imu_comm_init(device_imu);
    if(imu == NULL){
	err_check(ERROR_FAIL,"Failed to init imu");
    }

    // Init some other file
    file = fopen(device_file,"r+");
    if(file == NULL){
	err_check(ERROR_FAIL,"Failed to open file");
    }

    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    /// Register IO devices
    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    // imu
    int imu_fds;
    retval = imu_comm_get_fds(imu,& imu_fds);
    FREE_N_DIE_IF_ERROR(retval,"Failed to get imu fds!!");
    retval = io_add_dev(io,imu_fds);
    FREE_N_DIE_IF_ERROR(retval,"Failed to add imu to dev list");
    if(io->dev_list.dev_count != 1){
	FREE_N_DIE_IF_ERROR(retval,"Reg device counter error!"); 
    }
    // Pipe
    // To create a pipe, do:
    //     mknode my.pipe p
    // Then open my.pipe as a regular file.
    int file_fds;
    file_fds = fileno(file);
    retval = io_add_dev(io,file_fds);
    FREE_N_DIE_IF_ERROR(retval,"Failed to add file to dev list");
    if(io->dev_list.dev_count != 2){
	FREE_N_DIE_IF_ERROR(retval,"Reg device counter error!"); 
    }
    // stdin
    retval = io_add_dev(io,STDIN_FILENO);
    FREE_N_DIE_IF_ERROR(retval,"Failed to add STDIN to dev list");
    if(io->dev_list.dev_count != 3){
	FREE_N_DIE_IF_ERROR(retval,"Reg device counter error!"); 
    }

    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    /// Poll n read loop
    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    uquad_bool_t read = false,write = false;
    uquad_bool_t reg_imu = true, reg_pipe = true, reg_stdin = true;
    uquad_bool_t imu_ready = false;
    imu_data_t imu_data;
    unsigned char tmp_buff[2];
    int counter = 0;
    poll_n_read:
    while(1){
	retval = io_poll(io);
	FREE_N_DIE_IF_ERROR(retval,"io_poll() error");
	// imu
	if(reg_imu){
	    retval = io_dev_ready(io,imu_fds,&read,&write);
	    FREE_N_DIE_IF_ERROR(retval,"io_dev_ready() error");
	    if(read){
		retval = imu_comm_read(imu,&imu_ready);
		if(imu_ready)
		{
		    if(retval != ERROR_OK){
			fprintf(stdout,"\nIMU missed frame?\n\n");
		    }else{
			retval = imu_comm_get_data_latest_unread(imu,&imu_data);
			if(retval != ERROR_OK)
			    fprintf(stdout,"\nIMU had no data!\n\n");
		    }
		}
	    }
	}
	// pipe
	if(reg_pipe){
	    retval = io_dev_ready(io,file_fds,&read,&write);
	    FREE_N_DIE_IF_ERROR(retval,"io_dev_ready() error");
	    if(read){
		retval = fgetc(file);
		if(retval<0)
		    fprintf(stdout,"\nEOF or error!!\n\n");
		if(retval>0){
		    fprintf(stdout,"Read data from file.\n");
		}
		if(retval==0)
		    fprintf(stdout,"File had no data!.\n");
	    }
	}
	// stdin
	if(reg_stdin){
	    retval = io_dev_ready(io,STDIN_FILENO,&read,&write);
	    FREE_N_DIE_IF_ERROR(retval,"io_dev_ready() error");
	    if(read){
		retval = fread(tmp_buff,1,1,stdin);
		if(retval<=0)
		    fprintf(stdout,"\nNo user input!!\n\n");
		else
		    // Each time user presses RET a device will be removed from
		    // the registered dev list.
		    goto rm;
	    }
	}
	fflush(stdout);
    }
	
    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    /// Remove test
    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    rm:
    switch (counter){
    case 0:
	retval = io_rm_dev(io,file_fds);
	FREE_N_DIE_IF_ERROR(retval,"Failed to remove PIPE from dev list");
	fprintf(stdout,"Removed PIPE from dev list.\n");
	reg_pipe = false;
	fflush(stdout);
	break;
    case 1:
	retval = io_rm_dev(io,imu_fds);
	FREE_N_DIE_IF_ERROR(retval,"Failed to remove IMU from dev list");
	fprintf(stdout,"Removed IMU from dev list.\n");
	reg_imu = false;
	fflush(stdout);
	break;
    case 2:
	fprintf(stdout,"Removed STDIN from dev list.\n");
	retval = io_rm_dev(io,STDIN_FILENO);
	FREE_N_DIE_IF_ERROR(retval,"Failed to remove STDIN from dev list");
	reg_stdin = false;
	fflush(stdout);
	break;	
    default:
	FREE_N_DIE_IF_ERROR(ERROR_FAIL,"COUNTER out of bounds!");
	break;
    }

    if(++counter < 3)
	goto poll_n_read;

    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    /// Free everything
    /// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    kill_n_close:
    retval = io_deinit(io);
    if(retval != ERROR_OK){
	fprintf(stderr,"Warning! Failed to free io structure!\nIgnoring error...\n");
    }
    retval = imu_comm_deinit(imu);
    if(retval != ERROR_OK){
	fprintf(stderr,"Warning! Failed to free imu structure!\nIgnoring error...\n");
    }
    return 0;
}