/*************************************************************************** hardware.c - Created by Peter Mauger 03/04/01 last modified 12/10/01 hardware contains all of the functions that manipulate hardware on the eyebot. ***************************************************************************/ #include "hardware.h" /************************* Functions to manipulate the control surface structure */ /* Init_Ctrl_Surface initialises a servo and sets the limits and neutral point * inputs: ctrl_surface_name->the name of the servo you wish to initialise (servoconsts) * returns: SERVOERROR if the servo was not correctly initialised, * IDERROR if the identifier was not valid * NOERROR otherwise */ error Init_Ctrl_Surface(servoconsts ctrl_surface_name, ctrlsurface *ctrl_surface) { ctrl_surface->angle = 0; ctrl_surface->id = ctrl_surface_name; if(ctrl_surface->id == RUDDER) { ctrl_surface->max_limit = MAX_ANGLE_RUDDER; /* set the limits to those defined in planeconst.h */ ctrl_surface->min_limit = MIN_ANGLE_RUDDER; /* with neutral half way between */ ctrl_surface->neutral_point = 0; ctrl_surface->servo = SERVOInit(SERVO1); /* initialise the servo handle */ if(ctrl_surface->servo == 0) /* returns 0 if it failed */ { LCDPrintf("ServoRudd Error "); return SERVOERROR; } else return NOERROR; } else if(ctrl_surface->id == AILERON) { ctrl_surface->max_limit = MAX_ANGLE_AILERON; ctrl_surface->min_limit = MIN_ANGLE_AILERON; ctrl_surface->neutral_point = 0; ctrl_surface->servo = SERVOInit(SERVO2); if(ctrl_surface->servo == 0) { LCDPrintf("ServoAiler Error\n"); return SERVOERROR; } else return NOERROR; } else if(ctrl_surface->id == ELEVATOR) { ctrl_surface->max_limit = MAX_ANGLE_ELEVATOR; ctrl_surface->min_limit = MIN_ANGLE_ELEVATOR; ctrl_surface->neutral_point = 0; ctrl_surface->servo = SERVOInit(SERVO3); if(ctrl_surface->servo == 0) { LCDPrintf("ServoElev Error\n"); return SERVOERROR; } else return NOERROR; } else if(ctrl_surface->id == THROTTLE) { ctrl_surface->max_limit = MAX_SETTING_THROTTLE; ctrl_surface->min_limit = MIN_SETTING_THROTTLE; ctrl_surface->neutral_point = 0; ctrl_surface->servo = SERVOInit(SERVO4); if(ctrl_surface->servo == 0) { LCDPrintf("ServoThrott Error\n"); return SERVOERROR; } else return NOERROR; } else { LCDPrintf("CtrlS ID invalid"); return IDERROR; } } /* Get_Angle retrieves the angle the control surface is currently set at * inputs: ctrl_surface->structure containing the control surface info * returns: angle the surface is set to */ double Get_Angle(ctrlsurface ctrl_surface) { return ctrl_surface.angle; } /* Set_Angle sets the angle the control surface should be set to. This will be * updated to an actual servo value when Update_Servo is called. * inputs: ctrl_surface->structure containing the control surface info * angle->the angle the control surface should be set to * mode->if the mode is SET then use the absolute limits * if NORMAL then use the user defined limits * returns: LIMITERROR if the angle is outside of the servo's MAX/MIN limit, * NOERROR otherwise */ error Set_Angle(ctrlsurface *ctrl_surface, double angle, anglesetmode mode) { double max_limit = 0, min_limit = 0; if(mode == SET) { if(ctrl_surface->id == RUDDER) { max_limit = MAX_ANGLE_RUDDER; min_limit = MIN_ANGLE_RUDDER; } if(ctrl_surface->id == AILERON) { max_limit = MAX_ANGLE_AILERON; min_limit = MIN_ANGLE_AILERON; } if(ctrl_surface->id == ELEVATOR) { max_limit = MAX_ANGLE_ELEVATOR; min_limit = MIN_ANGLE_ELEVATOR; } if(ctrl_surface->id == THROTTLE) { max_limit = MAX_SETTING_THROTTLE; min_limit = MIN_SETTING_THROTTLE; } } else { max_limit = ctrl_surface->max_limit; min_limit = ctrl_surface->min_limit; } if(angle<=max_limit && angle>=min_limit) { /* make sure it's within the user set limits */ ctrl_surface->angle = angle; return NOERROR; } else return LIMITERROR; } /* Get_Servo returns the handle for the servo so that it can be manipulated * inputs: ctrl_surface->the control surface you wish to retrieve the servo from * returns: the handle of the servo that was requested. */ ServoHandle Get_Servo(ctrlsurface ctrl_surface) { return ctrl_surface.servo; } /* Get_Min_Limits returns the minimum value the servo should be set to * inputs: ctrl_surface->structure containing the control surface info * returns: the minimum limit of that servo */ double Get_Min_Limit(ctrlsurface ctrl_surface) { return ctrl_surface.min_limit; } /* Set_Min_Limits sets the minimum value the servo can be set to * inputs: ctrl_surface->structure containing the control surface info * min_limit->the minimum value the servo should be set to * returns: ABSOLUTELIMITERROR if the limit entered is lower than the possible minimum, * LIMITCROSS if the limit entered is higher than the current maximum limit, * IDERROR if the identifier was not valid * NOERROR otherwise */ error Set_Min_Limit(ctrlsurface *ctrl_surface, double min_limit) { if(ctrl_surface->id == RUDDER) { if(min_limit>=MIN_ANGLE_RUDDER) /* make sure limit is above absolute min */ { if(min_limitmax_limit && min_limitneutral_point) { /* make sure it is below the max limit and neutral */ ctrl_surface->min_limit = min_limit; } else return LIMITCROSS; } else return ABSOLUTELIMITERROR; } else if(ctrl_surface->id == AILERON) { if(min_limit>=MIN_ANGLE_AILERON) { if(min_limitmax_limit && min_limitneutral_point) { ctrl_surface->min_limit = min_limit; } else return LIMITCROSS; } else return ABSOLUTELIMITERROR; } else if(ctrl_surface->id == ELEVATOR) { if(min_limit>=MIN_ANGLE_ELEVATOR) { if(min_limitmax_limit && min_limitneutral_point) { ctrl_surface->min_limit = min_limit; } else return LIMITCROSS; } else return ABSOLUTELIMITERROR; } else if(ctrl_surface->id == THROTTLE) { if(min_limit>=MIN_SETTING_THROTTLE) { if(min_limitmax_limit && min_limitneutral_point) { ctrl_surface->min_limit = min_limit; } else return LIMITCROSS; } else return ABSOLUTELIMITERROR; } else return IDERROR; return NOERROR; } /* Get_Max_Limits returns the maximum value the servo should be set to * inputs: ctrl_surface->structure containing the control surface info * returns: the maximum limit of that servo */ double Get_Max_Limit(ctrlsurface ctrl_surface) { return ctrl_surface.max_limit; } /* Set_Max_Limit sets the maximum value the servo can be set to * inputs: ctrl_surface->structure containing the control surface info * max_limit->the maximum value the servo should be set to * returns: ABSOLUTELIMITERROR if the limit entered is higher than the possible maximum, * LIMITCROSS if the limit entered is lower than the current minimum limit, * IDERROR if the identifier was not valid * NOERROR otherwise */ error Set_Max_Limit(ctrlsurface *ctrl_surface, double max_limit) { if(ctrl_surface->id == RUDDER) { if(max_limit<=MAX_ANGLE_RUDDER) /* make sure limit is below absolute max */ { if(max_limit>ctrl_surface->min_limit && max_limit>ctrl_surface->neutral_point) { /* make sure it is above the min limit and neutral */ ctrl_surface->max_limit = max_limit; } else return LIMITCROSS; } else return ABSOLUTELIMITERROR; } else if(ctrl_surface->id == AILERON) { if(max_limit<=MAX_ANGLE_AILERON) { if(max_limit>ctrl_surface->min_limit && max_limit>ctrl_surface->neutral_point) { ctrl_surface->max_limit = max_limit; } else return LIMITCROSS; } else return ABSOLUTELIMITERROR; } else if(ctrl_surface->id == ELEVATOR) { if(max_limit<=MAX_ANGLE_ELEVATOR) { if(max_limit>ctrl_surface->min_limit && max_limit>ctrl_surface->neutral_point) { ctrl_surface->max_limit = max_limit; } else return LIMITCROSS; } else return ABSOLUTELIMITERROR; } else if(ctrl_surface->id == THROTTLE) { if(max_limit<=MAX_SETTING_THROTTLE) { if(max_limit>ctrl_surface->min_limit && max_limit>ctrl_surface->neutral_point) { ctrl_surface->max_limit = max_limit; } else return LIMITCROSS; } else return ABSOLUTELIMITERROR; } return NOERROR; } /* Get_Neutral_Point returns the neutral angle of the control surface * inputs: ctrl_surface->contains the neutral point * returns: the neutral point of the control surface */ double Get_Neutral_Point(ctrlsurface ctrl_surface) { return ctrl_surface.neutral_point; } /* Set_Neutral_Point sets the neutral point of the control surface * inputs: ctrl_surface->contains the neutral point * neutral_point->the neutral angle of the control surface * returns: LIMITERROR if the neutral point is outside of the max and min limits * NOERROR otherwise */ error Set_Neutral_Point(ctrlsurface *ctrl_surface, double neutral_point) { if(ctrl_surface->min_limit < neutral_point && neutral_point < ctrl_surface->max_limit) { /* make sure the neutral point is between the other two limits */ ctrl_surface->neutral_point = neutral_point; return NOERROR; } else return LIMITERROR; } /* Move_Ctrl_Surface_Servo reads the angle of a control surface and sets the servo * to that angle. * inputs: ctrl_surface->contains the angle and the servo handle * returns: SERVOERROR if the servo was unable to be set to that value * IDERROR if the identifier was not valid * NOERROR if the servo was set correctly */ error Move_Ctrl_Surface_Servo(ctrlsurface ctrl_surface) { int setting, servostate; error error_type; error_type = Convert_Angle2Servo(ctrl_surface, ctrl_surface.angle, &setting); /* convert the angle to a servo setting */ if(error_type == NOERROR) { servostate = SERVOSet(ctrl_surface.servo, setting); /* set the servo */ if(servostate == -1) return SERVOERROR; /* -1 means an error occured */ else return NOERROR; } else return error_type; } /* Establish_Servo_Limits sets the three limits of the control surface passed in. * inputs: ctrl_surface->contains the settings for the control surface * returns: An error indicating a problem has occured * NOERROR otherwise */ error Establish_Servo_Limits(ctrlsurface *ctrl_surface) { double angle; int setting, key; error error_type; bool valid; /*********** Set the minimum limit ***********/ LCDClear(); LCDPrintf("Minimum Limit\n"); LCDMenu("+","-","SET","END"); key = 0; angle = 0; setting = 0; angle = Get_Min_Limit(*ctrl_surface); /* get the current minimum limit */ error_type = Set_Angle(ctrl_surface, angle, SET); /* set the surface to that angle so the user can see it */ if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(*ctrl_surface); if(error_type == NOERROR) { error_type = Convert_Angle2Servo(*ctrl_surface, angle, &setting); /* determine the servo setting from the angle */ if(error_type == NOERROR) { valid = FALSE; do { do { key = 0; while(key == 0) { key = Check_Input(); } if(key == KEY1) { if((setting+5)<=255) setting+=5; /* if + was pressed increment by 5 */ } if(key == KEY2) { if((setting-5)>=0) setting-=5; /* if - was pressed decrement by 5 */ } error_type = Convert_Servo2Angle(*ctrl_surface, setting, &angle); if(error_type == NOERROR) /* convert the servo setting to an angle */ { error_type = Set_Angle(ctrl_surface, angle, SET); LCDPrintf("ang:%f\n",(float)angle); /* then set the control surface to that angle */ if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(*ctrl_surface); if(error_type != NOERROR) return error_type; } else return error_type; } else return error_type; }while(key!=KEY3 && key!=KEY4); if(key == KEY3) /* once the user has decided on a setting */ { error_type = Set_Min_Limit(ctrl_surface, angle); /* try and set the limit */ if(error_type == NOERROR) { LCDPrintf("Min Limit Set\n"); valid = TRUE; } else if(error_type == LIMITCROSS) { LCDPrintf("Min Limit > Max Limit\n"); valid = FALSE; } else { LCDPrintf("Limit Set outside of absolute\n"); valid = FALSE; } } if(key == KEY4) return NOERROR; }while(valid == FALSE); } else return error_type; } else return error_type; } /*********** Set the Neutral Point ***********/ /* this has an identical procedure to setting the minimum limit */ LCDClear(); LCDPrintf("Neutral Point\n"); LCDMenu("+","-","SET","END"); key = 0; angle = 0; setting = 0; angle = Get_Neutral_Point(*ctrl_surface); error_type = Set_Angle(ctrl_surface, angle, SET); if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(*ctrl_surface); if(error_type == NOERROR) { error_type = Convert_Angle2Servo(*ctrl_surface, angle, &setting); if(error_type == NOERROR) { valid = FALSE; do { do { key = 0; while(key == 0) { key = Check_Input(); } if(key == KEY1) { if((setting+5)<=255) setting+=5; } if(key == KEY2) { if((setting-5)>=0) setting-=5; } error_type = Convert_Servo2Angle(*ctrl_surface, setting, &angle); if(error_type == NOERROR) { error_type = Set_Angle(ctrl_surface, angle, SET); LCDPrintf("ang:%f\n",(float)angle); if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(*ctrl_surface); if(error_type != NOERROR) return error_type; } else return error_type; } else return error_type; }while(key!=KEY3 && key!=KEY4); if(key == KEY3) { error_type = Set_Neutral_Point(ctrl_surface, angle); if(error_type == NOERROR) { LCDPrintf("Neutral Point Set\n"); valid = TRUE; } else { LCDPrintf("Neutral Point set outside of limits\n"); valid = FALSE; } } if(key == KEY4) return NOERROR; }while(valid == FALSE); } else return error_type; } else return error_type; } /*********** Set the maximum limit ***********/ /* this has an identical procedure to setting the minimum limit */ LCDClear(); LCDPrintf("Maximum Limit\n"); LCDMenu("+","-","SET","END"); key = 0; angle = 0; setting = 0; angle = Get_Max_Limit(*ctrl_surface); error_type = Set_Angle(ctrl_surface, angle, SET); if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(*ctrl_surface); if(error_type == NOERROR) { error_type = Convert_Angle2Servo(*ctrl_surface, angle, &setting); if(error_type == NOERROR) { valid = FALSE; do { do { key = 0; while(key == 0) { key = Check_Input(); } if(key == KEY1) { if((setting+5)<=255) setting+=5; } if(key == KEY2) { if((setting-5)>=0) setting-=5; } error_type = Convert_Servo2Angle(*ctrl_surface, setting, &angle); if(error_type == NOERROR) { error_type = Set_Angle(ctrl_surface, angle, SET); LCDPrintf("ang:%f\n",(float)angle); if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(*ctrl_surface); if(error_type != NOERROR) return error_type; } else return error_type; } else return error_type; }while(key!=KEY3 && key!=KEY4); if(key == KEY3) { error_type = Set_Max_Limit(ctrl_surface, angle); if(error_type == NOERROR) { LCDPrintf("Max Limit Set\n"); valid = TRUE; } else if(error_type == LIMITCROSS) { LCDPrintf("Max Limit < Min Limit\n"); valid = FALSE; } else { LCDPrintf("Limit Set outside of absolute\n"); valid = FALSE; } } if(key == KEY4) return NOERROR; }while(valid == FALSE); } else return error_type; } else return error_type; } return NOERROR; } /* Convert_Servo2Angle converts a servo setting into a control surface angle * inputs: ctrl_surface->contains the limit settings * setting->the servo setting to be converted into an angle * angle->the angle that the setting was converted into * returns: IDERROR if the servo id was not recognised * NOERROR otherwise */ error Convert_Servo2Angle(ctrlsurface ctrl_surface, int setting, double *angle) { double ratio; double d_setting = (setting/255.0); /* first find the ratio of the value*/ if(ctrl_surface.id == RUDDER) /* between 0 and 255 */ { ratio = d_setting*(MAX_ANGLE_RUDDER - MIN_ANGLE_RUDDER); /* multiply by the total angle difference between the 0 and 255 settings */ *angle = ratio + MIN_ANGLE_RUDDER; /* then shift it by the 0 value angle */ return NOERROR; } else if(ctrl_surface.id == AILERON) { ratio = d_setting*(MAX_ANGLE_AILERON - MIN_ANGLE_AILERON); *angle = ratio + MIN_ANGLE_AILERON; return NOERROR; } else if(ctrl_surface.id == ELEVATOR) { ratio = d_setting*(MAX_ANGLE_ELEVATOR - MIN_ANGLE_ELEVATOR); *angle = ratio + MIN_ANGLE_ELEVATOR; return NOERROR; } else if(ctrl_surface.id == THROTTLE) { ratio = d_setting*(MAX_SETTING_THROTTLE - MIN_SETTING_THROTTLE); *angle = ratio + MIN_SETTING_THROTTLE; return NOERROR; } else return IDERROR; } /* Convert_Angle2Servo converts a servo setting into a control surface angle * inputs: ctrl_surface->contains the limit settings * angle->the angle to be converted into a setting * setting->the servo setting that the angle was converted into * returns: IDERROR if the servo id was not recognised * NOERROR otherwise */ error Convert_Angle2Servo(ctrlsurface ctrl_surface, double angle, int *setting) { double ratio; if(ctrl_surface.id == RUDDER) { ratio = (angle - MIN_ANGLE_RUDDER)/(MAX_ANGLE_RUDDER - MIN_ANGLE_RUDDER); /* determine the ratio of the input angle */ } /* between the absolute limits */ else if(ctrl_surface.id == AILERON) { ratio = (angle - MIN_ANGLE_AILERON)/(MAX_ANGLE_AILERON - MIN_ANGLE_AILERON); } else if(ctrl_surface.id == ELEVATOR) { ratio = (angle - MIN_ANGLE_ELEVATOR)/(MAX_ANGLE_ELEVATOR - MIN_ANGLE_ELEVATOR); } else if(ctrl_surface.id == THROTTLE) { ratio = (angle - MIN_SETTING_THROTTLE)/(MAX_SETTING_THROTTLE - MIN_SETTING_THROTTLE); } else return IDERROR; *setting = floor(ratio*255+.5); /* ratio*255 determines the servo setting */ return NOERROR; /* floor(X + 0.5) causes the answer to be rounded before casting to int */ } /* Test_Servo_Limits tests the accuracy of the limit settings for the control surface * inputs: ctrl_surface->contains limit information * valid->passes the success or failure of the test out * returns: An error if one occured in the test * NOERROR otherwise */ error Test_Servo_Limits(ctrlsurface ctrl_surface, bool *valid) { int key; double angle; error error_type; LCDClear(); LCDPrintf("Minimum Limit\n"); LCDMenu("OK","","","BAD"); key = 0; angle = Get_Min_Limit(ctrl_surface); /* set the surface to the minimum limit */ error_type = Set_Angle(&ctrl_surface, angle, NORMAL); if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(ctrl_surface); if(error_type == NOERROR) { do { key = Check_Input(); }while(key != KEY1 && key != KEY4); /* wait for button 1 or 4 to be pressed */ if(key == KEY4) { *valid = FALSE; return NOERROR; } } else return error_type; } else return error_type; LCDClear(); LCDPrintf("Neutral Point\n"); LCDMenu("OK","","","BAD"); key = 0; angle = Get_Neutral_Point(ctrl_surface); /* set the surface to the neutral point */ error_type = Set_Angle(&ctrl_surface, angle, NORMAL); if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(ctrl_surface); if(error_type == NOERROR) { do { key = Check_Input(); }while(key!=KEY1 && key!=KEY4); /* wait for button 1 or 4 to be pressed */ if(key == KEY4) { *valid = FALSE; return NOERROR; } } else return error_type; } else return error_type; LCDClear(); LCDPrintf("Maximum Limit\n"); LCDMenu("OK","","","BAD"); key = 0; angle = Get_Max_Limit(ctrl_surface); /* set the surface to the maximum limit */ error_type = Set_Angle(&ctrl_surface, angle, NORMAL); if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(ctrl_surface); if(error_type == NOERROR) { do { key = Check_Input(); }while(key!=KEY1 && key!=KEY4); /* wait for button 1 or 4 to be pressed */ if(key == KEY4) { *valid = FALSE; return NOERROR; } } else return error_type; } else return error_type; angle = Get_Neutral_Point(ctrl_surface); /* reset the rudder to the neutral position */ error_type = Set_Angle(&ctrl_surface, angle, NORMAL); if(error_type == NOERROR) { error_type = Move_Ctrl_Surface_Servo(ctrl_surface); if(error_type != NOERROR) return error_type; } else return error_type; *valid = TRUE; /* if it got this far then all buttons pressed were 'OK' */ return NOERROR; } /***************************************** Other hardware manipulating functions */ /* Initialise_Plane performs all of the required initialisation steps for the plane to be ready for flight. * It will provide all feedback required through the eyebot LCD screen * inputs: plane->pointer to plane struct which will be initialised and contain all required info for flight * returns: the error that occured or * NOERROR if initialisation was successfull */ error Initialise_Plane(planestate *plane) { int i, key = 0; wplist wps; bool valid; error error_type; IRTVInit(SPACE_CODE, 15, 0, 0x3FF, SLOPPY_MODE, 4, -1); /* First initialise the IR input */ LCDPrintf("IR initialised\n"); LCDPrintf("Press a button to cancel\n"); /* Then allow 1 sec to cancel autostart */ OSWait(100); key = Check_Input(); if(key != 0) return INITERROR; LCDClear(); LCDPrintf("Starting prog\n"); error_type = Init_Plane_State(plane); /* Initialise the plane data structure */ if(error_type != NOERROR) return error_type; /*********** Compass Test ************/ valid = FALSE; valid = Init_Compass(); /* initialise compass */ if(valid == FALSE) /* if FALSE then initialisation */ { /* failed */ LCDPrintf("Compass Not Init"); return COMPASSERROR; } OSWait(SHORT); /* MUST wait a short time after start before trying to read data */ valid = FALSE; i = 0; while( i<5 && valid == FALSE ) /* read heading 5 times max to ensure compass is working */ { valid = Obtain_Heading(plane); i++; } if(valid == FALSE) /* if it doesn't work, Obtain_Heading has failed, something is wrong with the compass */ { LCDPrintf("No or Bad Compass Data"); return COMPASSHEADINGERROR; } Store_Old_Heading(plane); /* store the last heading */ /********** Test GPS *********/ valid = FALSE; while(valid == FALSE) { valid = Init_GPS(); if(valid == TRUE) { valid = Test_GPS(); } if(valid == FALSE) /* If either function failed then allow the user to retry or exit */ { LCDPrintf("GPS not sending\nRed: when ready\nBlue: finish prog"); while(TRUE) { key = 0; while(key == 0) { key = Check_Input(); } if(key == KEY1) break; if(key == KEY4) return INITERROR; } } } valid = FALSE; while( valid == FALSE ) /* try to receive positional data */ { valid = Obtain_GPS_Position(plane); } Store_Old_Position(plane); /* store the last position */ LCDPrintf( "GPSinit complete" ); /******** Get default waypoints from header file ********/ Obtain_Wplist_From_HFile(&wps); Store_Wplist(plane, wps); return NOERROR; } /* Check_Switch checks the state of the manual->autopilot switch * returns: ON->autopilot engaged * OFF->manual engaged * UNDEFINED->switch not detected (CRITICAL ERROR!) */ switchstate Check_Switch() { int check; check = OSGetAD(SWITCH); if(check >= 0) { if(check < SWITCH_THRESHHOLD) return ON; /* If the switch is below threshhold then autopilot */ else if(check < SWITCH_MAX) return OFF; /* If the switch is above threshhold and below max then manual */ else return UNDEFINED; /* else an error has occured */ } else return UNDEFINED; /* else an error has occured */ } /* Check_Input determines whether an input has been received from either input * device (buttons or remote) and returns an identifier for the button if it has * been pushed * returns: KEY1 to KEY4 representing the buttons on the eyebot */ int Check_Input() { int key = 0; int remote = 0; key = KEYRead(); /* Read from both inputs */ remote = IRTVRead(); if(key != 0) /* if a key was pressed respond to that */ { return key; } if(remote != 0) /* if an IR button was pressed respond to that */ { /* convert coloured buttons to eyebot button identifiers */ if(remote == RC_RED) return KEY1; else if(remote == RC_GREEN) return KEY2; else if(remote == RC_YELLOW) return KEY3; else if(remote == RC_BLUE) return KEY4; } return 0; } /* Shut_Down terminates all hardware so that it can be reused later * inputs: plane->contains handles for hardware */ void Shut_Down(planestate plane) { COMPASSRelease(); SERVORelease(plane.control.rudder.servo); SERVORelease(plane.control.banking.servo); SERVORelease(plane.control.elevator.servo); SERVORelease(plane.control.throttle.servo); IRTVTerm(); }