/* * * * * * * * * * * * * * * * * * * * * *
 * @file  MyroC-utilities.h
 * @brief Header for implementation utilities used by several MyroC functions
 *
 *      helper functions for an individual user function are included in the
 *          implementation file for that function
 *
 * Revision History
 *
 * Version 1.0 based on a C++ package by April O'Neill, David Cowden,
 *     Dilan Ustek, Erik Opavsky, and Henry M. Walker
 *
 * Developers of the C package for Linux:
 *  Creators Version 2.0 (C functions for utilities,general,sensors,movement):
 *    Spencer Liberto
 *    Dilan Ustek
 *    Jordan Yuan
 *    Henry M. Walker
 *  Contributors Version 2.2-2.3: (C functions for image processing)
 *    Anita DeWitt
 *    Jason Liu
 *    Nick Knoebber
 *    Vasilisa Bashlovkina
 * Revision for Version 2.4:  (image row/column made to match matrix notation)
 *    Henry M. Walker
 *
 * Revisions for Version 3.0 
 *    Henry M. Walker
 *
 *  C ported to Macintosh
 *     Linux/Mac differences required for connections — otherwise same code
 *  OpenGL used to display images, replacing ImageMagick
 *     same [new] code used for both Linux and Macintosh
 *     1 process for robot control
 *     1 process needed for each titled window (not each image, as in 2.2-2.4)
 *  Blocking options (negative duration parameter)
 *     utilize separate thread timer
 *  MyroC implementation files organized by user function as follows:
 *
 * Revisions for Version 3.1 
 *    Henry M. Walker
 *
 *    Picture struct and image functions revised to allow 
 *       192 by  256 images from origial Fluke camera
 *       266 x 427 low-resolution images from Fluke 2
 *         (high-resolution (800 x 1280) too large for more than 2-4 
 *          variables on run-time stack)
 *       storage , retrieval, and display of any images up to 266 x 427 
 *
 * Revisions for Version 3.2
 *    Henry M. Walker
 *    
 *    Practical range of rBeep duration identified as <= 3.0014 seconds
 *    Image display and processing resolves several matters and adds functionality
 *        function rDisplayPicture completely rewritten
 *                over time OpenGL rountines had encountered troubles
 *                on Linux, specifically glutHideWindow() hid images, but could not be
 *                          restored, with difficulties depending on the graphics card
 *                on Mac, High Sierra generated compile warnings and 
 *                          restricted threads that could display images
 *    function rDisplayImageProcessingErrors added
 *    function rWaitTimedImageDisplay updated substantially
 *
 *  This program and all MyroC software is licensed under the Creative Commons
 *  Attribution-Noncommercial-Share Alike 3.0 United States License.
 *  Details available at http://creativecommons.org/licenses/by-nc-sa/3.0/us/
 *
 ********************** implementation overview *************************

 0. LOW-LEVEL UTILITY (prototypes in MyroC-utilities.h
                       implemented in * MyroC-connect.c)
  > rSend
  > rReceive
  > rSetOpeningExchange
  > rSetBluetoothEcho
  > rSetEchoMode
  > rCheckHardwareVersionSetCameraSize

 1. GENERAL (mostly MyroC-general.c) 2. SENSOR  (MyroC-sensors.c)
  > rConnect  (* MyroC-connect.c)     a.Scribbler Sensors
  > rDisconnect  (* MyroC-connect.c)    rGetLightsAll
    rSetConnection                      rGetLightTxt
    rFinishProcessing                   rGetIRAll
    rSetVolume                          rGetIRTxt
    rBeep                               rGetLine
    rBeep2                        
    rSetName                          b.Fluke Sensors
    rGetName                            rGetObstacleAll
    rSetForwardness                     rGetObstacleTxt
    rGetForwardness                     rGetBrightAll
    rSetLEDFront                        rGetBrightTxt
    rSetLEDBack                         rSetIRPower
    rGetBattery                          
    rGetStall           

      Note:
      *  MyroC-connect requires special
         knowledge of a Mac or Linux
         environment, yielding two versions:
         MyroC-connect-mac.c
         MyroC-connect-linux.c

 3. MOVEMENT (MyroC-movement.c)      4. PICTURES (files as indicated)
    rTurnLeft                           rGetCameraSize (MyroC-camera.c)
    rTurnRight                          rTakePicture (MyroC-camera.c)
    rTurnSpeed                          rDisplayPicture (MyroC-display.c)
    rForward                            rDisplayImageProcessingErrors (MyroC-display.c)
    rFastForward                        rWaitTimedImageDisplay(MyroC-display.c)
    rBackward                           rSavePicture (MyroC-image-file.c)
    rMotors                             rLoadPicture (MyroC-image-file.c)   
    rStop
    rHardStop


 ************************************************************************
 */

#ifndef _MyroC_utilities
#define _MyroC_utilities


/*
 ************************** macros **************************************
*/

#define BYTES_OF_SENSOR_DATA 11
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) 
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) 

/* 
 ***********************global definitions ******************************
*/

/*
 definitions to specify if Scribbler echoes a command
   (most or all do)
*/
#define ECHO_COMMAND_ON  1
#define ECHO_COMMAND_OFF 0

/* 
 flags to specify if Scribbler echoes all sensor data 
*/
#define ECHO_SENSOR_ON   1
#define ECHO_SENSOR_OFF  0

// definitions for Bluetooth communications with sockets
// basic 
#if  defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
   // set following variable to the directory of the image handler (e.g., /usr/local/bin)
   #define  DIRECTORY_FOR_IMAGE_HANDLER  "C:/msys64/usr/local/bin"
   #include <winsock2.h>
   #include <ws2bth.h>
   #define SOCKET_TYPE SOCKET  
   // current socket used for Bluetooth communications
   extern SOCKET_TYPE socket_num;  // a Windows 10 SOCKET is a long, long int

#else
   #define SOCKET_TYPE int  
   // current socket used for Bluetooth communications
   extern SOCKET_TYPE socket_num;
#endif

/* ********************** Declarations for MyroC internals ****************
 */
#include <pthread.h>

/**
 * Struct for recording number of motion commands by a robot
 */
typedef struct
{
  SOCKET_TYPE robot_socket_num;
  int camera_height;
  int camera_width;
  char * fluke_type;  /* values:  "unknown", robot not yet consulted
                                  "unecognized", query gave neither Fluke 1/2
                                  "original fluke"
                                  "Fluke 2"
                       */
  int motion_seq_num;
  pthread_t thread_motion_timer_id;
} robot_motion_camera_record;

/**
 * Struct for timing motion commands of given robot
 */
typedef struct
{
  double duration_time;
  SOCKET_TYPE robot_socket_num;
  int motion_seq_num;
} motion_timing_data;


/*
 ************************ global variables ******************************

variables identifed as external here; variables allocated in MyroC-utilities.c
 */

/* version specification 
 */
extern char * version;
extern int version_printed;  // 0 - version not yet printed; 1 - version printed

// baudrate for Bluetooth communication
extern const int baudrate; // = 38400;

// debug flag for communications
extern int debug;  // 1 == echo all communications; 0 no extra printing

// allow beeps and data exchange during opening connect
extern int followOpeningExchange; // 1==robot beeps, exchanges data at connect; 
                                  // 0==no beeps or data exchange

extern pthread_mutex_t bluetooth_lock;  // mutex to prevent concurrent
                                        // communication over 
                                        // socket for robot communication

/* 
 variables for counting motion commands per robot, based on socket number
 variables referenced in connections (rConnect, rDisconnect) and motion commands
 variable for whether or not to display error messages from image processes
 */

#define max_number_robots 20

extern int current_num_robots;

extern int displayImageErrors;

extern robot_motion_camera_record robot_sock_array [];

/*
 ************************ utility procedures ****************************
 */

/**                                                                            
 * send bytes to the Scribbler --- same as rSend, EXCEPT                       
 * @pre                  mutex set to prevent concurrent Bluetooth processing
 * @param message        the command/data to be sent                         
 * @param numberOfBytes  how many bytes to transmit                          
 * @param echo           whether or not (1/0) the Scribbler echoes the command
 * @param sensor_echo    whether or not the Scribbler sends all sensor data   
 *                       back after echoing the command                       
 */
void rSend_protected (char message[], int numberOfBytes, int echo, 
                      int sensor_echo, char * commandText);

/**                                                                         
 * send bytes to the Scribbler --- same as rSend_protected, EXCEPT          
 * @pre                  mutex NOT set for concurrent Bluetooth processiung 
 * @param message        the command/data to be sent                        
 * @param numberOfBytes  how many bytes to transmit                         
 * @param echo           whether or not (1/0) the Scribbler echoes the command
 * @param sensor_echo    whether or not the Scribbler sends all sensor data
 *                       back after echoing the command                    
 */
void rSend (char message[], int numberOfBytes, int echo, 
            int sensor_echo, char * commandText);

/**
 * Receives data via bluetooth
 * @param message        pointer to allocated space, where data will be stored
 * @param numberOfBytes  number of bytes to be received from the Scribbler 
 * @pew                  space pointed to by message >= numberOfEchoBytes
 */
void rReceive (unsigned char * message, int numberOfBytes);

/**
 * @brief Turn on and off opening exchange with robot, including
 *                   distinctive beeps when connecting 
 * @param onOff      char 'y' enables beeps (default)
 *                   char 'n' disables beeps 
 *                   other character values ignored
 */
void rSetOpeningExchange (char onOff);

/**
 * @brief Turn on and off echo mode for Bluetooth communications
 * Echo Mode repeats the 1-byte command code after echoing the command
 *    and sensor data for Scribbler commands.
 * @param onOff      char 'y' enables echo mode (default)
 *                   char 'n' disables echo mode 
 *                   other character values ignored
 */
void rSetEchoMode (char onOff);

/**
 * @brief  determine Scribbler and Fluke versions, set default camera size
 * @param  printYorN   print Scribbler/Fluke version numbers during processing
 * @post   if original fluke, camera size set to 192 (height) by 256 (width)
 *         if Fluke 2, camera size set to 266 (height) by 427 (width)
 */
void rCheckHardwareVersionSetCameraSize (char printYorN);

/**
 * @brief set/record image size for camera
 * @param resolution if Fluke 2 is present
 *                       "low"  or "lo": pictures from camera 266 (high) by 427
 *                       "high" or "hi": pictures from camera 800 (high) by 1280
 * @pre              if Fluke 2 present, resolution must be "low" or "high"
 * @post             no effect if original Fluke present
 * @post             if Fluke 2 present, camera resolution set for next images
 */
void rSetCameraSize (char * resolution);

/**
 * @brief return default image size from camera
 * @param width, height set to image size
 * @return "unknown", "original Fluke", "Fluke 2", or "unrecognized"
 * @post  if no connection to robot present, 
 *           dimensions are 0, 0; and "no connection" returned
 * @post  if previous connection, but type not determined, "unknown" returned
 * @post  if connection to robot, but no size specified previously,
 *           original fluke size:  192 by  256;  "original Fluke" returned
 *           Fluke 2 size:         800 by 1280;  "Fluke 2" returned
 * @post  if robot query not anticipated, "unrecognized" returned
 * @post  if connections previously set, dimensions returned as set
 */
const char * rGetCameraSize (int *height, int *width);

/**
 * @brief return default image size from camera
 * @param width, height set to image size
 * @return "unknown", "original Fluke", "Fluke 2", or "unrecognized"
 * @post  if no connection to robot present, 
 *           dimensions are 0, 0; and "unknown" returned
 * @post  if connection to robot, but no size specified previously,
 *           original fluke size:  192 by 256;  "original Fluke" returned
 *           Fluke 2 size:         266 by 427;  "Fluke 2" returned
 * @post  if robot query not anticipated, "unrecognized" returned
 * @post  if connections previously set, dimensions returned as set
 */
const char * rGetCameraSize (int *height, int *width);

#endif

