/*******************************************************************************
* PRIVATE FUNCTION: test_uart1a
*
* PARAMETERS:
* ~ void
*
* RETURN:
* ~ void
*
* DESCRIPTIONS:
* Test the UART1 Alternative.
*
*******************************************************************************/
void test_uart1a(void)
{	
	unsigned char i = 0;
	while (SW1==1) // Loop until SW1 is press
	{
	lcd_clear();
	lcd_putstr("SW1 test UART1A\nConnect UC00A");	
	for (i = 0; i < 50; i++)
		{
		if(SW1 == 0) break;			
		delay_ms(30);		
		}
	
	lcd_clear();
	lcd_putstr("TX Selector=TX1A\nRX Selector=RX1A");	
	for (i = 0; i < 50; i++) 
		{	
		if(SW1 == 0) break;			
		delay_ms(30);		
		}
	lcd_clear();
	lcd_putstr(arr_hyperterminal);	
	for (i = 0; i < 50; i++) 
		{	
		if(SW1 == 0) break;			
		delay_ms(30);		
		}
	}//while (SW1 == 1)	
		
	while(SW1==0); //wait for SW1 to be release
	
	uart1a_initialize();	// initialize UART1A
	lcd_clear();
	lcd_putstr(arr_enter);	
	
	// Sending message to the PC through UART1
	uart1_transmit(0x0C);	//clear HyperTerminal
	uart1_putstr(arr_thanks);
	uart1_putstr("\r\n\nDemo UART1 Alternative on SKds40A...\r\n");
	uart1_putstr(arr_keyboard);
	uart1_putstr(arr_echo);
	uart1_putstr(arr_enter_keyboard);
	
	do {
		c_received_data = uc_uart1_receive();	//echo what is received
		LED1 = ~LED1;		// toggle LED 1
		uart1_transmit(c_received_data);
	}
	while (c_received_data != '\r' && c_received_data != '\n');	
	
	// Sending message to the PC.
	uart1_putstr("\r\n\nUART1 Alternative Demo Completed.\r\n");
	LED1 = 0;	
	beep(2);	
	lcd_clear();
	lcd_putstr("UART1 Alternative\nPass!");	
	delay_ms(500);	
}
/*******************************************************************************
* PRIVATE FUNCTION: test_uart1a
*
* PARAMETERS:
* ~ void
*
* RETURN:
* ~ void
*
* DESCRIPTIONS:
* Test the UART1 Alternative.
*
*******************************************************************************/
void test_uart1a(void)
{	
	unsigned char i = 0;
	while (SW1==1) // Loop until SW1 is press
	{
	lcd_clear();
	lcd_putstr("SW1 test UART1A\nConnect UC00A");	
	for (i = 0; i < 50; i++)
		{
		if(SW1 == 0) break;			
		delay_ms(30);		
		}
	
	lcd_clear();
	lcd_putstr("TX Selector=TX1A\nRX Selector=RX1A");	
	for (i = 0; i < 50; i++) 
		{	
		if(SW1 == 0) break;			
		delay_ms(30);		
		}
	lcd_clear();
	lcd_putstr("HyperTerminal\n9600, 8, N, 1");	
	for (i = 0; i < 50; i++) 
		{	
		if(SW1 == 0) break;			
		delay_ms(30);		
		}
	}//while (SW1 == 1)	
		
	while(SW1==0); //wait for SW1 to be release
	
	uart1a_initialize();	// initialize UART1A
	lcd_clear();
	lcd_putstr("Press enter on\nkeyboard to exit");	
	
	// Sending message to the PC through UART1
	uart1_transmit(0x0C);	//clear HyperTerminal
	uart1_putstr("\r\n\nThanks for using Cytron Technologies product\r\n");
	uart1_putstr("\r\n\nDemo UART1 Alternative on SKds40A...\r\n");
	uart1_putstr("Press any key on keyboard to demo.\r\n");
	uart1_putstr("It will be echo back to HyperTerminal.\r\n");
	uart1_putstr("Press enter to exit.\r\n\n");
	
	do {
		c_received_data = uc_uart1_receive();	//echo what is received
		LED1 = ~LED1;		// toggle LED 1
		uart1_transmit(c_received_data);
	}
	while (c_received_data != '\r' && c_received_data != '\n');	
	
	// Sending message to the PC.
	uart1_putstr("\r\n\nUART1 Alternative Demo Completed.\r\n");
	LED1 = 0;	
	beep(2);	
	lcd_clear();
	lcd_putstr("UART1 Alternative\nPass!");	
	delay_ms(500);	
}
/*******************************************************************************
* PUBLIC FUNCTION: uart1_putstr
*
* PARAMETERS:
* ~ csz_string	- The null terminated string to transmit.
*
* RETURN:
* ~ void
*
* DESCRIPTIONS:
* Transmit a string using the UART1.
*
*******************************************************************************/
void uart1_putstr(const char* csz_string)
{
	// Loop until the end of string.
	while (*csz_string != '\0') {
		uart1_transmit(*csz_string);
			
		// Point to next character.
		csz_string++;
	}
}
/**
 * @brief Receive communication packets and handle them
 *
 * This function decodes packets on the protocol level and also handles
 * their value by calling the appropriate functions.
 */
void communication_receive(void)
{
	mavlink_message_t msg;
	mavlink_status_t status =
	{ 0 };
	status.packet_rx_drop_count = 0;

	// COMMUNICATION WITH ONBOARD COMPUTER

	while (uart0_char_available())
	{
		uint8_t c = uart0_get_char();


		if (global_data.state.uart0mode == UART_MODE_MAVLINK)
		{
			// Try to get a new message
			if (mavlink_parse_char(MAVLINK_COMM_0, c, &msg, &status))
			{
				// Handle message
				handle_mavlink_message(MAVLINK_COMM_0, &msg);
			}
		}
		else if (global_data.state.uart0mode == UART_MODE_BYTE_FORWARD)
		{
			uart1_transmit(c);
		}
		// And get the next one
	}

	// Update global packet drops counter
	global_data.comm.uart0_rx_drop_count += status.packet_rx_drop_count;
	global_data.comm.uart0_rx_success_count += status.packet_rx_success_count;
	status.packet_rx_drop_count = 0;

	// COMMUNICATION WITH EXTERNAL COMPUTER

	while (uart1_char_available())
	{
		uint8_t c = uart1_get_char();

		// Check if this link is used for MAVLink or GPS
		if (global_data.state.uart1mode == UART_MODE_MAVLINK)
		{
			//uart0_transmit((unsigned char)c);
			// Try to get a new message
			if (mavlink_parse_char(MAVLINK_COMM_1, c, &msg, &status))
			{
				// Handle message
				handle_mavlink_message(MAVLINK_COMM_1, &msg);
			}
		}
		else if (global_data.state.uart1mode == UART_MODE_GPS)
		{
			if (global_data.state.gps_mode == 10)
			{
				static uint8_t gps_i = 0;
				static char gps_chars[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN];
				if (c == '$' || gps_i == MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN
						- 1)
				{
					gps_i = 0;
					char gps_chars_buf[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN];
					strncpy(gps_chars_buf, gps_chars,
							MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN);
					debug_message_buffer(gps_chars_buf);

				}
				gps_chars[gps_i++] = c;
			}
			if (gps_parse(c))
			{
				// New GPS data received
				//debug_message_buffer("RECEIVED NEW GPS DATA");
				parse_gps_msg();

				if (gps_lat == 0)
				{
					global_data.state.gps_ok = 0;
					//debug_message_buffer("GPS Signal Lost");
				}
				else
				{
					global_data.state.gps_ok = 1;

					mavlink_msg_gps_raw_send(
							global_data.param[PARAM_SEND_DEBUGCHAN],
							sys_time_clock_get_unix_time(), gps_mode, gps_lat
									/ 1e7f, gps_lon / 1e7f, gps_alt / 100.0f,
							0.0f, 0.0f, gps_gspeed / 100.0f, gps_course / 10.0f);
				}
				//				// Output satellite info
				//				for (int i = 0; i < gps_nb_channels; i++)
				//				{
				//					mavlink_msg_gps_status_send(global_data.param[PARAM_SEND_DEBUGCHAN], gps_numSV, gps_svinfos[i].svid, gps_satellite_used(gps_svinfos[i].qi), gps_svinfos[i].elev, ((gps_svinfos[i].azim/360.0f)*255.0f), gps_svinfos[i].cno);
				//				}
			}

		}
		else if (global_data.state.uart1mode == UART_MODE_BYTE_FORWARD)
		{
			uart0_transmit(c);
			led_toggle(LED_YELLOW);
		}
		// And get the next one
	}

	// Update global packet drops counter
	global_data.comm.uart0_rx_drop_count += status.packet_rx_drop_count;
	global_data.comm.uart0_rx_success_count += status.packet_rx_success_count;
	status.packet_rx_drop_count = 0;
}
//@{
void handle_mavlink_message(mavlink_channel_t chan,
		mavlink_message_t* msg)
{
	uint8_t buf[MAVLINK_MAX_PACKET_LEN];
	uint32_t len;
	switch (chan)
	{
	case MAVLINK_COMM_0:
	{
		if (msg->msgid != MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE)
		{
			// Copy to COMM 1
			len = mavlink_msg_to_send_buffer(buf, msg);
			for (int i = 0; i < len; i++)
			{
				uart1_transmit(buf[i]);
			}
		}
	}
	break;
	case MAVLINK_COMM_1:
	{
		if (msg->msgid != MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE && msg->msgid != MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE)
		{
			// Copy to COMM 0
			len = mavlink_msg_to_send_buffer(buf, msg);
			for (int i = 0; i < len; i++)
			{
				uart0_transmit(buf[i]);
			}
			break;
		}
	}
	default:
		break;
	}


	switch (msg->msgid)
	{
	case MAVLINK_MSG_ID_SET_MODE:
	{
		mavlink_set_mode_t mode;
		mavlink_msg_set_mode_decode(msg, &mode);
		// Check if this system should change the mode
		if (mode.target == (uint8_t)global_data.param[PARAM_SYSTEM_ID])
		{
			sys_set_mode(mode.mode);

			// Emit current mode
			mavlink_msg_sys_status_send(MAVLINK_COMM_0, global_data.state.mav_mode, global_data.state.nav_mode,
					global_data.state.status, global_data.cpu_usage, global_data.battery_voltage,
					global_data.motor_block, communication_get_uart_drop_rate());
			mavlink_msg_sys_status_send(MAVLINK_COMM_1, global_data.state.mav_mode, global_data.state.nav_mode,
					global_data.state.status, global_data.cpu_usage, global_data.battery_voltage,
					global_data.motor_block, communication_get_uart_drop_rate());

		}
	}
	break;
	case MAVLINK_MSG_ID_ACTION:
	{
		execute_action(mavlink_msg_action_get_action(msg));

		//Forwart actions from Xbee to Onboard Computer and vice versa
		if (chan == MAVLINK_COMM_1)
		{
			mavlink_send_uart(MAVLINK_COMM_0, msg);
		}
		else if (chan == MAVLINK_COMM_0)
		{
			mavlink_send_uart(MAVLINK_COMM_1, msg);
		}
	}
	break;
	case MAVLINK_MSG_ID_SYSTEM_TIME:
	{
		if (!sys_time_clock_get_unix_offset())
		{
			int64_t offset = ((int64_t) mavlink_msg_system_time_get_time_usec(
					msg)) - (int64_t) sys_time_clock_get_time_usec();
			sys_time_clock_set_unix_offset(offset);

			debug_message_buffer("UNIX offset updated");
		}
		else
		{

			//			debug_message_buffer("UNIX offset REFUSED");
		}
	}
	break;
	case MAVLINK_MSG_ID_REQUEST_DATA_STREAM:
	{
		mavlink_request_data_stream_t stream;
		mavlink_msg_request_data_stream_decode(msg, &stream);
		switch (stream.req_stream_id)
		{
		case 0: // UNIMPLEMENTED
			break;
		case 1: // RAW SENSOR DATA
			global_data.param[PARAM_SEND_SLOT_RAW_IMU] = stream.start_stop;
			break;
		case 2: // EXTENDED SYSTEM STATUS
			global_data.param[PARAM_SEND_SLOT_ATTITUDE] = stream.start_stop;
			break;
		case 3: // REMOTE CONTROL CHANNELS
			global_data.param[PARAM_SEND_SLOT_REMOTE_CONTROL] = stream.start_stop;
			break;
		case 4: // RAW CONTROLLER
			//global_data.param[PARAM_SEND_SLOT_DEBUG_5] = stream.start_stop;
			//global_data.param[PARAM_SEND_SLOT_DEBUG_3] = stream.start_stop;
			global_data.param[PARAM_SEND_SLOT_CONTROLLER_OUTPUT] = stream.start_stop;
			break;
		case 5: // SENSOR FUSION

			//LOST IN GROUDNCONTROL
			//			global_data.param[PARAM_SEND_SLOT_DEBUG_5] = stream.start_stop;
			break;
		case 6: // POSITION
			global_data.param[PARAM_SEND_SLOT_DEBUG_5] = stream.start_stop;
			break;
		case 7: // EXTRA1
			global_data.param[PARAM_SEND_SLOT_DEBUG_2] = stream.start_stop;
			break;
		case 8: // EXTRA2
			global_data.param[PARAM_SEND_SLOT_DEBUG_4] = stream.start_stop;
			break;
		case 9: // EXTRA3
			global_data.param[PARAM_SEND_SLOT_DEBUG_6] = stream.start_stop;
			break;
		default:
			// Do nothing
			break;
		}
	}
	break;
	case MAVLINK_MSG_ID_PARAM_REQUEST_READ:
	{
		mavlink_param_request_read_t set;
		mavlink_msg_param_request_read_decode(msg, &set);

		// Check if this message is for this system
		if ((uint8_t) set.target_system
				== (uint8_t) global_data.param[PARAM_SYSTEM_ID]
				                               && (uint8_t) set.target_component
				                               == (uint8_t) global_data.param[PARAM_COMPONENT_ID])
		{
			char* key = (char*) set.param_id;

			if (set.param_id[0] == '\0')
			{
				// Choose parameter based on index
				if (set.param_index < ONBOARD_PARAM_COUNT)
				{
					// Report back value
					mavlink_msg_param_value_send(chan,
							(int8_t*) global_data.param_name[set.param_index],
							global_data.param[set.param_index], ONBOARD_PARAM_COUNT, set.param_index);
				}
			}
			else
			{
				for (int i = 0; i < ONBOARD_PARAM_COUNT; i++)
				{
					bool match = true;
					for (int j = 0; j < ONBOARD_PARAM_NAME_LENGTH; j++)
					{
						// Compare
						if (((char) (global_data.param_name[i][j]))
								!= (char) (key[j]))
						{
							match = false;
						}

						// End matching if null termination is reached
						if (((char) global_data.param_name[i][j]) == '\0')
						{
							break;
						}
					}

					// Check if matched
					if (match)
					{
						// Report back value
						mavlink_msg_param_value_send(chan,
								(int8_t*) global_data.param_name[i],
								global_data.param[i], ONBOARD_PARAM_COUNT, m_parameter_i);
					}
				}
			}
		}
	}
	break;
	case MAVLINK_MSG_ID_PARAM_REQUEST_LIST:
	{
		// Start sending parameters
		m_parameter_i = 0;
	}
	break;
	case MAVLINK_MSG_ID_PARAM_SET:
	{
		mavlink_param_set_t set;
		mavlink_msg_param_set_decode(msg, &set);

		// Check if this message is for this system
		if ((uint8_t) set.target_system
				== (uint8_t) global_data.param[PARAM_SYSTEM_ID]
				                               && (uint8_t) set.target_component
				                               == (uint8_t) global_data.param[PARAM_COMPONENT_ID])
		{
			char* key = (char*) set.param_id;

			for (int i = 0; i < ONBOARD_PARAM_COUNT; i++)
			{
				bool match = true;
				for (int j = 0; j < ONBOARD_PARAM_NAME_LENGTH; j++)
				{
					// Compare
					if (((char) (global_data.param_name[i][j]))
							!= (char) (key[j]))
					{
						match = false;
					}

					// End matching if null termination is reached
					if (((char) global_data.param_name[i][j]) == '\0')
					{
						break;
					}
				}

				// Check if matched
				if (match)
				{
					// Only write and emit changes if there is actually a difference
					// AND only write if new value is NOT "not-a-number"
					// AND is NOT infy
					if (global_data.param[i] != set.param_value
							&& !isnan(set.param_value)
							&& !isinf(set.param_value))
					{
						global_data.param[i] = set.param_value;
						// Report back new value
						mavlink_msg_param_value_send(MAVLINK_COMM_0,
								(int8_t*) global_data.param_name[i],
								global_data.param[i], ONBOARD_PARAM_COUNT, m_parameter_i);
						mavlink_msg_param_value_send(MAVLINK_COMM_1,
								(int8_t*) global_data.param_name[i],
								global_data.param[i], ONBOARD_PARAM_COUNT, m_parameter_i);

						debug_message_buffer_sprintf("Parameter received param id=%i",i);
					}
				}
			}
		}
	}
	break;
	case MAVLINK_MSG_ID_POSITION_CONTROL_SETPOINT_SET:
	{
		mavlink_position_control_setpoint_set_t pos;
		mavlink_msg_position_control_setpoint_set_decode(msg, &pos);
		if (global_data.param[PARAM_POSITIONSETPOINT_ACCEPT] == 1)
		{
			//			global_data.position_setpoint.x = pos.x;
			//			global_data.position_setpoint.y = pos.y;
			//			global_data.position_setpoint.z = pos.z;
			debug_message_buffer("Position setpoint updated. OLD?\n");
		}
		else
		{
			debug_message_buffer(
					"Position setpoint recieved but not updated. OLD?\n");
		}

		// Send back a message confirming the new position
		mavlink_msg_position_control_setpoint_send(MAVLINK_COMM_0, pos.id,
				pos.x, pos.y, pos.z, pos.yaw);
		mavlink_msg_position_control_setpoint_send(MAVLINK_COMM_1, pos.id,
				pos.x, pos.y, pos.z, pos.yaw);
	}
	break;
	case MAVLINK_MSG_ID_POSITION_CONTROL_OFFSET_SET:
	{
		mavlink_position_control_offset_set_t set;
		mavlink_msg_position_control_offset_set_decode(msg, &set);
		//global_data.attitude_setpoint_pos_body_offset.z = set.yaw;

		//Ball Tracking
		if (global_data.param[PARAM_POSITIONSETPOINT_ACCEPT] == 1 && global_data.param[PARAM_POSITION_YAW_TRACKING]==1)
		{
			global_data.param[PARAM_POSITION_SETPOINT_YAW]
			                  = global_data.attitude.z + set.yaw;

			mavlink_msg_debug_send(global_data.param[PARAM_SEND_DEBUGCHAN], 92, set.yaw);
		}
	}
	break;
	case MAVLINK_MSG_ID_SET_CAM_SHUTTER:
	{
		// Decode the desired shutter
		mavlink_set_cam_shutter_t cam;
		mavlink_msg_set_cam_shutter_decode(msg, &cam);
		shutter_set(cam.interval, cam.exposure);
		debug_message_buffer_sprintf("set_cam_shutter. interval %i",
				cam.interval);

	}
	break;
	case MAVLINK_MSG_ID_IMAGE_TRIGGER_CONTROL:
	{
		uint8_t enable = mavlink_msg_image_trigger_control_get_enable(msg);
		shutter_control(enable);
		if (enable)
		{
			debug_message_buffer("CAM: Enabling hardware trigger");
		}
		else
		{
			debug_message_buffer("CAM: Disabling hardware trigger");
		}
	}
	break;
	case MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE:
	{
		mavlink_vision_position_estimate_t pos;
		mavlink_msg_vision_position_estimate_decode(msg, &pos);

		vision_buffer_handle_data(&pos);
		// Update validity time is done in vision buffer

	}
	break;
	case MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE:
	{
		mavlink_vicon_position_estimate_t pos;
		mavlink_msg_vicon_position_estimate_decode(msg, &pos);

		global_data.vicon_data.x = pos.x;
		global_data.vicon_data.y = pos.y;
		global_data.vicon_data.z = pos.z;
		global_data.state.vicon_new_data=1;
		// Update validity time
		global_data.vicon_last_valid = sys_time_clock_get_time_usec();
		global_data.state.vicon_ok=1;

//		//Set data from Vicon into vision filter
//		global_data.vision_data.ang.x = pos.roll;
//		global_data.vision_data.ang.y = pos.pitch;
//		global_data.vision_data.ang.z = pos.yaw;
//
//		global_data.vision_data.pos.x = pos.x;
//		global_data.vision_data.pos.y = pos.y;
//		global_data.vision_data.pos.z = pos.z;
//
//		global_data.vision_data.new_data = 1;

		if (!global_data.state.vision_ok)
		{
			//Correct YAW
			global_data.attitude.z = pos.yaw;
			//If yaw goes to infy (no idea why) set it to setpoint, next time will be better
			if (global_data.attitude.z > 18.8495559 || global_data.attitude.z
					< -18.8495559)
			{
				global_data.attitude.z = global_data.yaw_pos_setpoint;
				debug_message_buffer(
						"vicon CRITICAL FAULT yaw was bigger than 6 PI! prevented crash");
			}
		}


		//send the vicon message to UART0 with new timestamp
		mavlink_msg_vicon_position_estimate_send(MAVLINK_COMM_0, global_data.vicon_last_valid, pos.x, pos.y, pos.z, pos.roll, pos.pitch, pos.yaw);

	}
	break;
	case MAVLINK_MSG_ID_PING:
	{
		mavlink_ping_t ping;
		mavlink_msg_ping_decode(msg, &ping);
		if (ping.target_system == 0 && ping.target_component == 0)
		{
			// Respond to ping
			uint64_t r_timestamp = sys_time_clock_get_unix_time();
			mavlink_msg_ping_send(chan, ping.seq, msg->sysid, msg->compid, r_timestamp);
		}
	}
	break;
	case MAVLINK_MSG_ID_LOCAL_POSITION_SETPOINT_SET:
	{
		mavlink_local_position_setpoint_set_t sp;
		mavlink_msg_local_position_setpoint_set_decode(msg, &sp);
		if (sp.target_system == global_data.param[PARAM_SYSTEM_ID])
		{
			if (global_data.param[PARAM_POSITIONSETPOINT_ACCEPT] == 1)
			{
				if (sp.x >= global_data.position_setpoint_min.x && sp.y
						>= global_data.position_setpoint_min.y && sp.z
						>= global_data.position_setpoint_min.z && sp.x
						<= global_data.position_setpoint_max.x && sp.y
						<= global_data.position_setpoint_max.y && sp.z
						<= global_data.position_setpoint_max.z)
				{
					debug_message_buffer("Setpoint accepted and set.");
					global_data.param[PARAM_POSITION_SETPOINT_X] = sp.x;
					global_data.param[PARAM_POSITION_SETPOINT_Y] = sp.y;
					global_data.param[PARAM_POSITION_SETPOINT_Z] = sp.z;

					if (global_data.param[PARAM_POSITION_YAW_TRACKING] == 0)
					{
						// Only update yaw if we are not tracking ball.
						global_data.param[PARAM_POSITION_SETPOINT_YAW] = sp.yaw;
					}

					//check if we want to start or land
					if (global_data.state.status == MAV_STATE_ACTIVE
							|| global_data.state.status == MAV_STATE_CRITICAL)
					{
						if (sp.z > -0.1)
						{
							if (!(global_data.state.fly == FLY_GROUNDED
									|| global_data.state.fly == FLY_SINKING
									|| global_data.state.fly
											== FLY_WAIT_LANDING
									|| global_data.state.fly == FLY_LANDING
									|| global_data.state.fly == FLY_RAMP_DOWN))
							{
								//if setpoint is lower that ground iate landing
								global_data.state.fly = FLY_SINKING;
								global_data.param[PARAM_POSITION_SETPOINT_Z]
										= -0.2;//with lowpass
								debug_message_buffer(
										"Sinking for LANDING. (z-sp lower than 10cm)");
							}
							else if (!(global_data.state.fly == FLY_GROUNDED))
							{
								global_data.param[PARAM_POSITION_SETPOINT_Z]
										= -0.2;//with lowpass
							}
						}
						else if (global_data.state.fly == FLY_GROUNDED && sp.z
								< -0.50)
						{
							//start if we were grounded and get a sp over 0.5m
							global_data.state.fly = FLY_WAIT_MOTORS;
							debug_message_buffer(
									"STARTING wait motors. (z-sp higher than 50cm)");
							//set point changed with lowpass, after 5s it will be ok.
						}
					}

					//SINK TO 0.7m if we are critical or emergency
					if (global_data.state.status == MAV_STATE_EMERGENCY
							|| global_data.state.status == MAV_STATE_CRITICAL)
					{
						global_data.param[PARAM_POSITION_SETPOINT_Z] = -0.7;//with lowpass
					}
				}
				else
				{
					debug_message_buffer("Setpoint refused. Out of range.");
				}
			}
			else
			{
				debug_message_buffer("Setpoint refused. Param setpoint accept=0.");
			}
		}
	}
	break;
	default:
		break;
	}
}
/**
* @brief This is the main loop
*
* It will be executed at maximum MCU speed (60 Mhz)
*/
void main_loop_fixed_wing(void)
{
	last_mainloop_idle = sys_time_clock_get_time_usec();
	debug_message_buffer("Starting main loop");
	while (1)
	{
		// Time Measurement
		uint64_t loop_start_time = sys_time_clock_get_time_usec();

		///////////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////////
		/// Camera Shutter
		///////////////////////////////////////////////////////////////////////////
		// Set camera shutter with 2.5ms resolution
		if (us_run_every(2500, COUNTER1, loop_start_time))
		{
			camera_shutter_handling(loop_start_time);
		}

		if (global_data.state.mav_mode == MAV_MODE_RC_TRAINING)
		{
			///////////////////////////////////////////////////////////////////////////
			/// RC INTERFACE HACK AT 50 Hz
			///////////////////////////////////////////////////////////////////////////
			if (us_run_every(20000, COUNTER8, loop_start_time))
			{
				// Write start byte
				uart1_transmit(0xFF);

				// Write channels 1-6
				for (int i = 1; i < 7; i++)
				{
					uart1_transmit((radio_control_get_channel(1)+1)*127);
				}
			}
			led_toggle(LED_GREEN);
			led_toggle(LED_RED);
			// Do not execute any of the functions below
			continue;
		}

		///////////////////////////////////////////////////////////////////////////
		/// CRITICAL 200 Hz functions
		///////////////////////////////////////////////////////////////////////////
		if (us_run_every(5000, COUNTER2, loop_start_time))
		{
			// Kalman Attitude filter, used on all systems
			gyro_read();
			sensors_read_acc();

			// Read out magnetometer at its default 50 Hz rate
			static uint8_t mag_count = 0;
			if (mag_count == 3)
			{
				sensors_read_mag();
				attitude_observer_correct_magnet(global_data.magnet_corrected);
				mag_count = 0;
			}
			else
			{
				mag_count++;
			}

			// Correction step of observer filter
			attitude_observer_correct_accel(global_data.accel_raw);

			// Write in roll and pitch
			static float_vect3 att; //if not static we have spikes in roll and pitch on bravo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			attitude_observer_get_angles(&att);
			global_data.attitude.x = att.x;
			global_data.attitude.y = att.y;
			if (global_data.param[PARAM_ATT_KAL_IYAW])
			{
				global_data.attitude.z += 0.005 * global_data.gyros_si.z;
			}
			else
			{
				global_data.attitude.z = att.z;
			}
			// Prediction step of observer
			attitude_observer_predict(global_data.gyros_si);

			control_fixed_wing_attitude();

		}
		///////////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////////
		/// CRITICAL FAST 50 Hz functions
		///////////////////////////////////////////////////////////////////////////
		else if (us_run_every(20000, COUNTER3, loop_start_time))
		{
			// Read Analog-to-Digital converter
			adc_read();
			// Read remote control
			remote_control();
		}
		///////////////////////////////////////////////////////////////////////////



		///////////////////////////////////////////////////////////////////////////
		/// NON-CRITICAL SLOW 100 Hz functions
		///////////////////////////////////////////////////////////////////////////
		else if (us_run_every(10000, COUNTER6, loop_start_time))
		{
			// Send the raw sensor/ADC values
			communication_send_raw_data(loop_start_time);
		}
		///////////////////////////////////////////////////////////////////////////



		///////////////////////////////////////////////////////////////////////////
		/// UNCRITICAL SLOW 5 Hz functions
		///////////////////////////////////////////////////////////////////////////
		else if (us_run_every(200000, COUNTER8, loop_start_time))
		{
			// The onboard controllers go into failsafe mode once
			// position data is missing
			handle_controller_timeouts(loop_start_time);
			// Send buffered data such as debug text messages
			communication_queued_send();
			// Empty one message out of the buffer
			debug_message_send_one();

			// Toggle status led
			//led_toggle(LED_YELLOW);
			led_toggle(LED_RED); // just for green LED on alpha at the moment

			// Toggle active mode led
			if (global_data.state.mav_mode == MAV_MODE_MANUAL || global_data.state.mav_mode
					== MAV_MODE_GUIDED || global_data.state.mav_mode == MAV_MODE_AUTO)
			{
				led_on(LED_GREEN);
			}
			else
			{
				led_off(LED_GREEN);
			}

			handle_eeprom_write_request();
			handle_reset_request();

			communication_send_controller_feedback();

			communication_send_remote_control();

			// Pressure sensor driver works, but not tested regarding stability
			sensors_pressure_bmp085_read_out();

			if (global_data.param[PARAM_POSITION_YAW_TRACKING] == 1)
			{
				mavlink_msg_debug_send(global_data.param[PARAM_SEND_DEBUGCHAN],
						90, global_data.param[PARAM_POSITION_SETPOINT_YAW]);
				mavlink_msg_debug_send(global_data.param[PARAM_SEND_DEBUGCHAN],
						91, global_data.yaw_pos_setpoint);
			}

		}
		///////////////////////////////////////////////////////////////////////////



		///////////////////////////////////////////////////////////////////////////
		/// NON-CRITICAL SLOW 1 Hz functions
		///////////////////////////////////////////////////////////////////////////
		else if (us_run_every(1000000, COUNTER9, loop_start_time))
		{
			// Send system state, mode, battery voltage, etc.
			send_system_state();

			if (global_data.param[PARAM_GPS_MODE] >= 10)
			{
				//Send GPS information
				float_vect3 gps;
				gps.x = gps_utm_north / 100.0f;//m
				gps.y = gps_utm_east / 100.0f;//m
				gps.z = gps_utm_zone;// gps_week;
				debug_vect("GPS", gps);
			}

			beep_on_low_voltage();

		}
		///////////////////////////////////////////////////////////////////////////




		///////////////////////////////////////////////////////////////////////////
		/// NON-CRITICAL SLOW 20 Hz functions
		///////////////////////////////////////////////////////////////////////////
		else if (us_run_every(50000, COUNTER7, loop_start_time))
		{
			led_toggle(LED_YELLOW);

			if (global_data.param[PARAM_GPS_MODE] >= 10)
			{
				//get thru all gps messages
				debug_message_send_one();
			}

			communication_send_attitude_position(loop_start_time);
		}
		///////////////////////////////////////////////////////////////////////////




		///////////////////////////////////////////////////////////////////////////
		/// NON-CRITICAL SLOW 200 Hz functions                                     //
		///////////////////////////////////////////////////////////////////////////
		else if (us_run_every(5000, COUNTER5, loop_start_time))
		{
			if (global_data.state.status == MAV_STATE_STANDBY)
			{
				//Check if parameters should be written or read
				param_handler();
			}
		}
		///////////////////////////////////////////////////////////////////////////

		else {
			// All Tasks are fine and we have no starvation
			last_mainloop_idle = loop_start_time;
		}

		// Read out comm at max rate - takes only a few microseconds in worst case
		communication_receive();

		// MCU load measurement
		uint64_t loop_stop_time = sys_time_clock_get_time_usec();
		global_data.cpu_usage = measure_avg_cpu_load(loop_start_time, loop_stop_time, min_mainloop_time);
		global_data.cpu_peak = measure_peak_cpu_load(loop_start_time, loop_stop_time, min_mainloop_time);
		if (loop_start_time - last_mainloop_idle >= 5000)
		{
			debug_message_buffer(
					"CRITICAL WARNING! CPU LOAD TO HIGH. STARVATION!");
			last_mainloop_idle = loop_start_time;//reset to prevent multiple messages
		}
		if (global_data.cpu_usage > 800)
		{
			// CPU load higher than 80%
			debug_message_buffer("CRITICAL WARNING! CPU LOAD HIGHER THAN 80%");
		}
	} // End while(1)

}