/**
 *  
 *  @file MyroC.h                                                          
 *  @brief Header for a C-based, my-robot package for the Scribbler 2      
 *                                                                          
 *  @authors  Spencer Liberto
 *  @authors  Dilan Ustek
 *  @authors  Jordan Yuan
 *  @authors  Vasilisa Bashlovkina
 *  @authors  Anita DeWitt
 *  @authors  Jason Liu 
 *  @authors  Nick Knoebber 
 *  @authors  Henry M. Walker
 *                                                                          
 *                                                                          
 *  Based on a C++ package by April O'Neill, David Cowden, Dilan Ustek,     
 *     Erik Opavsky, and Henry M. Walker                                    
 *                                                                          
 *  @note  There is an r in the beginning of every function to make it      
 *       easier to understand whether it is a robot function.               
 *                                                                          
 *                                                                          
 */

 /*
     Index of all functions

 1.  GENERAL                        2.  SENSOR
     rConnect                          a. Scribbler Sensors
     rDisconnect                          rGetLightsAll  
     rSetConnection                       rGetLightTxt
     rBeep                                rGetIRAll
     rBeep2                               rGetIRTxt
     rSetName                             rGetLine
     rGetName                             
     rSetForwardness                   b. Fluke Sensors
     rGetForwardness                      rSetIRPower
     rSetLEDFront                         rGetObstacleAll
     rSetLEDBack                          rGetObstacleTxt
     rGetBattery                          rGetBrightAll
     rGetStall                            rGetBrightTxt
     rSetBluetoothEcho

3.  MOVEMENT                         4.  PICTURES
    rTurnLeft                            rTakePicture
    rTurnRight                           rSavePicture
    rTurnSpeed                           rLoadPicture
    rForward                             rDisplayPicture
    rFastForward
    rBackward
    rMotors
    rStop
    rHardStop
*/

#ifndef _MyroC
#define _MyroC
/**
 * @brief Struct for a pixel
 */
typedef struct
{
  unsigned char R; //!< The value of the red component 
  unsigned char G; //!< The value of the green component 
  unsigned char B; //!< The value of the blue component 
} Pixel;

/**
 * @brief Struct for a picture object
 * @note the picture size is always 256 in width and 192 in height
 * @note Following standard mathematical convention for a 2D matrix, 
 * @note all references to a pixel are given within an array as [row][col]

 */
typedef struct 
{
  int height; /**< The height of the image -- set to 192 for robot camera */
  int width; /**< The width of the image   -- set to 256 for robot camera */
  Pixel pix_array[192][256]; /**< The array of pixels comprising the image */
} Picture;
/* ***************************************************************/
/* 1. GENERAL - GENERAL - GENERAL - GENERAL - GENERAL - GENERAL  */
/*****************************************************************/

/**
 * @brief connects program to Scribbler
 * @param address  string, giving name of workstation port
 *                 or a Scribbler Bluetooth designation
 *
 *                 several string formats are possible
 *                 a communications port, such as "/dev/rfcomm0"
 *                 a MAC address, such as "00:1E:19:01:0E:13"
 *                 a Scribbler 2 fluke serial number, such as "245787"
 *                 a full IPRE serial number, such as "IPRE245787"
 *                 a Fluke 2 serial number (hexadecimal), such as "021F"
 *                 a full Fluke 2 serial number, such as "Fluke2-021F"
 *
 * @return         the socket number of communications port
 *
 * @post           subsequent communications will take place through
 *                 this socket, unless changed by rSetConnection
 */
int rConnect (const char * address);

/**
 * @brief disconnect program from Scribbler 
 */
void rDisconnect();

/**
 * @brief set current connection to the socket number
 * @param new_socket_num  the number of an open socket for communication
 * @pre                   new_socket_num has been returned by rConnect
 *                        the designated socket has not been closed
 */
void rSetConnection (int new_socket_num);

/**
 * @brief Beeps with the given duration and frequency
 * @param duration   length of note in seconds
 * @param frequency  frequency of pitch in cycles per second (hertz)
 * @pre              duration > 0.0
 */
void rBeep(double duration, int frequency);

/**
 * @brief Generates two notes for the prescribed duration
 * @param duration  length of note in seconds
 * @param freq1     frequency of first pitch in cycles per second (hertz)
 * @param freq2     frequency of second pitch in cycles per second (hertz)
 * @pre             duration > 0.0
 */
void rBeep2(double duration, int freq1, int freq2);

/**
 * @brief Change name stored in the robot to the 16-byte name given
 * @param name  specifies new name of robot
 *              if < 16 bytes given, name is filled with null characters
 *              if >= 16 bytes given, name is truncated to 15 bytes plus null
 */
void rSetName (const char * name);

/**
 * @brief Get the name of the robot
 * @return information about the name of the robot
 * @post  the returned name is a newly-allocated 17-byte string
 */
const char * rGetName();

/**
 * @brief specifies which end of the Scribbler is considered the front
 * @param direction  identifies front direction
 * @pre              direction is either "fluke-forward" or "scribbler-forward"
 *                   (not case sensitive)
*/
void rSetForwardness(char * direction);

/**
 * @brief alternative to rSetForwardness for compatibility with earlier MyroC 
 */
void rSetForwardnessTxt (char * direction);

/**
 * @brief Gets the forwardness of the Scribbler
 * @return either "fluke-forward" or "scribbler-forward"
 */
char * rGetForwardness ();

/**
 * @brief Set the front [fluke] LED on or off
 * @param led  value 1 turns on LED
 *             value 0 turns off LED
 * @pre        led must be 0 or 1
 */
void rSetLEDFront(int led);

/**
 * @brief Set the the intensity of the back fluke LED,
 * @param led  intensity of the LED
 *             values between 0 and 1 provide a range of brightness
 *             from off to full intensity
 *             values bigger than 1 are treated as 1 (full brightness)
 *             values less than 0 are treated as 0 (LED off).
 */
void rSetLEDBack(double led);

/**
 * @brief Get the percentage of volts left in the batteries of the scribbler
 * @return  percentage of battery voltage
 */
double rGetBattery();

/** 
 * @brief Determine if robot has stalled
 * Since readings of each brightness sensor can vary substantially,
 *   each sensor can be queried sampleSize times and an average obtained.
 * @param sampleSize  how many readings are taken for each sensor
 * @pre               sampleSize > 0
 * @return            whether or not robot current has stalled
 * @post              Returns 1 if the robot has stalled
 *                    Returns 0 otherwise.
 */
int rGetStall (int sampleSize);

/**
 * @brief Turn on and off echoing of Bluetooth transmissions
 * All robot commands involve the transmission of a command over Bluetooth
 *   Scribbler commands are always 9 bytes
 *   Fluke commands have varying lengths
 * The fluke echos most, but not all, of the commands
 * For many commands, the fluke also echos 11 bytes of sensor data
 * @param onOff      char 'y' enables echoing
 *                   char 'n' disables echoing
 *                   other character values ignored
 */
void rSetBluetoothEcho (char onOff);


/**************************************************************************/
/* 2. SENSORS - SENSORS - SENSORS - SENSORS - SENSORS - SENSORS - SENSORS */
/**************************************************************************/

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*  Group a:  Scribbler Sensors                                          */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * @brief Get the average values of each of the three light sensors in an array.
 * Values of each light sensor can somewhat (typically under 5%-10%).
 * To even out variability, the sensor can be queried sampleSize times
 * and an average obtained.
 * @param lightSensors  array to store intensity values
 * @param sampleSize   how many readings are taken for each sensor
 * @pre                space already allocated for lightSensors array
 *                     sampleSize > 0
 * @post  
 *                     lightSensors[0] gives average value for left sensor
 *                     lightSensors[1] gives average value for middle sensor
 *                     lightSensors[2] gives average value for right sensor
 *                     Intensity values near 0 represent bright light
 *                     Intensities may extend to about 65000 for a very dark region.
*/
void rGetLightsAll (int lightSensors[3], int sampleSize);


/**
 * @brief Get the average values of a specified light sensor.
 * Values of each light sensor can somewhat (typically under 5%-10%).
 * To even out variability, the sensor can be queried sampleSize times
 * and an average obtained.
 * @param sensorName   name of the light sensor
 * @pre                sensorName is "left", "center", "middle", or "right"
 *                     (not case sensitive)
 *                     designations "center" and "middle" are alternatives
 *                     for the same light sensor
 * @param sampleSize   how many readings are taken for the sensor
 * @pre                sampleSize > 0
 * @return             reading from the specified light sensor, averaged
 *                     over sampleSize number of data samples
 *                     if sensorName invalid, returns -1.0
 */
int rGetLightTxt (const char * sensorName, int sampleSize);

/**
 * @brief Get an array of true/false values regarding the presence of obstacle
 * based on the average values of each of the three IR sensors.
 * Since readings of each light sensor can vary substantially,
 *    each sensor can be queried sampleSize times and an average obtained.
 * @param irSensors   array to store intensity values
 * @param sampleSize  how many readings are taken for each sensor
 * @pre               space already allocated for irSensors array
 *                    sampleSize > 0
 * @post  
 *                    irSensors[0] checks obstacle for left sensor
 *                    irSensors[1] checks obstacle for right sensor
 * @post              for each irSensors array value
 *                    return 0 indicates no obstacle detected
 *                    return 1 indicates obstacle detected  
*/
void rGetIRAll (int irSensors[2], int sampleSize);


/**
 * @brief Use specified IR sensor to determine if obstacle is present.
 * Since values of each light sensor can vary substantially,
 * the sensor can be queried sampleSize times and an average obtained.
 * @param sensorName   name of the light sensor
 * @pre                sensorName is "left" or "right"
 *                     (not case sensitive)
 * @param sampleSize   how many readings are taken for the sensor
 * @pre                sampleSize > 0
 * @return             true/false (0/1) determination of obstacle, based on IR
 *                     sensorName sensor, averaged over sampleSize number of
 *                     data samples
 * @post               return 0 indicates no obstacle detected
 *                     return 1 indicates obstacle detected
*/
int rGetIRTxt (const char * sensorName, int sampleSize);

/**
 * @brief Use Scribbler 2 line sensors of Scribbler to check for a black line
 * on a white surface under the robot.
 * Since values of each light sensor can vary substantially,
 *    the sensor can be queried sampleSize times and an average obtained.
 * @warning            results of these sensors may be flakey!
 * @param lineSensors  array to store line values detected
 * @param sampleSize   how many readings are taken for each sensor
 * @pre                space already allocated for lineSensors array
 *                     sampleSize > 0
 * @post               lineSensors[0] checks left sensor for line
 *                     lineSensors[1] checks right sensor for line
 * @post               for each irSensors array value
 *                     return 0 indicates line is identified
 *                     return 1 indicates line is not identified
 */
void rGetLine (int lineSensors[2], int sampleSize);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*  Group b:  Fluke Sensors                                              */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * @brief Set the amount of power for the dongle's IR sensors
 * @param power  the desired power level for the IR sensors
 * @pre          power is between 0 and 255 (inclusive)
*/
void rSetIRPower (int power);

/**
 * @brief Get the average values of the three obstacle sensors in an array.
 * Since readings of each obstacle sensor can vary substantially (successive
 *      readings may differ by several hundred or more),
 *      each sensor can be queried sampleSize times and an average obtained.
 * @param obstSensors   array to store intensity values
 * @param sampleSize    how many readings are taken for each sensor
 * @pre                 space already allocated for obstSensors array
 *                      sampleSize > 0
 * @post                obstSensors[0] gives average value for left sensor
 *                      obstSensors[1] gives average value for middle sensor
 *                      obstSensors[2] gives average value for right sensor
 *                      Obstacle values near 0 represent no obstacle is seen
 *                      Obstacle values may approach 6000 as obstacle gets close.
 * @warning             As battery degrades, sensor readings degrade,
 *                      yielding systematically lower numbers.
*/
void rGetObstacleAll (int obstSensors[3], int sampleSize);

/** 
 * @brief Get the average values of a specified obstacle (IR) sensor.
 * Since values of each obstacle sensor can vary substantially (successive
 *      readings may differ by several hundred or more),
 *      the sensor can be queried sampleSize times and an average obtained.
 * @param sensorName  name of the obstacle sensor
 * @pre               sensorName is "left", "center", "middle", or "right"
 *                    (not case sensitive)
 *                    designations "center" and "middle" are alternatives
 *                    for the same light sensor
 * @param sampleSize  how many readings are taken for the sensor
 * @pre               space already allocated for vals array
 *                    sampleSize > 0
 * @return            reading from the specified obstacle sensor, averaged
 *                    over sampleSize number of data samples
 *                    Obstacle values near 0 represent no obstacle is seen
 *                    Obstacle values may approach 6000 as obstacle gets close.
 * @warning           As battery degrades, sensor values degrade,
 *                    yielding systematically lower numbers.
 */
int rGetObstacleTxt (const char * sensorName, int sampleSize);

/**
 * @brief Read the Fluke's virtual light sensors.
 *  Since readings of each brightness sensor can vary substantially (successive
 *     readings may differ by 5000-10000),
 *     each sensor can be queried sampleSize times and an average obtained.
 * @param brightSensors  array to store intensity values
 * @param sampleSize     how many readings are taken for each sensor
 * @pre                  space already allocated for brightSensors array
 *                       sampleSize > 0
 * @post                 brightSensors[0] gives average value for left sensor
 *                       brightSensors[1] gives average value for middle sensor
 *                       brightSensors[2] gives average value for right sensor
 *                       Brightness values near 0 represent bright light
 *                       Brightness values may extend to about 65535 for a very dark region.
 */
void rGetBrightAll (int brightSensors[3], int sampleSize);

/**
 * @brief Reads one of the Fluke's virtual light sensors.
 * Since values of each obstacle sensor can vary substantially (successive
 *    readings may differ by 5000-10000),
 *    the sensor can be queried sampleSize times and an average obtained.
 * @param sensorName  name of the obstacle sensor
 * @pre               sensorName is "left", "center", "middle", or "right"
 *                    (not case sensitive)
 *                    designations "center" and "middle" are alternatives
 *                    for the same light sensor
 * @param sampleSize  how many readings are taken for the sensor
 * @pre               sampleSize > 0
 * @return            reading from the specified obstacle sensor, averaged
 *                    over sampleSize number of data samples
 *                    Brightness values near 0 represent bright light
 *                    Brightness values may extend to about 65535 for a very dark region.
 */
int rGetBrightTxt (char * sensorName, int sampleSize);

/**
 * @brief returns information about the robot's dongle, firmware, and 
 * communication mode as a 60 character array in infoBuffer. 
 * @param infoBuffer  a pre-defined, 60-character array 
 * @post              infoBuffer contains relevant robot information
 */
void rGetInfo (char * infoBuffer);


/***********************************************************************/
/* 3. MOVEMENT - MOVEMENT - MOVEMENT - MOVEMENT - MOVEMENT - MOVEMENT  */
/***********************************************************************/

/* In this section, "non-blocking" refers to commands that do not prevent
   the robot from executing other non-movement commands at the same time.
   For example, a call to rForward in the non-blocking mode with a
   consecutive call to rBeep will result in the Scribbler moving forward
   while beeping.
*/
   

/**
 * @brief turn Scribbler left for a specified time and speed
 * @param speed  the rate at which the robot should move left
 *               linear range:  -1.0 specifies right turn at full speed
 *                              0.0 specifies no turn
 *                              1.0 specifies left turn at full speed
 * @param time   specifies the duration of the turn
 *               if negative:    robot continues to turn until given another
 *                               motion command or disconnected (non-blocking)
 *               if nonnegative: robot turns for the given duration, in seconds
 */
void rTurnLeft (double speed, double time);

/**
 * @brief turn Scribbler right for a specified time and speed  
 *  @param speed  the rate at which the robot should move right
 *                linear range: -1.0 specifies left turn at full speed
 *                              0.0 specifies no turn
 *                              1.0 specifies right turn at full speed
 *  @param time   specifies the duration of the turn
 *                if negative:    robot continues to turn until given another
 *                                motion command or disconnected (non-blocking)
 *                if nonnegative: robot turns for the given duration, in seconds
 */
void rTurnRight (double speed, double time);

/** 
 * @brief turn Scribbler in direction for a specified time and speed
 * @param direction  direction of turn, based on looking from
 *                   the center of the robot and facing forward
 * @param speed      the rate at which the robot should move forward
 *                   linear range:  -1.0 specifies turn at full speed
 *                                  0.0 specifies no turn
 *                                  1.0 specifies turn at full speed
 * @param time       specifies the duration of the turn
 *                   if negative: robot continues to turn until given another
 *                                motion command or disconnected
 *                   if nonnegative: robot turns for the given duration,
 *                    in seconds
 * @pre              direction is "left" or "right", case insensitive
 */
void rTurnSpeed (char * direction, double speed, double time);

/**
 * @brief moves Scribbler forward for a specified time and speed
 * @param speed   the rate at which the robot should move forward
 *                linear range:  -1.0 specifies move backward at full speed
 *                               0.0 specifies no forward/backward movement
 *                               1.0 specifies move forward at full speed
 * @param time    specifies the duration of movement
 *                if negative:    robot continues to move forward until given
 *                                another motion command or disconnected 
 *                                (non-blocking)
 *                if nonnegative: robot moves forward for the given duration, in
 *                                seconds
 */
void rForward (double speed, double time);

/** 
 * @brief moves Scribbler forward at the largest possible speed for a specified time 
 * @param time  specifies the duration of movement
 *              if negative: robot continues to move forward until given another
 *                           motion command or disconnected (non-blocking)
 *              if nonnegative: robot moves forward for the given duration, in
 *                              seconds
 * @warning     may take longer than usual to execute
 */
void rFastForward (double time);
 
/**
 * @brief moves Scribbler backward for a specified time and speed  
 * @param speed  the rate at which the robot should move backward
 *               linear range:  -1.0 specifies move forward at full speed
 *                              0.0 specifies no forward/backward movement
 *                              1.0 specifies move backward at full speed
 * @param time   specifies the duration of the turn
 *               if negative: robot continues to go backward until given another
 *                            motion command or disconnected (non-blocking)
 *               if nonnegative: robot moves backward for the given duration, in
 *                               seconds
 *                  
 */
void rBackward (double speed, double time);

/**
 * @brief move robot with given speeds for the left and right motors
 * continues until given another motion command or disconnected (non-blocking)
 * @param leftSpeed  the rate at which the left wheel should turn
 *              linear range:  -1.0 specifies move backward at full speed
 *                              0.0 specifies no forward/backward movement
 *                              1.0 specifies move forwardward at full speed
 * @param rightSpeed the rate at which the right wheel should turn
 *              linear range:  -1.0 specifies move backward at full speed
 *                              0.0 specifies no forward/backward movement
 *                              1.0 specifies move forward at full speed
 */
void rMotors (double leftSpeed, double rightSpeed);

/**
 * @brief directs robot to stop movement
 */
void rStop();

/**
 * @brief cuts power to the motor of the robot
 */
void rHardStop();

/***********************************************************************/
/* 4.) PICTURES PICTURES PICTURES PICTURES PICTURES PICTURES PICTURES  */
/***********************************************************************/
/* In this section we deal with taking and manipulating pictures produced 
   from the Scribbler 2 camera. These pictures will always be 192x256 
   (192 rows by 256 columns) and internally are defined as type Picture, 
   which hold a 2D array of type of Pixel. These can be saved and loaded 
   as .jpeg files.

   Following standard mathematical convention for a 2D matrix, 
   all references to a pixel are given within an array as [row][col]
 */

/**
 * @brief Use the camera to take a photo
 * @return Picture
 */
Picture rTakePicture();

/**
 * @brief Save a Picture to a .jpeg
 * @param pic      RGB picture struct from Scribbler 2 camera
 * @param filename the name of the file
 * @pre            filename ends with .jpeg or .jpg.
 * @post           If the file does not exist, a new file will be created.
 * @post           If the file exists, the file will be overwritten.
 */
void rSavePicture(Picture pic, char * filename);

/**
 * @brief Load a picture from a .jpeg file.
 * @param filename  the name of the file
 * @pre             file must exist
 * @pre             file must be a 256x192 .jpeg or .jpg
 * @return          Picture
 */
Picture rLoadPicture(char * filename);


/**
 * @brief Display a picture in a new window
 * @param pic         RGB picture struct from Scribbler 2 camera
 * @param duration    if duration > 0, operation is blocking
 *                    if duration <= 0, operation is non-blocking
 *                    for duration != 0, picture displayed for abs(duration) 
 *                            seconds or until picture closed manually
 *                    if duration == 0, picture displayed until closed manually
 * @param windowTitle The title of the window that appears.
 *                    white spaces will be replaced with underscores. 
 * @pre               windowTitle is less than 100 characters. 
 */

void rDisplayPicture(Picture pic, double duration, const char * windowTitle);


#endif
