// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

#pragma once

#include <stddef.h>
#include <stdint.h>

#include "wpi/hal/DriverStationTypes.h"
#include "wpi/hal/Types.h"
#include "wpi/util/Synchronization.h"
#include "wpi/util/string.h"

/**
 * @defgroup hal_driverstation Driver Station Functions
 * @ingroup hal_capi
 * @{
 */

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Sends an error to the driver station.
 *
 * @param isError   true for error, false for warning
 * @param errorCode the error code
 * @param isLVCode  true for a LV error code, false for a standard error code
 * @param details   the details of the error
 * @param location  the file location of the error
 * @param callStack the callstack of the error
 * @param printMsg  true to print the error message to stdout as well as to the
 * DS
 * @return the error code, or 0 for success
 */
int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
                      const char* details, const char* location,
                      const char* callStack, HAL_Bool printMsg);

/**
 * Set the print function used by HAL_SendError
 *
 * @param func Function called by HAL_SendError when stderr is printed
 */
void HAL_SetPrintErrorImpl(void (*func)(const char* line, size_t size));

/**
 * Sends a line to the driver station console.
 *
 * @param line the line to send (null terminated)
 * @return the error code, or 0 for success
 */
int32_t HAL_SendConsoleLine(const char* line);

/**
 * Gets the current control word of the driver station.
 *
 * The control word contains the robot state.
 *
 * @param controlWord the control word (out)
 * @return the error code, or 0 for success
 */
int32_t HAL_GetControlWord(HAL_ControlWord* controlWord);

/**
 * Gets the current control word of the driver station. Unlike
 * HAL_GetControlWord, this function gets the latest value rather than using the
 * value cached by HAL_RefreshDSData().
 *
 * The control word contains the robot state.
 *
 * @param controlWord the control word (out)
 * @return the error code, or 0 for success
 */
int32_t HAL_GetUncachedControlWord(HAL_ControlWord* controlWord);

/**
 * Sets operating mode options.
 *
 * @param options array of operating mode options
 * @param count number of options in the array
 * @return the error code, or 0 for success
 */
int32_t HAL_SetOpModeOptions(const struct HAL_OpModeOption* options,
                             int32_t count);

/**
 * Gets the current alliance station ID.
 *
 * @param[out] status the error code, or 0 for success
 * @return the alliance station ID
 */
HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status);

/**
 * Gets the axes of a specific joystick.
 *
 * @param joystickNum the joystick number
 * @param axes        the axes values (output)
 * @return the error code, or 0 for success
 */
int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes);

/**
 * Gets the POVs of a specific joystick.
 *
 * @param joystickNum the joystick number
 * @param povs        the POV values (output)
 * @return the error code, or 0 for success
 */
int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs);

/**
 * Gets the buttons of a specific joystick.
 *
 * @param joystickNum the joystick number
 * @param buttons     the button values (output)
 * @return the error code, or 0 for success
 */
int32_t HAL_GetJoystickButtons(int32_t joystickNum,
                               HAL_JoystickButtons* buttons);

/**
 * Gets the touchpads of a specific joystick.
 * @param joystickNum the joystick number
 * @param touchpads   the touchpad values (output)
 * @return the error code, or 0 for success
 */
int32_t HAL_GetJoystickTouchpads(int32_t joystickNum,
                                 HAL_JoystickTouchpads* touchpads);

/**
 * Gets all the data of a specific joystick.
 *
 * @param joystickNum the joystick number
 * @param axes        the axes values (output)
 * @param povs        the POV values (output)
 * @param buttons     the button values (output)
 * @param touchpads   the touchpad values (output)
 */
void HAL_GetAllJoystickData(int32_t joystickNum, HAL_JoystickAxes* axes,
                            HAL_JoystickPOVs* povs,
                            HAL_JoystickButtons* buttons,
                            HAL_JoystickTouchpads* touchpads);

/**
 * Retrieves the Joystick Descriptor for particular slot.
 *
 * @param joystickNum the joystick number
 * @param[out] desc   descriptor (data transfer object) to fill in. desc is
 *                    filled in regardless of success. In other words, if
 *                    descriptor is not available, desc is filled in with
 *                    default values matching the init-values in Java and C++
 *                    Driver Station for when caller requests a too-large
 *                    joystick index.
 * @return error code reported from Network Comm back-end.  Zero is good,
 *         nonzero is bad.
 */
int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
                                  HAL_JoystickDescriptor* desc);

/**
 * Gets whether a specific joystick is considered to be an Gamepad.
 *
 * @param joystickNum the joystick number
 * @return true if gamepad, false otherwise
 */
HAL_Bool HAL_GetJoystickIsGamepad(int32_t joystickNum);

/**
 * Gets the type of joystick connected.
 *
 * This maps to SDL_GamepadType
 *
 * @param joystickNum the joystick number
 * @return the enumerated gamepad type
 */
int32_t HAL_GetJoystickGamepadType(int32_t joystickNum);

/**
 * Gets the game-specific message for the current match.
 *
 * @param gameData the game-specific message (output)
 * @return the error code, or 0 for success
 */
int32_t HAL_GetGameData(HAL_GameData* gameData);

/**
 * Gets the supported outputs of a specific joystick.
 *
 * @param joystickNum the joystick number
 * @return bitmask of supported outputs
 */
int32_t HAL_GetJoystickSupportedOutputs(int32_t joystickNum);

/**
 * Gets the name of a joystick.
 *
 * The returned string must be freed with WPI_FreeString
 *
 * @param name the joystick name string
 * @param joystickNum the joystick number
 */
void HAL_GetJoystickName(struct WPI_String* name, int32_t joystickNum);

/**
 * Set joystick rumbles.
 *
 * @param joystickNum the joystick number
 * @param leftRumble  the left rumble value (0-FFFF)
 * @param rightRumble the right rumble value (0-FFFF)
 * @param leftTriggerRumble  the left trigger rumble value (0-FFFF)
 * @param rightTriggerRumble the right trigger rumble value (0-FFFF)
 * @return the error code, or 0 for success
 */
int32_t HAL_SetJoystickRumble(int32_t joystickNum, int32_t leftRumble,
                              int32_t rightRumble, int32_t leftTriggerRumble,
                              int32_t rightTriggerRumble);

/**
 * Set joystick LEDs.
 * @param joystickNum the joystick number
 * @param leds  the rgb led color value (0xRRGGBB)
 * @return the error code, or 0 for success
 */
int32_t HAL_SetJoystickLeds(int32_t joystickNum, int32_t leds);

/**
 * Return the approximate match time. The FMS does not send an official match
 * time to the robots, but does send an approximate match time. The value will
 * count down the time remaining in the current period (auto or teleop).
 * Warning: This is not an official time (so it cannot be used to dispute ref
 * calls or guarantee that a function will trigger before the match ends).
 *
 * <p>When connected to the real field, this number only changes in full integer
 * increments, and always counts down.
 *
 * <p>When the DS is in practice mode, this number is a floating point number,
 * and counts down.
 *
 * <p>When the DS is in teleop or autonomous mode, this number returns -1.0.
 *
 * <p>Simulation matches DS behavior without an FMS connected.
 *
 * @param[out] status the error code, or 0 for success
 * @return Time remaining in current match period (auto or teleop) in seconds
 */
double HAL_GetMatchTime(int32_t* status);

/**
 * Gets if outputs are enabled by the control system.
 *
 * @return true if outputs are enabled
 */
HAL_Bool HAL_GetOutputsEnabled(void);

/**
 * Gets info about a specific match.
 *
 * @param[in] info the match info (output)
 * @return the error code, or 0 for success
 */
int32_t HAL_GetMatchInfo(HAL_MatchInfo* info);

/**
 * Refresh the DS control word.
 *
 * @return true if updated
 */
HAL_Bool HAL_RefreshDSData(void);

/**
 * Adds an event handle to be signalled when new data arrives.
 *
 * @param handle the event handle to be signalled
 */
void HAL_ProvideNewDataEventHandle(WPI_EventHandle handle);

/**
 * Removes the event handle from being signalled when new data arrives.
 *
 * @param handle the event handle to remove
 */
void HAL_RemoveNewDataEventHandle(WPI_EventHandle handle);

/**
 * Sets the program starting flag in the DS.
 *
 * This is what changes the DS to showing robot code ready.
 */
void HAL_ObserveUserProgramStarting(void);

/**
 * Sets the control word state returned to the DS.
 *
 * This is used for the DS to ensure the robot is properly responding to its
 * state request. Ensure this gets called about every 50ms, or the robot will be
 * disabled by the DS.
 *
 * @param word control word returned by HAL_GetControlWord
 */
void HAL_ObserveUserProgram(HAL_ControlWord word);

#ifdef __cplusplus
}  // extern "C"
#endif
/** @} */
