2024-11-30 18:04:00 +00:00
|
|
|
// 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.
|
|
|
|
|
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/hal/HAL.h"
|
2024-11-30 18:04:00 +00:00
|
|
|
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
#include <signal.h> // linux for kill
|
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <thread>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
2024-12-08 12:01:28 -08:00
|
|
|
#include "CANInternal.h"
|
2024-11-30 18:04:00 +00:00
|
|
|
#include "HALInitializer.h"
|
|
|
|
|
#include "HALInternal.h"
|
2025-01-16 09:49:40 -08:00
|
|
|
#include "SystemServerInternal.h"
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/hal/DriverStation.h"
|
|
|
|
|
#include "wpi/hal/Errors.h"
|
|
|
|
|
#include "wpi/hal/Notifier.h"
|
|
|
|
|
#include "wpi/hal/handles/HandlesInternal.h"
|
2025-11-07 19:57:55 -05:00
|
|
|
#include "wpi/util/MemoryBuffer.hpp"
|
|
|
|
|
#include "wpi/util/StringExtras.hpp"
|
|
|
|
|
#include "wpi/util/fs.hpp"
|
|
|
|
|
#include "wpi/util/mutex.hpp"
|
|
|
|
|
#include "wpi/util/print.hpp"
|
|
|
|
|
#include "wpi/util/timestamp.h"
|
2024-11-30 18:04:00 +00:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
using namespace wpi::hal;
|
2024-11-30 18:04:00 +00:00
|
|
|
|
|
|
|
|
static uint64_t dsStartTime;
|
|
|
|
|
|
|
|
|
|
static int32_t teamNumber = -1;
|
|
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
using namespace wpi::hal;
|
2024-11-30 18:04:00 +00:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
namespace wpi::hal {
|
2024-11-30 18:04:00 +00:00
|
|
|
void InitializeDriverStation();
|
|
|
|
|
void WaitForInitialPacket();
|
|
|
|
|
namespace init {
|
|
|
|
|
void InitializeHAL() {
|
|
|
|
|
InitializeCTREPCM();
|
|
|
|
|
InitializeREVPH();
|
|
|
|
|
InitializeAddressableLED();
|
|
|
|
|
InitializeAnalogInput();
|
|
|
|
|
InitializeCAN();
|
|
|
|
|
InitializeCANAPI();
|
|
|
|
|
InitializeConstants();
|
|
|
|
|
InitializeCounter();
|
|
|
|
|
InitializeDIO();
|
|
|
|
|
InitializeDutyCycle();
|
|
|
|
|
InitializeEncoder();
|
|
|
|
|
InitializeFRCDriverStation();
|
|
|
|
|
InitializeI2C();
|
2025-06-11 00:57:42 -04:00
|
|
|
InitializeIMU();
|
2024-11-30 18:04:00 +00:00
|
|
|
InitializeMain();
|
|
|
|
|
InitializeNotifier();
|
|
|
|
|
InitializeCTREPDP();
|
|
|
|
|
InitializeREVPDH();
|
|
|
|
|
InitializePorts();
|
|
|
|
|
InitializePower();
|
|
|
|
|
InitializePWM();
|
|
|
|
|
InitializeSerialPort();
|
2024-12-08 22:08:05 -08:00
|
|
|
InitializeSmartIo();
|
2024-11-30 18:04:00 +00:00
|
|
|
InitializeThreads();
|
2025-02-07 12:37:23 -08:00
|
|
|
InitializeUsageReporting();
|
2024-11-30 18:04:00 +00:00
|
|
|
}
|
|
|
|
|
} // namespace init
|
|
|
|
|
|
|
|
|
|
uint64_t GetDSInitializeTime() {
|
|
|
|
|
return dsStartTime;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
} // namespace wpi::hal
|
2024-11-30 18:04:00 +00:00
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
|
|
const char* HAL_GetErrorMessage(int32_t code) {
|
|
|
|
|
switch (code) {
|
|
|
|
|
case 0:
|
|
|
|
|
return "";
|
|
|
|
|
case SAMPLE_RATE_TOO_HIGH:
|
|
|
|
|
return SAMPLE_RATE_TOO_HIGH_MESSAGE;
|
|
|
|
|
case VOLTAGE_OUT_OF_RANGE:
|
|
|
|
|
return VOLTAGE_OUT_OF_RANGE_MESSAGE;
|
|
|
|
|
case LOOP_TIMING_ERROR:
|
|
|
|
|
return LOOP_TIMING_ERROR_MESSAGE;
|
|
|
|
|
case SPI_WRITE_NO_MOSI:
|
|
|
|
|
return SPI_WRITE_NO_MOSI_MESSAGE;
|
|
|
|
|
case SPI_READ_NO_MISO:
|
|
|
|
|
return SPI_READ_NO_MISO_MESSAGE;
|
|
|
|
|
case SPI_READ_NO_DATA:
|
|
|
|
|
return SPI_READ_NO_DATA_MESSAGE;
|
|
|
|
|
case INCOMPATIBLE_STATE:
|
|
|
|
|
return INCOMPATIBLE_STATE_MESSAGE;
|
|
|
|
|
case NO_AVAILABLE_RESOURCES:
|
|
|
|
|
return NO_AVAILABLE_RESOURCES_MESSAGE;
|
|
|
|
|
case RESOURCE_IS_ALLOCATED:
|
|
|
|
|
return RESOURCE_IS_ALLOCATED_MESSAGE;
|
|
|
|
|
case RESOURCE_OUT_OF_RANGE:
|
|
|
|
|
return RESOURCE_OUT_OF_RANGE_MESSAGE;
|
|
|
|
|
case HAL_INVALID_ACCUMULATOR_CHANNEL:
|
|
|
|
|
return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
|
|
|
|
|
case HAL_HANDLE_ERROR:
|
|
|
|
|
return HAL_HANDLE_ERROR_MESSAGE;
|
|
|
|
|
case NULL_PARAMETER:
|
|
|
|
|
return NULL_PARAMETER_MESSAGE;
|
|
|
|
|
case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
|
|
|
|
|
return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
|
|
|
|
|
case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
|
|
|
|
|
return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
|
|
|
|
|
case PARAMETER_OUT_OF_RANGE:
|
|
|
|
|
return PARAMETER_OUT_OF_RANGE_MESSAGE;
|
|
|
|
|
case HAL_COUNTER_NOT_SUPPORTED:
|
|
|
|
|
return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
|
|
|
|
|
case HAL_ERR_CANSessionMux_InvalidBuffer:
|
|
|
|
|
return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
|
|
|
|
|
case HAL_ERR_CANSessionMux_MessageNotFound:
|
|
|
|
|
return ERR_CANSessionMux_MessageNotFound_MESSAGE;
|
|
|
|
|
case HAL_WARN_CANSessionMux_NoToken:
|
|
|
|
|
return WARN_CANSessionMux_NoToken_MESSAGE;
|
|
|
|
|
case HAL_ERR_CANSessionMux_NotAllowed:
|
|
|
|
|
return ERR_CANSessionMux_NotAllowed_MESSAGE;
|
|
|
|
|
case HAL_ERR_CANSessionMux_NotInitialized:
|
|
|
|
|
return ERR_CANSessionMux_NotInitialized_MESSAGE;
|
2025-07-14 23:46:57 -07:00
|
|
|
case HAL_WARN_CANSessionMux_TxQueueFull:
|
|
|
|
|
return HAL_WARN_CANSessionMux_TxQueueFull_MESSAGE;
|
|
|
|
|
case HAL_WARN_CANSessionMux_SocketBufferFull:
|
|
|
|
|
return HAL_WARN_CANSessionMux_SocketBufferFull_MESSAGE;
|
2024-11-30 18:04:00 +00:00
|
|
|
case HAL_PWM_SCALE_ERROR:
|
|
|
|
|
return HAL_PWM_SCALE_ERROR_MESSAGE;
|
|
|
|
|
case HAL_SERIAL_PORT_NOT_FOUND:
|
|
|
|
|
return HAL_SERIAL_PORT_NOT_FOUND_MESSAGE;
|
|
|
|
|
case HAL_THREAD_PRIORITY_ERROR:
|
|
|
|
|
return HAL_THREAD_PRIORITY_ERROR_MESSAGE;
|
|
|
|
|
case HAL_THREAD_PRIORITY_RANGE_ERROR:
|
|
|
|
|
return HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE;
|
|
|
|
|
case HAL_SERIAL_PORT_OPEN_ERROR:
|
|
|
|
|
return HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE;
|
|
|
|
|
case HAL_SERIAL_PORT_ERROR:
|
|
|
|
|
return HAL_SERIAL_PORT_ERROR_MESSAGE;
|
|
|
|
|
case HAL_CAN_TIMEOUT:
|
|
|
|
|
return HAL_CAN_TIMEOUT_MESSAGE;
|
|
|
|
|
case HAL_CAN_BUFFER_OVERRUN:
|
|
|
|
|
return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
|
|
|
|
|
case HAL_LED_CHANNEL_ERROR:
|
|
|
|
|
return HAL_LED_CHANNEL_ERROR_MESSAGE;
|
|
|
|
|
case HAL_INVALID_DMA_STATE:
|
|
|
|
|
return HAL_INVALID_DMA_STATE_MESSAGE;
|
|
|
|
|
case HAL_INVALID_DMA_ADDITION:
|
|
|
|
|
return HAL_INVALID_DMA_ADDITION_MESSAGE;
|
|
|
|
|
case HAL_USE_LAST_ERROR:
|
|
|
|
|
return HAL_USE_LAST_ERROR_MESSAGE;
|
|
|
|
|
case HAL_CONSOLE_OUT_ENABLED_ERROR:
|
|
|
|
|
return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
|
|
|
|
|
default:
|
|
|
|
|
return "Unknown error status";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HAL_RuntimeType runtimeType = HAL_Runtime_SystemCore;
|
|
|
|
|
|
|
|
|
|
HAL_RuntimeType HAL_GetRuntimeType(void) {
|
|
|
|
|
return runtimeType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_GetSerialNumber(struct WPI_String* serialNumber) {
|
|
|
|
|
const char* serialNum = std::getenv("serialnum");
|
|
|
|
|
if (!serialNum) {
|
|
|
|
|
serialNum = "";
|
|
|
|
|
}
|
|
|
|
|
size_t len = std::strlen(serialNum);
|
|
|
|
|
auto write = WPI_AllocateString(serialNumber, len);
|
|
|
|
|
std::memcpy(write, serialNum, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_GetComments(struct WPI_String* comments) {
|
|
|
|
|
comments->len = 0;
|
|
|
|
|
comments->str = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InitializeTeamNumber(void) {
|
|
|
|
|
char hostnameBuf[25];
|
|
|
|
|
auto status = gethostname(hostnameBuf, sizeof(hostnameBuf));
|
|
|
|
|
if (status != 0) {
|
|
|
|
|
teamNumber = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string_view hostname{hostnameBuf, sizeof(hostnameBuf)};
|
|
|
|
|
|
|
|
|
|
// hostname is frc-{TEAM}-roborio
|
2025-01-05 20:53:43 -08:00
|
|
|
// Split string around '-' (max of 2 splits), take the second element
|
|
|
|
|
teamNumber = 0;
|
|
|
|
|
int i = 0;
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::util::split(hostname, '-', 2, false, [&](auto part) {
|
2025-01-05 20:53:43 -08:00
|
|
|
if (i == 1) {
|
2025-11-07 20:00:05 -05:00
|
|
|
teamNumber = wpi::util::parse_integer<int32_t>(part, 10).value_or(0);
|
2025-01-05 20:53:43 -08:00
|
|
|
}
|
|
|
|
|
++i;
|
|
|
|
|
});
|
2024-11-30 18:04:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t HAL_GetTeamNumber(void) {
|
|
|
|
|
if (teamNumber == -1) {
|
|
|
|
|
InitializeTeamNumber();
|
|
|
|
|
}
|
|
|
|
|
return teamNumber;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t HAL_GetFPGATime(int32_t* status) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::CheckInit();
|
|
|
|
|
return wpi::util::NowDefault();
|
2024-11-30 18:04:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
|
|
|
|
|
// Capture the current FPGA time. This will give us the upper half of the
|
|
|
|
|
// clock.
|
|
|
|
|
uint64_t fpgaTime = HAL_GetFPGATime(status);
|
|
|
|
|
if (*status != 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now, we need to detect the case where the lower bits rolled over after we
|
|
|
|
|
// sampled. In that case, the upper bits will be 1 bigger than they should
|
|
|
|
|
// be.
|
|
|
|
|
|
|
|
|
|
// Break it into lower and upper portions.
|
|
|
|
|
uint32_t lower = fpgaTime & 0xffffffffull;
|
|
|
|
|
uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
|
|
|
|
|
|
|
|
|
|
// The time was sampled *before* the current time, so roll it back.
|
|
|
|
|
if (lower < unexpandedLower) {
|
|
|
|
|
--upper;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAL_Bool HAL_GetSystemActive(int32_t* status) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::CheckInit();
|
2024-11-30 18:04:00 +00:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAL_Bool HAL_GetBrownedOut(int32_t* status) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::CheckInit();
|
2024-11-30 18:04:00 +00:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t HAL_GetCommsDisableCount(int32_t* status) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::CheckInit();
|
2024-11-30 18:04:00 +00:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAL_Bool HAL_GetRSLState(int32_t* status) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::CheckInit();
|
2024-11-30 18:04:00 +00:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
|
|
|
|
|
static std::atomic_bool initialized{false};
|
2025-11-07 20:00:05 -05:00
|
|
|
static wpi::util::mutex initializeMutex;
|
2024-11-30 18:04:00 +00:00
|
|
|
// Initial check, as if it's true initialization has finished
|
|
|
|
|
if (initialized) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::scoped_lock lock(initializeMutex);
|
|
|
|
|
// Second check in case another thread was waiting
|
|
|
|
|
if (initialized) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-31 10:53:11 -07:00
|
|
|
// Initialize system server first, other things might use it
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::InitializeSystemServer();
|
2025-05-31 10:53:11 -07:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::InitializeHAL();
|
2024-11-30 18:04:00 +00:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::HAL_IsInitialized.store(true);
|
2024-11-30 18:04:00 +00:00
|
|
|
|
|
|
|
|
setlinebuf(stdin);
|
|
|
|
|
setlinebuf(stdout);
|
|
|
|
|
|
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
|
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
if (!wpi::hal::InitializeCanBuses()) {
|
2024-12-08 12:01:28 -08:00
|
|
|
std::printf("Failed to initialize can buses\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-30 18:04:00 +00:00
|
|
|
// // Return false if program failed to kill an existing program
|
|
|
|
|
// if (!killExistingProgram(timeout, mode)) {
|
|
|
|
|
// return false;
|
|
|
|
|
// }
|
|
|
|
|
|
2025-11-07 20:00:43 -05:00
|
|
|
// WPILIB_NetworkCommunication_Reserve(nullptr);
|
2024-11-30 18:04:00 +00:00
|
|
|
|
|
|
|
|
int32_t status = 0;
|
|
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::InitializeDriverStation();
|
2024-11-30 18:04:00 +00:00
|
|
|
|
|
|
|
|
dsStartTime = HAL_GetFPGATime(&status);
|
|
|
|
|
if (status != 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::WaitForInitialPacket();
|
2024-11-30 18:04:00 +00:00
|
|
|
|
|
|
|
|
initialized = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_Shutdown(void) {}
|
|
|
|
|
|
|
|
|
|
void HAL_SimPeriodicBefore(void) {}
|
|
|
|
|
|
|
|
|
|
void HAL_SimPeriodicAfter(void) {}
|
|
|
|
|
|
|
|
|
|
} // extern "C"
|