mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-04 03:11:43 +00:00
Update to 2018_v4 image and new build system. (#598)
* Revert "Force OpenCV to 3.1.0 (#602)"
This reverts commit 50ed55e8e2.
* Removes Simulation
* Removes old build system
* Removes old gtest
* Adds new gmock and gtest
* Updates to new ni-libraries
* removes MyRobot (to be replaced)
* moves files to new location
* Adds new sim backend and new test executables
* updates .styleguide and .gitignore
* Changes cpp WPILibVersion to a function
MSVC throws an AV with the old version.
* Disables USBCamera on all systems except for linux
* 2018 NI Libraries
* New build system
This commit is contained in:
committed by
Peter Johnson
parent
50ed55e8e2
commit
e1195e8b9d
256
hal/src/main/native/athena/Accelerometer.cpp
Normal file
256
hal/src/main/native/athena/Accelerometer.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Accelerometer.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/HAL.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
// The 7-bit I2C address with a 0 "send" bit
|
||||
static const uint8_t kSendAddress = (0x1c << 1) | 0;
|
||||
|
||||
// The 7-bit I2C address with a 1 "receive" bit
|
||||
static const uint8_t kReceiveAddress = (0x1c << 1) | 1;
|
||||
|
||||
static const uint8_t kControlTxRx = 1;
|
||||
static const uint8_t kControlStart = 2;
|
||||
static const uint8_t kControlStop = 4;
|
||||
|
||||
static std::unique_ptr<tAccel> accel;
|
||||
static HAL_AccelerometerRange accelerometerRange;
|
||||
|
||||
// Register addresses
|
||||
enum Register {
|
||||
kReg_Status = 0x00,
|
||||
kReg_OutXMSB = 0x01,
|
||||
kReg_OutXLSB = 0x02,
|
||||
kReg_OutYMSB = 0x03,
|
||||
kReg_OutYLSB = 0x04,
|
||||
kReg_OutZMSB = 0x05,
|
||||
kReg_OutZLSB = 0x06,
|
||||
kReg_Sysmod = 0x0B,
|
||||
kReg_IntSource = 0x0C,
|
||||
kReg_WhoAmI = 0x0D,
|
||||
kReg_XYZDataCfg = 0x0E,
|
||||
kReg_HPFilterCutoff = 0x0F,
|
||||
kReg_PLStatus = 0x10,
|
||||
kReg_PLCfg = 0x11,
|
||||
kReg_PLCount = 0x12,
|
||||
kReg_PLBfZcomp = 0x13,
|
||||
kReg_PLThsReg = 0x14,
|
||||
kReg_FFMtCfg = 0x15,
|
||||
kReg_FFMtSrc = 0x16,
|
||||
kReg_FFMtThs = 0x17,
|
||||
kReg_FFMtCount = 0x18,
|
||||
kReg_TransientCfg = 0x1D,
|
||||
kReg_TransientSrc = 0x1E,
|
||||
kReg_TransientThs = 0x1F,
|
||||
kReg_TransientCount = 0x20,
|
||||
kReg_PulseCfg = 0x21,
|
||||
kReg_PulseSrc = 0x22,
|
||||
kReg_PulseThsx = 0x23,
|
||||
kReg_PulseThsy = 0x24,
|
||||
kReg_PulseThsz = 0x25,
|
||||
kReg_PulseTmlt = 0x26,
|
||||
kReg_PulseLtcy = 0x27,
|
||||
kReg_PulseWind = 0x28,
|
||||
kReg_ASlpCount = 0x29,
|
||||
kReg_CtrlReg1 = 0x2A,
|
||||
kReg_CtrlReg2 = 0x2B,
|
||||
kReg_CtrlReg3 = 0x2C,
|
||||
kReg_CtrlReg4 = 0x2D,
|
||||
kReg_CtrlReg5 = 0x2E,
|
||||
kReg_OffX = 0x2F,
|
||||
kReg_OffY = 0x30,
|
||||
kReg_OffZ = 0x31
|
||||
};
|
||||
|
||||
namespace hal {
|
||||
|
||||
static void writeRegister(Register reg, uint8_t data);
|
||||
static uint8_t readRegister(Register reg);
|
||||
|
||||
/**
|
||||
* Initialize the accelerometer.
|
||||
*/
|
||||
static void initializeAccelerometer() {
|
||||
int32_t status;
|
||||
|
||||
if (!accel) {
|
||||
accel.reset(tAccel::create(&status));
|
||||
|
||||
// Enable I2C
|
||||
accel->writeCNFG(1, &status);
|
||||
|
||||
// Set the counter to 100 kbps
|
||||
accel->writeCNTR(213, &status);
|
||||
|
||||
// The device identification number should be 0x2a
|
||||
assert(readRegister(kReg_WhoAmI) == 0x2a);
|
||||
}
|
||||
}
|
||||
|
||||
static void writeRegister(Register reg, uint8_t data) {
|
||||
int32_t status = 0;
|
||||
uint64_t initialTime;
|
||||
|
||||
accel->writeADDR(kSendAddress, &status);
|
||||
|
||||
// Send a start transmit/receive message with the register address
|
||||
accel->writeCNTL(kControlStart | kControlTxRx, &status);
|
||||
accel->writeDATO(reg, &status);
|
||||
accel->strobeGO(&status);
|
||||
|
||||
// Execute and wait until it's done (up to a millisecond)
|
||||
initialTime = HAL_GetFPGATime(&status);
|
||||
while (accel->readSTAT(&status) & 1) {
|
||||
if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
|
||||
}
|
||||
|
||||
// Send a stop transmit/receive message with the data
|
||||
accel->writeCNTL(kControlStop | kControlTxRx, &status);
|
||||
accel->writeDATO(data, &status);
|
||||
accel->strobeGO(&status);
|
||||
|
||||
// Execute and wait until it's done (up to a millisecond)
|
||||
initialTime = HAL_GetFPGATime(&status);
|
||||
while (accel->readSTAT(&status) & 1) {
|
||||
if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t readRegister(Register reg) {
|
||||
int32_t status = 0;
|
||||
uint64_t initialTime;
|
||||
|
||||
// Send a start transmit/receive message with the register address
|
||||
accel->writeADDR(kSendAddress, &status);
|
||||
accel->writeCNTL(kControlStart | kControlTxRx, &status);
|
||||
accel->writeDATO(reg, &status);
|
||||
accel->strobeGO(&status);
|
||||
|
||||
// Execute and wait until it's done (up to a millisecond)
|
||||
initialTime = HAL_GetFPGATime(&status);
|
||||
while (accel->readSTAT(&status) & 1) {
|
||||
if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
|
||||
}
|
||||
|
||||
// Receive a message with the data and stop
|
||||
accel->writeADDR(kReceiveAddress, &status);
|
||||
accel->writeCNTL(kControlStart | kControlStop | kControlTxRx, &status);
|
||||
accel->strobeGO(&status);
|
||||
|
||||
// Execute and wait until it's done (up to a millisecond)
|
||||
initialTime = HAL_GetFPGATime(&status);
|
||||
while (accel->readSTAT(&status) & 1) {
|
||||
if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
|
||||
}
|
||||
|
||||
return accel->readDATI(&status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a 12-bit raw acceleration value into a scaled double in units of
|
||||
* 1 g-force, taking into account the accelerometer range.
|
||||
*/
|
||||
static double unpackAxis(int16_t raw) {
|
||||
// The raw value is actually 12 bits, not 16, so we need to propogate the
|
||||
// 2's complement sign bit to the unused 4 bits for this to work with
|
||||
// negative numbers.
|
||||
raw <<= 4;
|
||||
raw >>= 4;
|
||||
|
||||
switch (accelerometerRange) {
|
||||
case HAL_AccelerometerRange_k2G:
|
||||
return raw / 1024.0;
|
||||
case HAL_AccelerometerRange_k4G:
|
||||
return raw / 512.0;
|
||||
case HAL_AccelerometerRange_k8G:
|
||||
return raw / 256.0;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* Set the accelerometer to active or standby mode. It must be in standby
|
||||
* mode to change any configuration.
|
||||
*/
|
||||
void HAL_SetAccelerometerActive(HAL_Bool active) {
|
||||
initializeAccelerometer();
|
||||
|
||||
uint8_t ctrlReg1 = readRegister(kReg_CtrlReg1);
|
||||
ctrlReg1 &= ~1; // Clear the existing active bit
|
||||
writeRegister(kReg_CtrlReg1, ctrlReg1 | (active ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the range of values that can be measured (either 2, 4, or 8 g-forces).
|
||||
* The accelerometer should be in standby mode when this is called.
|
||||
*/
|
||||
void HAL_SetAccelerometerRange(HAL_AccelerometerRange range) {
|
||||
initializeAccelerometer();
|
||||
|
||||
accelerometerRange = range;
|
||||
|
||||
uint8_t xyzDataCfg = readRegister(kReg_XYZDataCfg);
|
||||
xyzDataCfg &= ~3; // Clear the existing two range bits
|
||||
writeRegister(kReg_XYZDataCfg, xyzDataCfg | range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x-axis acceleration
|
||||
*
|
||||
* This is a floating point value in units of 1 g-force
|
||||
*/
|
||||
double HAL_GetAccelerometerX() {
|
||||
initializeAccelerometer();
|
||||
|
||||
int32_t raw =
|
||||
(readRegister(kReg_OutXMSB) << 4) | (readRegister(kReg_OutXLSB) >> 4);
|
||||
return unpackAxis(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y-axis acceleration
|
||||
*
|
||||
* This is a floating point value in units of 1 g-force
|
||||
*/
|
||||
double HAL_GetAccelerometerY() {
|
||||
initializeAccelerometer();
|
||||
|
||||
int32_t raw =
|
||||
(readRegister(kReg_OutYMSB) << 4) | (readRegister(kReg_OutYLSB) >> 4);
|
||||
return unpackAxis(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the z-axis acceleration
|
||||
*
|
||||
* This is a floating point value in units of 1 g-force
|
||||
*/
|
||||
double HAL_GetAccelerometerZ() {
|
||||
initializeAccelerometer();
|
||||
|
||||
int32_t raw =
|
||||
(readRegister(kReg_OutZMSB) << 4) | (readRegister(kReg_OutZLSB) >> 4);
|
||||
return unpackAxis(raw);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
196
hal/src/main/native/athena/AnalogAccumulator.cpp
Normal file
196
hal/src/main/native/athena/AnalogAccumulator.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/AnalogAccumulator.h"
|
||||
|
||||
#include "AnalogInternal.h"
|
||||
#include "HAL/HAL.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
extern "C" {
|
||||
/**
|
||||
* Is the channel attached to an accumulator.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
* @return The analog channel is attached to an accumulator.
|
||||
*/
|
||||
HAL_Bool HAL_IsAccumulatorChannel(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
for (int32_t i = 0; i < kNumAccumulators; i++) {
|
||||
if (port->channel == kAccumulatorChannels[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the accumulator.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
*/
|
||||
void HAL_InitAccumulator(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
if (!HAL_IsAccumulatorChannel(analogPortHandle, status)) {
|
||||
*status = HAL_INVALID_ACCUMULATOR_CHANNEL;
|
||||
return;
|
||||
}
|
||||
HAL_SetAccumulatorCenter(analogPortHandle, 0, status);
|
||||
HAL_ResetAccumulator(analogPortHandle, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the accumulator to the initial value.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
*/
|
||||
void HAL_ResetAccumulator(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (port->accumulator == nullptr) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
port->accumulator->strobeReset(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the center value of the accumulator.
|
||||
*
|
||||
* The center value is subtracted from each A/D value before it is added to the
|
||||
* accumulator. This is used for the center value of devices like gyros and
|
||||
* accelerometers to make integration work and to take the device offset into
|
||||
* account when integrating.
|
||||
*
|
||||
* This center value is based on the output of the oversampled and averaged
|
||||
* source from channel 1. Because of this, any non-zero oversample bits will
|
||||
* affect the size of the value for this field.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
* @param center The center value of the accumulator.
|
||||
*/
|
||||
void HAL_SetAccumulatorCenter(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t center, int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (port->accumulator == nullptr) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
port->accumulator->writeCenter(center, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the accumulator's deadband.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
* @param deadband The deadband of the accumulator.
|
||||
*/
|
||||
void HAL_SetAccumulatorDeadband(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t deadband, int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (port->accumulator == nullptr) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
port->accumulator->writeDeadband(deadband, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the accumulated value.
|
||||
*
|
||||
* Read the value that has been accumulating on channel 1.
|
||||
* The accumulator is attached after the oversample and average engine.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
* @return The 64-bit value accumulated since the last Reset().
|
||||
*/
|
||||
int64_t HAL_GetAccumulatorValue(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (port->accumulator == nullptr) {
|
||||
*status = NULL_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
int64_t value = port->accumulator->readOutput_Value(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the number of accumulated values.
|
||||
*
|
||||
* Read the count of the accumulated values since the accumulator was last
|
||||
* Reset().
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
* @return The number of times samples from the channel were accumulated.
|
||||
*/
|
||||
int64_t HAL_GetAccumulatorCount(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (port->accumulator == nullptr) {
|
||||
*status = NULL_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
return port->accumulator->readOutput_Count(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the accumulated value and the number of accumulated values atomically.
|
||||
*
|
||||
* This function reads the value and count from the FPGA atomically.
|
||||
* This can be used for averaging.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
* @param value Pointer to the 64-bit accumulated output.
|
||||
* @param count Pointer to the number of accumulation cycles.
|
||||
*/
|
||||
void HAL_GetAccumulatorOutput(HAL_AnalogInputHandle analogPortHandle,
|
||||
int64_t* value, int64_t* count, int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (port->accumulator == nullptr) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
if (value == nullptr || count == nullptr) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
tAccumulator::tOutput output = port->accumulator->readOutput(status);
|
||||
|
||||
*value = output.Value;
|
||||
*count = output.Count;
|
||||
}
|
||||
}
|
||||
241
hal/src/main/native/athena/AnalogGyro.cpp
Normal file
241
hal/src/main/native/athena/AnalogGyro.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/AnalogGyro.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "AnalogInternal.h"
|
||||
#include "HAL/AnalogAccumulator.h"
|
||||
#include "HAL/AnalogInput.h"
|
||||
#include "HAL/handles/IndexedHandleResource.h"
|
||||
|
||||
namespace {
|
||||
struct AnalogGyro {
|
||||
HAL_AnalogInputHandle handle;
|
||||
double voltsPerDegreePerSecond;
|
||||
double offset;
|
||||
int32_t center;
|
||||
};
|
||||
}
|
||||
|
||||
static constexpr uint32_t kOversampleBits = 10;
|
||||
static constexpr uint32_t kAverageBits = 0;
|
||||
static constexpr double kSamplesPerSecond = 50.0;
|
||||
static constexpr double kCalibrationSampleTime = 5.0;
|
||||
static constexpr double kDefaultVoltsPerDegreePerSecond = 0.007;
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
|
||||
HAL_HandleEnum::AnalogGyro>
|
||||
analogGyroHandles;
|
||||
|
||||
static void Wait(double seconds) {
|
||||
if (seconds < 0.0) return;
|
||||
std::this_thread::sleep_for(std::chrono::duration<double>(seconds));
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle analogHandle,
|
||||
int32_t* status) {
|
||||
if (!HAL_IsAccumulatorChannel(analogHandle, status)) {
|
||||
if (*status == 0) {
|
||||
*status = HAL_INVALID_ACCUMULATOR_CHANNEL;
|
||||
}
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
// handle known to be correct, so no need to type check
|
||||
int16_t channel = getHandleIndex(analogHandle);
|
||||
|
||||
auto handle = analogGyroHandles.Allocate(channel, status);
|
||||
|
||||
if (*status != 0)
|
||||
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
||||
|
||||
// Initialize port structure
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) { // would only error on thread issue
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
gyro->handle = analogHandle;
|
||||
gyro->voltsPerDegreePerSecond = 0;
|
||||
gyro->offset = 0;
|
||||
gyro->center = 0;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_SetupAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
gyro->voltsPerDegreePerSecond = kDefaultVoltsPerDegreePerSecond;
|
||||
|
||||
HAL_SetAnalogAverageBits(gyro->handle, kAverageBits, status);
|
||||
if (*status != 0) return;
|
||||
HAL_SetAnalogOversampleBits(gyro->handle, kOversampleBits, status);
|
||||
if (*status != 0) return;
|
||||
double sampleRate =
|
||||
kSamplesPerSecond * (1 << (kAverageBits + kOversampleBits));
|
||||
HAL_SetAnalogSampleRate(sampleRate, status);
|
||||
if (*status != 0) return;
|
||||
Wait(0.1);
|
||||
|
||||
HAL_SetAnalogGyroDeadband(handle, 0.0, status);
|
||||
if (*status != 0) return;
|
||||
}
|
||||
|
||||
void HAL_FreeAnalogGyro(HAL_GyroHandle handle) {
|
||||
analogGyroHandles.Free(handle);
|
||||
}
|
||||
|
||||
void HAL_SetAnalogGyroParameters(HAL_GyroHandle handle,
|
||||
double voltsPerDegreePerSecond, double offset,
|
||||
int32_t center, int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
gyro->voltsPerDegreePerSecond = voltsPerDegreePerSecond;
|
||||
gyro->offset = offset;
|
||||
gyro->center = center;
|
||||
HAL_SetAccumulatorCenter(gyro->handle, center, status);
|
||||
}
|
||||
|
||||
void HAL_SetAnalogGyroVoltsPerDegreePerSecond(HAL_GyroHandle handle,
|
||||
double voltsPerDegreePerSecond,
|
||||
int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
gyro->voltsPerDegreePerSecond = voltsPerDegreePerSecond;
|
||||
}
|
||||
|
||||
void HAL_ResetAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
HAL_ResetAccumulator(gyro->handle, status);
|
||||
if (*status != 0) return;
|
||||
|
||||
const double sampleTime = 1.0 / HAL_GetAnalogSampleRate(status);
|
||||
const double overSamples =
|
||||
1 << HAL_GetAnalogOversampleBits(gyro->handle, status);
|
||||
const double averageSamples =
|
||||
1 << HAL_GetAnalogAverageBits(gyro->handle, status);
|
||||
if (*status != 0) return;
|
||||
Wait(sampleTime * overSamples * averageSamples);
|
||||
}
|
||||
|
||||
void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_InitAccumulator(gyro->handle, status);
|
||||
if (*status != 0) return;
|
||||
Wait(kCalibrationSampleTime);
|
||||
|
||||
int64_t value;
|
||||
int64_t count;
|
||||
HAL_GetAccumulatorOutput(gyro->handle, &value, &count, status);
|
||||
if (*status != 0) return;
|
||||
|
||||
gyro->center = static_cast<int32_t>(
|
||||
static_cast<double>(value) / static_cast<double>(count) + .5);
|
||||
|
||||
gyro->offset = static_cast<double>(value) / static_cast<double>(count) -
|
||||
static_cast<double>(gyro->center);
|
||||
HAL_SetAccumulatorCenter(gyro->handle, gyro->center, status);
|
||||
if (*status != 0) return;
|
||||
HAL_ResetAnalogGyro(handle, status);
|
||||
}
|
||||
|
||||
void HAL_SetAnalogGyroDeadband(HAL_GyroHandle handle, double volts,
|
||||
int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
int32_t deadband = static_cast<int32_t>(
|
||||
volts * 1e9 / HAL_GetAnalogLSBWeight(gyro->handle, status) *
|
||||
(1 << HAL_GetAnalogOversampleBits(gyro->handle, status)));
|
||||
if (*status != 0) return;
|
||||
HAL_SetAccumulatorDeadband(gyro->handle, deadband, status);
|
||||
}
|
||||
|
||||
double HAL_GetAnalogGyroAngle(HAL_GyroHandle handle, int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
int64_t rawValue = 0;
|
||||
int64_t count = 0;
|
||||
HAL_GetAccumulatorOutput(gyro->handle, &rawValue, &count, status);
|
||||
|
||||
int64_t value = rawValue - static_cast<int64_t>(static_cast<double>(count) *
|
||||
gyro->offset);
|
||||
|
||||
double scaledValue =
|
||||
value * 1e-9 *
|
||||
static_cast<double>(HAL_GetAnalogLSBWeight(gyro->handle, status)) *
|
||||
static_cast<double>(1 << HAL_GetAnalogAverageBits(gyro->handle, status)) /
|
||||
(HAL_GetAnalogSampleRate(status) * gyro->voltsPerDegreePerSecond);
|
||||
|
||||
return scaledValue;
|
||||
}
|
||||
|
||||
double HAL_GetAnalogGyroRate(HAL_GyroHandle handle, int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (HAL_GetAnalogAverageValue(gyro->handle, status) -
|
||||
(static_cast<double>(gyro->center) + gyro->offset)) *
|
||||
1e-9 * HAL_GetAnalogLSBWeight(gyro->handle, status) /
|
||||
((1 << HAL_GetAnalogOversampleBits(gyro->handle, status)) *
|
||||
gyro->voltsPerDegreePerSecond);
|
||||
}
|
||||
|
||||
double HAL_GetAnalogGyroOffset(HAL_GyroHandle handle, int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return gyro->offset;
|
||||
}
|
||||
|
||||
int32_t HAL_GetAnalogGyroCenter(HAL_GyroHandle handle, int32_t* status) {
|
||||
auto gyro = analogGyroHandles.Get(handle);
|
||||
if (gyro == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return gyro->center;
|
||||
}
|
||||
}
|
||||
385
hal/src/main/native/athena/AnalogInput.cpp
Normal file
385
hal/src/main/native/athena/AnalogInput.cpp
Normal file
@@ -0,0 +1,385 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/AnalogInput.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "AnalogInternal.h"
|
||||
#include "FRC_NetworkCommunication/AICalibration.h"
|
||||
#include "HAL/AnalogAccumulator.h"
|
||||
#include "HAL/HAL.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
extern "C" {
|
||||
/**
|
||||
* Initialize the analog input port using the given port object.
|
||||
*
|
||||
* @param portHandle Handle to the port to initialize.
|
||||
*/
|
||||
HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle,
|
||||
int32_t* status) {
|
||||
initializeAnalog(status);
|
||||
|
||||
if (*status != 0) return HAL_kInvalidHandle;
|
||||
|
||||
int16_t channel = getPortHandleChannel(portHandle);
|
||||
if (channel == InvalidHandleIndex) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
HAL_AnalogInputHandle handle = analogInputHandles.Allocate(channel, status);
|
||||
|
||||
if (*status != 0)
|
||||
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
||||
|
||||
// Initialize port structure
|
||||
auto analog_port = analogInputHandles.Get(handle);
|
||||
if (analog_port == nullptr) { // would only error on thread issue
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
analog_port->channel = static_cast<uint8_t>(channel);
|
||||
if (HAL_IsAccumulatorChannel(handle, status)) {
|
||||
analog_port->accumulator.reset(tAccumulator::create(channel, status));
|
||||
} else {
|
||||
analog_port->accumulator = nullptr;
|
||||
}
|
||||
|
||||
// Set default configuration
|
||||
analogInputSystem->writeScanList(channel, channel, status);
|
||||
HAL_SetAnalogAverageBits(handle, kDefaultAverageBits, status);
|
||||
HAL_SetAnalogOversampleBits(handle, kDefaultOversampleBits, status);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param analogPortHandle Handle to the analog port.
|
||||
*/
|
||||
void HAL_FreeAnalogInputPort(HAL_AnalogInputHandle analogPortHandle) {
|
||||
// no status, so no need to check for a proper free.
|
||||
analogInputHandles.Free(analogPortHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the analog module number is valid.
|
||||
*
|
||||
* @param module The analog module number.
|
||||
* @return Analog module is valid and present
|
||||
*/
|
||||
HAL_Bool HAL_CheckAnalogModule(int32_t module) { return module == 1; }
|
||||
|
||||
/**
|
||||
* Check that the analog output channel number is value.
|
||||
* Verify that the analog channel number is one of the legal channel numbers.
|
||||
* Channel numbers are 0-based.
|
||||
*
|
||||
* @param channel The analog output channel number.
|
||||
* @return Analog channel is valid
|
||||
*/
|
||||
HAL_Bool HAL_CheckAnalogInputChannel(int32_t channel) {
|
||||
return channel < kNumAnalogInputs && channel >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sample rate.
|
||||
*
|
||||
* This is a global setting for the Athena and effects all channels.
|
||||
*
|
||||
* @param samplesPerSecond The number of samples per channel per second.
|
||||
*/
|
||||
void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status) {
|
||||
// TODO: This will change when variable size scan lists are implemented.
|
||||
// TODO: Need double comparison with epsilon.
|
||||
// wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond);
|
||||
initializeAnalog(status);
|
||||
if (*status != 0) return;
|
||||
setAnalogSampleRate(samplesPerSecond, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current sample rate.
|
||||
*
|
||||
* This assumes one entry in the scan list.
|
||||
* This is a global setting for the Athena and effects all channels.
|
||||
*
|
||||
* @return Sample rate.
|
||||
*/
|
||||
double HAL_GetAnalogSampleRate(int32_t* status) {
|
||||
initializeAnalog(status);
|
||||
if (*status != 0) return 0;
|
||||
uint32_t ticksPerConversion = analogInputSystem->readLoopTiming(status);
|
||||
uint32_t ticksPerSample =
|
||||
ticksPerConversion * getAnalogNumActiveChannels(status);
|
||||
return static_cast<double>(kTimebase) / static_cast<double>(ticksPerSample);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of averaging bits.
|
||||
*
|
||||
* This sets the number of averaging bits. The actual number of averaged samples
|
||||
* is 2**bits. Use averaging to improve the stability of your measurement at the
|
||||
* expense of sampling rate. The averaging is done automatically in the FPGA.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to configure.
|
||||
* @param bits Number of bits to average.
|
||||
*/
|
||||
void HAL_SetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t bits, int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
analogInputSystem->writeAverageBits(port->channel, static_cast<uint8_t>(bits),
|
||||
status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of averaging bits.
|
||||
*
|
||||
* This gets the number of averaging bits from the FPGA. The actual number of
|
||||
* averaged samples is 2**bits. The averaging is done automatically in the FPGA.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @return Bits to average.
|
||||
*/
|
||||
int32_t HAL_GetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return kDefaultAverageBits;
|
||||
}
|
||||
uint8_t result = analogInputSystem->readAverageBits(port->channel, status);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of oversample bits.
|
||||
*
|
||||
* This sets the number of oversample bits. The actual number of oversampled
|
||||
* values is 2**bits. Use oversampling to improve the resolution of your
|
||||
* measurements at the expense of sampling rate. The oversampling is done
|
||||
* automatically in the FPGA.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @param bits Number of bits to oversample.
|
||||
*/
|
||||
void HAL_SetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t bits, int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
analogInputSystem->writeOversampleBits(port->channel,
|
||||
static_cast<uint8_t>(bits), status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of oversample bits.
|
||||
*
|
||||
* This gets the number of oversample bits from the FPGA. The actual number of
|
||||
* oversampled values is 2**bits. The oversampling is done automatically in the
|
||||
* FPGA.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @return Bits to oversample.
|
||||
*/
|
||||
int32_t HAL_GetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return kDefaultOversampleBits;
|
||||
}
|
||||
uint8_t result = analogInputSystem->readOversampleBits(port->channel, status);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sample straight from the channel on this module.
|
||||
*
|
||||
* The sample is a 12-bit value representing the 0V to 5V range of the A/D
|
||||
* converter in the module. The units are in A/D converter codes. Use
|
||||
* GetVoltage() to get the analog value in calibrated units.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @return A sample straight from the channel on this module.
|
||||
*/
|
||||
int32_t HAL_GetAnalogValue(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tAI::tReadSelect readSelect;
|
||||
readSelect.Channel = port->channel;
|
||||
readSelect.Averaged = false;
|
||||
|
||||
std::lock_guard<priority_recursive_mutex> sync(analogRegisterWindowMutex);
|
||||
analogInputSystem->writeReadSelect(readSelect, status);
|
||||
analogInputSystem->strobeLatchOutput(status);
|
||||
return static_cast<int16_t>(analogInputSystem->readOutput(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sample from the output of the oversample and average engine for the
|
||||
* channel.
|
||||
*
|
||||
* The sample is 12-bit + the value configured in SetOversampleBits().
|
||||
* The value configured in SetAverageBits() will cause this value to be averaged
|
||||
* 2**bits number of samples. This is not a sliding window. The sample will not
|
||||
* change until 2**(OversamplBits + AverageBits) samples have been acquired from
|
||||
* the module on this channel. Use GetAverageVoltage() to get the analog value
|
||||
* in calibrated units.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @return A sample from the oversample and average engine for the channel.
|
||||
*/
|
||||
int32_t HAL_GetAnalogAverageValue(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
tAI::tReadSelect readSelect;
|
||||
readSelect.Channel = port->channel;
|
||||
readSelect.Averaged = true;
|
||||
|
||||
std::lock_guard<priority_recursive_mutex> sync(analogRegisterWindowMutex);
|
||||
analogInputSystem->writeReadSelect(readSelect, status);
|
||||
analogInputSystem->strobeLatchOutput(status);
|
||||
return static_cast<int32_t>(analogInputSystem->readOutput(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a scaled sample straight from the channel on this module.
|
||||
*
|
||||
* The value is scaled to units of Volts using the calibrated scaling data from
|
||||
* GetLSBWeight() and GetOffset().
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @return A scaled sample straight from the channel on this module.
|
||||
*/
|
||||
double HAL_GetAnalogVoltage(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
int32_t value = HAL_GetAnalogValue(analogPortHandle, status);
|
||||
int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogPortHandle, status);
|
||||
int32_t offset = HAL_GetAnalogOffset(analogPortHandle, status);
|
||||
double voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a scaled sample from the output of the oversample and average engine for
|
||||
* the channel.
|
||||
*
|
||||
* The value is scaled to units of Volts using the calibrated scaling data from
|
||||
* GetLSBWeight() and GetOffset(). Using oversampling will cause this value to
|
||||
* be higher resolution, but it will update more slowly. Using averaging will
|
||||
* cause this value to be more stable, but it will update more slowly.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @return A scaled sample from the output of the oversample and average engine
|
||||
* for the channel.
|
||||
*/
|
||||
double HAL_GetAnalogAverageVoltage(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
int32_t value = HAL_GetAnalogAverageValue(analogPortHandle, status);
|
||||
int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogPortHandle, status);
|
||||
int32_t offset = HAL_GetAnalogOffset(analogPortHandle, status);
|
||||
int32_t oversampleBits =
|
||||
HAL_GetAnalogOversampleBits(analogPortHandle, status);
|
||||
double voltage =
|
||||
LSBWeight * 1.0e-9 * value / static_cast<double>(1 << oversampleBits) -
|
||||
offset * 1.0e-9;
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a voltage to a raw value for a specified channel.
|
||||
*
|
||||
* This process depends on the calibration of each channel, so the channel must
|
||||
* be specified.
|
||||
*
|
||||
* @todo This assumes raw values. Oversampling not supported as is.
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @param voltage The voltage to convert.
|
||||
* @return The raw value for the channel.
|
||||
*/
|
||||
int32_t HAL_GetAnalogVoltsToValue(HAL_AnalogInputHandle analogPortHandle,
|
||||
double voltage, int32_t* status) {
|
||||
if (voltage > 5.0) {
|
||||
voltage = 5.0;
|
||||
*status = VOLTAGE_OUT_OF_RANGE;
|
||||
}
|
||||
if (voltage < 0.0) {
|
||||
voltage = 0.0;
|
||||
*status = VOLTAGE_OUT_OF_RANGE;
|
||||
}
|
||||
int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogPortHandle, status);
|
||||
int32_t offset = HAL_GetAnalogOffset(analogPortHandle, status);
|
||||
int32_t value =
|
||||
static_cast<int32_t>((voltage + offset * 1.0e-9) / (LSBWeight * 1.0e-9));
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the factory scaling least significant bit weight constant.
|
||||
* The least significant bit weight constant for the channel that was calibrated
|
||||
* in manufacturing and stored in an eeprom in the module.
|
||||
*
|
||||
* Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @return Least significant bit weight.
|
||||
*/
|
||||
int32_t HAL_GetAnalogLSBWeight(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
int32_t lsbWeight = FRC_NetworkCommunication_nAICalibration_getLSBWeight(
|
||||
0, port->channel, status); // XXX: aiSystemIndex == 0?
|
||||
return lsbWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the factory scaling offset constant.
|
||||
* The offset constant for the channel that was calibrated in manufacturing and
|
||||
* stored in an eeprom in the module.
|
||||
*
|
||||
* Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
|
||||
*
|
||||
* @param analogPortHandle Handle to the analog port to use.
|
||||
* @return Offset constant.
|
||||
*/
|
||||
int32_t HAL_GetAnalogOffset(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogInputHandles.Get(analogPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
int32_t offset = FRC_NetworkCommunication_nAICalibration_getOffset(
|
||||
0, port->channel, status); // XXX: aiSystemIndex == 0?
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
121
hal/src/main/native/athena/AnalogInternal.cpp
Normal file
121
hal/src/main/native/athena/AnalogInternal.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "AnalogInternal.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "HAL/AnalogInput.h"
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
namespace hal {
|
||||
priority_recursive_mutex analogRegisterWindowMutex;
|
||||
std::unique_ptr<tAI> analogInputSystem;
|
||||
std::unique_ptr<tAO> analogOutputSystem;
|
||||
|
||||
IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort, kNumAnalogInputs,
|
||||
HAL_HandleEnum::AnalogInput>
|
||||
analogInputHandles;
|
||||
|
||||
static int32_t analogNumChannelsToActivate = 0;
|
||||
|
||||
static std::atomic<bool> analogSystemInitialized{false};
|
||||
|
||||
bool analogSampleRateSet = false;
|
||||
|
||||
/**
|
||||
* Initialize the analog System.
|
||||
*/
|
||||
void initializeAnalog(int32_t* status) {
|
||||
if (analogSystemInitialized) return;
|
||||
std::lock_guard<priority_recursive_mutex> sync(analogRegisterWindowMutex);
|
||||
if (analogSystemInitialized) return;
|
||||
analogInputSystem.reset(tAI::create(status));
|
||||
analogOutputSystem.reset(tAO::create(status));
|
||||
setAnalogNumChannelsToActivate(kNumAnalogInputs);
|
||||
setAnalogSampleRate(kDefaultSampleRate, status);
|
||||
analogSystemInitialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of channels on the module in use.
|
||||
*
|
||||
* @return Active channels.
|
||||
*/
|
||||
int32_t getAnalogNumActiveChannels(int32_t* status) {
|
||||
int32_t scanSize = analogInputSystem->readConfig_ScanSize(status);
|
||||
if (scanSize == 0) return 8;
|
||||
return scanSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of active channels.
|
||||
*
|
||||
* This is an internal function to allow the atomic update of both the
|
||||
* number of active channels and the sample rate.
|
||||
*
|
||||
* When the number of channels changes, use the new value. Otherwise,
|
||||
* return the curent value.
|
||||
*
|
||||
* @return Value to write to the active channels field.
|
||||
*/
|
||||
int32_t getAnalogNumChannelsToActivate(int32_t* status) {
|
||||
if (analogNumChannelsToActivate == 0)
|
||||
return getAnalogNumActiveChannels(status);
|
||||
return analogNumChannelsToActivate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sample rate.
|
||||
*
|
||||
* This is a global setting for the Athena and effects all channels.
|
||||
*
|
||||
* @param samplesPerSecond The number of samples per channel per second.
|
||||
*/
|
||||
void setAnalogSampleRate(double samplesPerSecond, int32_t* status) {
|
||||
// TODO: This will change when variable size scan lists are implemented.
|
||||
// TODO: Need double comparison with epsilon.
|
||||
// wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond);
|
||||
analogSampleRateSet = true;
|
||||
|
||||
// Compute the convert rate
|
||||
uint32_t ticksPerSample =
|
||||
static_cast<uint32_t>(static_cast<double>(kTimebase) / samplesPerSecond);
|
||||
uint32_t ticksPerConversion =
|
||||
ticksPerSample / getAnalogNumChannelsToActivate(status);
|
||||
// ticksPerConversion must be at least 80
|
||||
if (ticksPerConversion < 80) {
|
||||
if ((*status) >= 0) *status = SAMPLE_RATE_TOO_HIGH;
|
||||
ticksPerConversion = 80;
|
||||
}
|
||||
|
||||
// Atomically set the scan size and the convert rate so that the sample rate
|
||||
// is constant
|
||||
tAI::tConfig config;
|
||||
config.ScanSize = getAnalogNumChannelsToActivate(status);
|
||||
config.ConvertRate = ticksPerConversion;
|
||||
analogInputSystem->writeConfig(config, status);
|
||||
|
||||
// Indicate that the scan size has been commited to hardware.
|
||||
setAnalogNumChannelsToActivate(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of active channels.
|
||||
*
|
||||
* Store the number of active channels to set. Don't actually commit to
|
||||
* hardware
|
||||
* until SetSampleRate().
|
||||
*
|
||||
* @param channels Number of active channels.
|
||||
*/
|
||||
void setAnalogNumChannelsToActivate(int32_t channels) {
|
||||
analogNumChannelsToActivate = channels;
|
||||
}
|
||||
} // namespace hal
|
||||
46
hal/src/main/native/athena/AnalogInternal.h
Normal file
46
hal/src/main/native/athena/AnalogInternal.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/Ports.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/IndexedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
namespace hal {
|
||||
constexpr int32_t kTimebase = 40000000; ///< 40 MHz clock
|
||||
constexpr int32_t kDefaultOversampleBits = 0;
|
||||
constexpr int32_t kDefaultAverageBits = 7;
|
||||
constexpr double kDefaultSampleRate = 50000.0;
|
||||
static const uint32_t kAccumulatorChannels[] = {0, 1};
|
||||
|
||||
extern std::unique_ptr<tAI> analogInputSystem;
|
||||
extern std::unique_ptr<tAO> analogOutputSystem;
|
||||
extern priority_recursive_mutex analogRegisterWindowMutex;
|
||||
extern bool analogSampleRateSet;
|
||||
|
||||
struct AnalogPort {
|
||||
uint8_t channel;
|
||||
std::unique_ptr<tAccumulator> accumulator;
|
||||
};
|
||||
|
||||
extern IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort,
|
||||
kNumAnalogInputs, HAL_HandleEnum::AnalogInput>
|
||||
analogInputHandles;
|
||||
|
||||
int32_t getAnalogNumActiveChannels(int32_t* status);
|
||||
int32_t getAnalogNumChannelsToActivate(int32_t* status);
|
||||
void setAnalogNumChannelsToActivate(int32_t channels);
|
||||
void setAnalogSampleRate(double samplesPerSecond, int32_t* status);
|
||||
void initializeAnalog(int32_t* status);
|
||||
} // namespace hal
|
||||
106
hal/src/main/native/athena/AnalogOutput.cpp
Normal file
106
hal/src/main/native/athena/AnalogOutput.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/AnalogOutput.h"
|
||||
|
||||
#include "AnalogInternal.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "HAL/handles/IndexedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace {
|
||||
struct AnalogOutput {
|
||||
uint8_t channel;
|
||||
};
|
||||
}
|
||||
|
||||
static IndexedHandleResource<HAL_AnalogOutputHandle, AnalogOutput,
|
||||
kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>
|
||||
analogOutputHandles;
|
||||
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* Initialize the analog output port using the given port object.
|
||||
*/
|
||||
HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle,
|
||||
int32_t* status) {
|
||||
initializeAnalog(status);
|
||||
|
||||
if (*status != 0) return HAL_kInvalidHandle;
|
||||
|
||||
int16_t channel = getPortHandleChannel(portHandle);
|
||||
if (channel == InvalidHandleIndex) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
HAL_AnalogOutputHandle handle = analogOutputHandles.Allocate(channel, status);
|
||||
|
||||
if (*status != 0)
|
||||
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
||||
|
||||
auto port = analogOutputHandles.Get(handle);
|
||||
if (port == nullptr) { // would only error on thread issue
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
port->channel = static_cast<uint8_t>(channel);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_FreeAnalogOutputPort(HAL_AnalogOutputHandle analogOutputHandle) {
|
||||
// no status, so no need to check for a proper free.
|
||||
analogOutputHandles.Free(analogOutputHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the analog output channel number is value.
|
||||
* Verify that the analog channel number is one of the legal channel numbers.
|
||||
* Channel numbers are 0-based.
|
||||
*
|
||||
* @return Analog channel is valid
|
||||
*/
|
||||
HAL_Bool HAL_CheckAnalogOutputChannel(int32_t channel) {
|
||||
return channel < kNumAnalogOutputs && channel >= 0;
|
||||
}
|
||||
|
||||
void HAL_SetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
|
||||
double voltage, int32_t* status) {
|
||||
auto port = analogOutputHandles.Get(analogOutputHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t rawValue = static_cast<uint16_t>(voltage / 5.0 * 0x1000);
|
||||
|
||||
if (voltage < 0.0)
|
||||
rawValue = 0;
|
||||
else if (voltage > 5.0)
|
||||
rawValue = 0x1000;
|
||||
|
||||
analogOutputSystem->writeMXP(port->channel, rawValue, status);
|
||||
}
|
||||
|
||||
double HAL_GetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
|
||||
int32_t* status) {
|
||||
auto port = analogOutputHandles.Get(analogOutputHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
uint16_t rawValue = analogOutputSystem->readMXP(port->channel, status);
|
||||
|
||||
return rawValue * 5.0 / 0x1000;
|
||||
}
|
||||
}
|
||||
206
hal/src/main/native/athena/AnalogTrigger.cpp
Normal file
206
hal/src/main/native/athena/AnalogTrigger.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/AnalogTrigger.h"
|
||||
|
||||
#include "AnalogInternal.h"
|
||||
#include "HAL/AnalogInput.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "HAL/handles/LimitedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace {
|
||||
struct AnalogTrigger {
|
||||
std::unique_ptr<tAnalogTrigger> trigger;
|
||||
HAL_AnalogInputHandle analogHandle;
|
||||
uint8_t index;
|
||||
};
|
||||
}
|
||||
|
||||
static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
|
||||
kNumAnalogTriggers, HAL_HandleEnum::AnalogTrigger>
|
||||
analogTriggerHandles;
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
|
||||
HAL_AnalogInputHandle portHandle, int32_t* index, int32_t* status) {
|
||||
// ensure we are given a valid and active AnalogInput handle
|
||||
auto analog_port = analogInputHandles.Get(portHandle);
|
||||
if (analog_port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
HAL_AnalogTriggerHandle handle = analogTriggerHandles.Allocate();
|
||||
if (handle == HAL_kInvalidHandle) {
|
||||
*status = NO_AVAILABLE_RESOURCES;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
auto trigger = analogTriggerHandles.Get(handle);
|
||||
if (trigger == nullptr) { // would only occur on thread issue
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
trigger->analogHandle = portHandle;
|
||||
trigger->index = static_cast<uint8_t>(getHandleIndex(handle));
|
||||
*index = trigger->index;
|
||||
|
||||
trigger->trigger.reset(tAnalogTrigger::create(trigger->index, status));
|
||||
trigger->trigger->writeSourceSelect_Channel(analog_port->channel, status);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
int32_t* status) {
|
||||
analogTriggerHandles.Free(analogTriggerHandle);
|
||||
// caller owns the analog input handle.
|
||||
}
|
||||
|
||||
void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
int32_t lower, int32_t upper,
|
||||
int32_t* status) {
|
||||
auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
|
||||
if (trigger == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (lower > upper) {
|
||||
*status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
|
||||
}
|
||||
trigger->trigger->writeLowerLimit(lower, status);
|
||||
trigger->trigger->writeUpperLimit(upper, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upper and lower limits of the analog trigger.
|
||||
* The limits are given as floating point voltage values.
|
||||
*/
|
||||
void HAL_SetAnalogTriggerLimitsVoltage(
|
||||
HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
|
||||
int32_t* status) {
|
||||
auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
|
||||
if (trigger == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (lower > upper) {
|
||||
*status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
|
||||
}
|
||||
|
||||
// TODO: This depends on the averaged setting. Only raw values will work as
|
||||
// is.
|
||||
trigger->trigger->writeLowerLimit(
|
||||
HAL_GetAnalogVoltsToValue(trigger->analogHandle, lower, status), status);
|
||||
trigger->trigger->writeUpperLimit(
|
||||
HAL_GetAnalogVoltsToValue(trigger->analogHandle, upper, status), status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the analog trigger to use the averaged vs. raw values.
|
||||
* If the value is true, then the averaged value is selected for the analog
|
||||
* trigger, otherwise the immediate value is used.
|
||||
*/
|
||||
void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
HAL_Bool useAveragedValue, int32_t* status) {
|
||||
auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
|
||||
if (trigger == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (trigger->trigger->readSourceSelect_Filter(status) != 0) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
// TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not
|
||||
// support average and filtering at the same time.");
|
||||
}
|
||||
trigger->trigger->writeSourceSelect_Averaged(useAveragedValue, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the analog trigger to use a filtered value.
|
||||
* The analog trigger will operate with a 3 point average rejection filter. This
|
||||
* is designed to help with 360 degree pot applications for the period where the
|
||||
* pot crosses through zero.
|
||||
*/
|
||||
void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
HAL_Bool useFilteredValue, int32_t* status) {
|
||||
auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
|
||||
if (trigger == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (trigger->trigger->readSourceSelect_Averaged(status) != 0) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
// TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not "
|
||||
// "support average and filtering at the same time.");
|
||||
}
|
||||
trigger->trigger->writeSourceSelect_Filter(useFilteredValue, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the InWindow output of the analog trigger.
|
||||
* True if the analog input is between the upper and lower limits.
|
||||
* @return The InWindow output of the analog trigger.
|
||||
*/
|
||||
HAL_Bool HAL_GetAnalogTriggerInWindow(
|
||||
HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
|
||||
auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
|
||||
if (trigger == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
return trigger->trigger->readOutput_InHysteresis(trigger->index, status) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TriggerState output of the analog trigger.
|
||||
* True if above upper limit.
|
||||
* False if below lower limit.
|
||||
* If in Hysteresis, maintain previous state.
|
||||
* @return The TriggerState output of the analog trigger.
|
||||
*/
|
||||
HAL_Bool HAL_GetAnalogTriggerTriggerState(
|
||||
HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
|
||||
auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
|
||||
if (trigger == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
return trigger->trigger->readOutput_OverLimit(trigger->index, status) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of the analog trigger output.
|
||||
* @return The state of the analog trigger output.
|
||||
*/
|
||||
HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
HAL_AnalogTriggerType type,
|
||||
int32_t* status) {
|
||||
auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
|
||||
if (trigger == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool result = false;
|
||||
switch (type) {
|
||||
case HAL_Trigger_kInWindow:
|
||||
result =
|
||||
trigger->trigger->readOutput_InHysteresis(trigger->index, status);
|
||||
break; // XXX: Backport
|
||||
case HAL_Trigger_kState:
|
||||
result = trigger->trigger->readOutput_OverLimit(trigger->index, status);
|
||||
break; // XXX: Backport
|
||||
case HAL_Trigger_kRisingPulse:
|
||||
case HAL_Trigger_kFallingPulse:
|
||||
*status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
193
hal/src/main/native/athena/Compressor.cpp
Normal file
193
hal/src/main/native/athena/Compressor.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Compressor.h"
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "PCMInternal.h"
|
||||
#include "PortsInternal.h"
|
||||
#include "ctre/PCM.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_CompressorHandle HAL_InitializeCompressor(int32_t module, int32_t* status) {
|
||||
// Use status to check for invalid index
|
||||
initializePCM(module, status);
|
||||
if (*status != 0) {
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
// As compressors can have unlimited objects, just create a
|
||||
// handle with the module number as the index.
|
||||
|
||||
return (HAL_CompressorHandle)createHandle(static_cast<int16_t>(module),
|
||||
HAL_HandleEnum::Compressor, 0);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_CheckCompressorModule(int32_t module) {
|
||||
return module < kNumPCMModules && module >= 0;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetCompressor(HAL_CompressorHandle compressorHandle,
|
||||
int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetCompressor(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void HAL_SetCompressorClosedLoopControl(HAL_CompressorHandle compressorHandle,
|
||||
HAL_Bool value, int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
*status = PCM_modules[index]->SetClosedLoopControl(value);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetCompressorClosedLoopControl(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetClosedLoopControl(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetCompressorPressureSwitch(HAL_CompressorHandle compressorHandle,
|
||||
int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetPressure(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
double HAL_GetCompressorCurrent(HAL_CompressorHandle compressorHandle,
|
||||
int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
float value;
|
||||
|
||||
*status = PCM_modules[index]->GetCompressorCurrent(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
HAL_Bool HAL_GetCompressorCurrentTooHighFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetCompressorCurrentTooHighFault(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
HAL_Bool HAL_GetCompressorCurrentTooHighStickyFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetCompressorCurrentTooHighStickyFault(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
HAL_Bool HAL_GetCompressorShortedStickyFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetCompressorShortedStickyFault(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
HAL_Bool HAL_GetCompressorShortedFault(HAL_CompressorHandle compressorHandle,
|
||||
int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetCompressorShortedFault(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
HAL_Bool HAL_GetCompressorNotConnectedStickyFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetCompressorNotConnectedStickyFault(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
HAL_Bool HAL_GetCompressorNotConnectedFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status) {
|
||||
int16_t index =
|
||||
getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
|
||||
if (index == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[index]->GetCompressorNotConnectedFault(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
} // extern "C"
|
||||
18
hal/src/main/native/athena/Constants.cpp
Normal file
18
hal/src/main/native/athena/Constants.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Constants.h"
|
||||
|
||||
#include "ConstantsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
extern "C" {
|
||||
int32_t HAL_GetSystemClockTicksPerMicrosecond(void) {
|
||||
return kSystemClockTicksPerMicrosecond;
|
||||
}
|
||||
}
|
||||
14
hal/src/main/native/athena/ConstantsInternal.h
Normal file
14
hal/src/main/native/athena/ConstantsInternal.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace hal {
|
||||
constexpr int32_t kSystemClockTicksPerMicrosecond = 40;
|
||||
}
|
||||
466
hal/src/main/native/athena/Counter.cpp
Normal file
466
hal/src/main/native/athena/Counter.cpp
Normal file
@@ -0,0 +1,466 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Counter.h"
|
||||
|
||||
#include "ConstantsInternal.h"
|
||||
#include "DigitalInternal.h"
|
||||
#include "HAL/HAL.h"
|
||||
#include "HAL/handles/LimitedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace {
|
||||
struct Counter {
|
||||
std::unique_ptr<tCounter> counter;
|
||||
uint8_t index;
|
||||
};
|
||||
}
|
||||
|
||||
static LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
|
||||
HAL_HandleEnum::Counter>
|
||||
counterHandles;
|
||||
|
||||
extern "C" {
|
||||
HAL_CounterHandle HAL_InitializeCounter(HAL_Counter_Mode mode, int32_t* index,
|
||||
int32_t* status) {
|
||||
auto handle = counterHandles.Allocate();
|
||||
if (handle == HAL_kInvalidHandle) { // out of resources
|
||||
*status = NO_AVAILABLE_RESOURCES;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
auto counter = counterHandles.Get(handle);
|
||||
if (counter == nullptr) { // would only occur on thread issues
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
counter->index = static_cast<uint8_t>(getHandleIndex(handle));
|
||||
*index = counter->index;
|
||||
|
||||
counter->counter.reset(tCounter::create(counter->index, status));
|
||||
counter->counter->writeConfig_Mode(mode, status);
|
||||
counter->counter->writeTimerConfig_AverageSize(1, status);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_FreeCounter(HAL_CounterHandle counterHandle, int32_t* status) {
|
||||
counterHandles.Free(counterHandle);
|
||||
}
|
||||
|
||||
void HAL_SetCounterAverageSize(HAL_CounterHandle counterHandle, int32_t size,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeTimerConfig_AverageSize(size, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source object that causes the counter to count up.
|
||||
* Set the up counting DigitalSource.
|
||||
*/
|
||||
void HAL_SetCounterUpSource(HAL_CounterHandle counterHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
bool routingAnalogTrigger = false;
|
||||
uint8_t routingChannel = 0;
|
||||
uint8_t routingModule = 0;
|
||||
bool success =
|
||||
remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
|
||||
routingModule, routingAnalogTrigger);
|
||||
if (!success) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
counter->counter->writeConfig_UpSource_Module(routingModule, status);
|
||||
counter->counter->writeConfig_UpSource_Channel(routingChannel, status);
|
||||
counter->counter->writeConfig_UpSource_AnalogTrigger(routingAnalogTrigger,
|
||||
status);
|
||||
|
||||
if (counter->counter->readConfig_Mode(status) == HAL_Counter_kTwoPulse ||
|
||||
counter->counter->readConfig_Mode(status) ==
|
||||
HAL_Counter_kExternalDirection) {
|
||||
HAL_SetCounterUpSourceEdge(counterHandle, true, false, status);
|
||||
}
|
||||
counter->counter->strobeReset(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the edge sensitivity on an up counting source.
|
||||
* Set the up source to either detect rising edges or falling edges.
|
||||
*/
|
||||
void HAL_SetCounterUpSourceEdge(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool risingEdge, HAL_Bool fallingEdge,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeConfig_UpRisingEdge(risingEdge, status);
|
||||
counter->counter->writeConfig_UpFallingEdge(fallingEdge, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the up counting source to the counter.
|
||||
*/
|
||||
void HAL_ClearCounterUpSource(HAL_CounterHandle counterHandle,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeConfig_UpFallingEdge(false, status);
|
||||
counter->counter->writeConfig_UpRisingEdge(false, status);
|
||||
// Index 0 of digital is always 0.
|
||||
counter->counter->writeConfig_UpSource_Channel(0, status);
|
||||
counter->counter->writeConfig_UpSource_AnalogTrigger(false, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source object that causes the counter to count down.
|
||||
* Set the down counting DigitalSource.
|
||||
*/
|
||||
void HAL_SetCounterDownSource(HAL_CounterHandle counterHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
uint8_t mode = counter->counter->readConfig_Mode(status);
|
||||
if (mode != HAL_Counter_kTwoPulse && mode != HAL_Counter_kExternalDirection) {
|
||||
// TODO: wpi_setWPIErrorWithContext(ParameterOutOfRange, "Counter only
|
||||
// supports DownSource in TwoPulse and ExternalDirection modes.");
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return;
|
||||
}
|
||||
|
||||
bool routingAnalogTrigger = false;
|
||||
uint8_t routingChannel = 0;
|
||||
uint8_t routingModule = 0;
|
||||
bool success =
|
||||
remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
|
||||
routingModule, routingAnalogTrigger);
|
||||
if (!success) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
counter->counter->writeConfig_DownSource_Module(routingModule, status);
|
||||
counter->counter->writeConfig_DownSource_Channel(routingChannel, status);
|
||||
counter->counter->writeConfig_DownSource_AnalogTrigger(routingAnalogTrigger,
|
||||
status);
|
||||
|
||||
HAL_SetCounterDownSourceEdge(counterHandle, true, false, status);
|
||||
counter->counter->strobeReset(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the edge sensitivity on a down counting source.
|
||||
* Set the down source to either detect rising edges or falling edges.
|
||||
*/
|
||||
void HAL_SetCounterDownSourceEdge(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool risingEdge, HAL_Bool fallingEdge,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeConfig_DownRisingEdge(risingEdge, status);
|
||||
counter->counter->writeConfig_DownFallingEdge(fallingEdge, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the down counting source to the counter.
|
||||
*/
|
||||
void HAL_ClearCounterDownSource(HAL_CounterHandle counterHandle,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeConfig_DownFallingEdge(false, status);
|
||||
counter->counter->writeConfig_DownRisingEdge(false, status);
|
||||
// Index 0 of digital is always 0.
|
||||
counter->counter->writeConfig_DownSource_Channel(0, status);
|
||||
counter->counter->writeConfig_DownSource_AnalogTrigger(false, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set standard up / down counting mode on this counter.
|
||||
* Up and down counts are sourced independently from two inputs.
|
||||
*/
|
||||
void HAL_SetCounterUpDownMode(HAL_CounterHandle counterHandle,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeConfig_Mode(HAL_Counter_kTwoPulse, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set external direction mode on this counter.
|
||||
* Counts are sourced on the Up counter input.
|
||||
* The Down counter input represents the direction to count.
|
||||
*/
|
||||
void HAL_SetCounterExternalDirectionMode(HAL_CounterHandle counterHandle,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeConfig_Mode(HAL_Counter_kExternalDirection, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Semi-period mode on this counter.
|
||||
* Counts up on both rising and falling edges.
|
||||
*/
|
||||
void HAL_SetCounterSemiPeriodMode(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool highSemiPeriod, int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeConfig_Mode(HAL_Counter_kSemiperiod, status);
|
||||
counter->counter->writeConfig_UpRisingEdge(highSemiPeriod, status);
|
||||
HAL_SetCounterUpdateWhenEmpty(counterHandle, false, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the counter to count in up or down based on the length of the input
|
||||
* pulse.
|
||||
* This mode is most useful for direction sensitive gear tooth sensors.
|
||||
* @param threshold The pulse length beyond which the counter counts the
|
||||
* opposite direction. Units are seconds.
|
||||
*/
|
||||
void HAL_SetCounterPulseLengthMode(HAL_CounterHandle counterHandle,
|
||||
double threshold, int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeConfig_Mode(HAL_Counter_kPulseLength, status);
|
||||
counter->counter->writeConfig_PulseLengthThreshold(
|
||||
static_cast<uint32_t>(threshold * 1.0e6) *
|
||||
kSystemClockTicksPerMicrosecond,
|
||||
status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Samples to Average which specifies the number of samples of the timer
|
||||
* to
|
||||
* average when calculating the period. Perform averaging to account for
|
||||
* mechanical imperfections or as oversampling to increase resolution.
|
||||
* @return SamplesToAverage The number of samples being averaged (from 1 to 127)
|
||||
*/
|
||||
int32_t HAL_GetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return counter->counter->readTimerConfig_AverageSize(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Samples to Average which specifies the number of samples of the timer
|
||||
* to average when calculating the period. Perform averaging to account for
|
||||
* mechanical imperfections or as oversampling to increase resolution.
|
||||
* @param samplesToAverage The number of samples to average from 1 to 127.
|
||||
*/
|
||||
void HAL_SetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
|
||||
int32_t samplesToAverage, int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (samplesToAverage < 1 || samplesToAverage > 127) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
counter->counter->writeTimerConfig_AverageSize(samplesToAverage, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the Counter to zero.
|
||||
* Set the counter value to zero. This doesn't effect the running state of the
|
||||
* counter, just sets the current value to zero.
|
||||
*/
|
||||
void HAL_ResetCounter(HAL_CounterHandle counterHandle, int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->strobeReset(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current counter value.
|
||||
* Read the value at this instant. It may still be running, so it reflects the
|
||||
* current value. Next time it is read, it might have a different value.
|
||||
*/
|
||||
int32_t HAL_GetCounter(HAL_CounterHandle counterHandle, int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
int32_t value = counter->counter->readOutput_Value(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the Period of the most recent count.
|
||||
* Returns the time interval of the most recent count. This can be used for
|
||||
* velocity calculations to determine shaft speed.
|
||||
* @returns The period of the last two pulses in units of seconds.
|
||||
*/
|
||||
double HAL_GetCounterPeriod(HAL_CounterHandle counterHandle, int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0.0;
|
||||
}
|
||||
tCounter::tTimerOutput output = counter->counter->readTimerOutput(status);
|
||||
double period;
|
||||
if (output.Stalled) {
|
||||
// Return infinity
|
||||
double zero = 0.0;
|
||||
period = 1.0 / zero;
|
||||
} else {
|
||||
// output.Period is a fixed point number that counts by 2 (24 bits, 25
|
||||
// integer bits)
|
||||
period = static_cast<double>(output.Period << 1) /
|
||||
static_cast<double>(output.Count);
|
||||
}
|
||||
return static_cast<double>(period *
|
||||
2.5e-8); // result * timebase (currently 25ns)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum period where the device is still considered "moving".
|
||||
* Sets the maximum period where the device is considered moving. This value is
|
||||
* used to determine the "stopped" state of the counter using the GetStopped
|
||||
* method.
|
||||
* @param maxPeriod The maximum period where the counted device is considered
|
||||
* moving in seconds.
|
||||
*/
|
||||
void HAL_SetCounterMaxPeriod(HAL_CounterHandle counterHandle, double maxPeriod,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeTimerConfig_StallPeriod(
|
||||
static_cast<uint32_t>(maxPeriod * 4.0e8), status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select whether you want to continue updating the event timer output when
|
||||
* there are no samples captured. The output of the event timer has a buffer of
|
||||
* periods that are averaged and posted to a register on the FPGA. When the
|
||||
* timer detects that the event source has stopped (based on the MaxPeriod) the
|
||||
* buffer of samples to be averaged is emptied. If you enable the update when
|
||||
* empty, you will be notified of the stopped source and the event time will
|
||||
* report 0 samples. If you disable update when empty, the most recent average
|
||||
* will remain on the output until a new sample is acquired. You will never see
|
||||
* 0 samples output (except when there have been no events since an FPGA reset)
|
||||
* and you will likely not see the stopped bit become true (since it is updated
|
||||
* at the end of an average and there are no samples to average).
|
||||
*/
|
||||
void HAL_SetCounterUpdateWhenEmpty(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool enabled, int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
counter->counter->writeTimerConfig_UpdateWhenEmpty(enabled, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the clock is stopped.
|
||||
* Determine if the clocked input is stopped based on the MaxPeriod value set
|
||||
* using the SetMaxPeriod method. If the clock exceeds the MaxPeriod, then the
|
||||
* device (and counter) are assumed to be stopped and it returns true.
|
||||
* @return Returns true if the most recent counter period exceeds the MaxPeriod
|
||||
* value set by SetMaxPeriod.
|
||||
*/
|
||||
HAL_Bool HAL_GetCounterStopped(HAL_CounterHandle counterHandle,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
return counter->counter->readTimerOutput_Stalled(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* The last direction the counter value changed.
|
||||
* @return The last direction the counter value changed.
|
||||
*/
|
||||
HAL_Bool HAL_GetCounterDirection(HAL_CounterHandle counterHandle,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value = counter->counter->readOutput_Direction(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Counter to return reversed sensing on the direction.
|
||||
* This allows counters to change the direction they are counting in the case of
|
||||
* 1X and 2X quadrature encoding only. Any other counter mode isn't supported.
|
||||
* @param reverseDirection true if the value counted should be negated.
|
||||
*/
|
||||
void HAL_SetCounterReverseDirection(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool reverseDirection,
|
||||
int32_t* status) {
|
||||
auto counter = counterHandles.Get(counterHandle);
|
||||
if (counter == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (counter->counter->readConfig_Mode(status) ==
|
||||
HAL_Counter_kExternalDirection) {
|
||||
if (reverseDirection)
|
||||
HAL_SetCounterDownSourceEdge(counterHandle, true, true, status);
|
||||
else
|
||||
HAL_SetCounterDownSourceEdge(counterHandle, false, true, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
532
hal/src/main/native/athena/DIO.cpp
Normal file
532
hal/src/main/native/athena/DIO.cpp
Normal file
@@ -0,0 +1,532 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/DIO.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "DigitalInternal.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "HAL/handles/LimitedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
// Create a mutex to protect changes to the digital output values
|
||||
static priority_recursive_mutex digitalDIOMutex;
|
||||
|
||||
static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
|
||||
kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>
|
||||
digitalPWMHandles;
|
||||
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* Create a new instance of a digital port.
|
||||
*/
|
||||
HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
|
||||
HAL_Bool input, int32_t* status) {
|
||||
initializeDigital(status);
|
||||
|
||||
if (*status != 0) return HAL_kInvalidHandle;
|
||||
|
||||
int16_t channel = getPortHandleChannel(portHandle);
|
||||
if (channel == InvalidHandleIndex || channel >= kNumDigitalChannels) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
auto handle =
|
||||
digitalChannelHandles.Allocate(channel, HAL_HandleEnum::DIO, status);
|
||||
|
||||
if (*status != 0)
|
||||
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
||||
|
||||
auto port = digitalChannelHandles.Get(handle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) { // would only occur on thread issue.
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
port->channel = static_cast<uint8_t>(channel);
|
||||
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
|
||||
tDIO::tOutputEnable outputEnable = digitalSystem->readOutputEnable(status);
|
||||
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
if (!getPortHandleSPIEnable(portHandle)) {
|
||||
// if this flag is not set, we actually want DIO.
|
||||
uint32_t bitToSet = 1u << remapSPIChannel(port->channel);
|
||||
|
||||
uint16_t specialFunctions = spiSystem->readEnableDIO(status);
|
||||
// Set the field to enable SPI DIO
|
||||
spiSystem->writeEnableDIO(specialFunctions | bitToSet, status);
|
||||
|
||||
if (input) {
|
||||
outputEnable.SPIPort =
|
||||
outputEnable.SPIPort & (~bitToSet); // clear the field for read
|
||||
} else {
|
||||
outputEnable.SPIPort =
|
||||
outputEnable.SPIPort | bitToSet; // set the bits for write
|
||||
}
|
||||
}
|
||||
} else if (port->channel < kNumDigitalHeaders) {
|
||||
uint32_t bitToSet = 1u << port->channel;
|
||||
if (input) {
|
||||
outputEnable.Headers =
|
||||
outputEnable.Headers & (~bitToSet); // clear the bit for read
|
||||
} else {
|
||||
outputEnable.Headers =
|
||||
outputEnable.Headers | bitToSet; // set the bit for write
|
||||
}
|
||||
} else {
|
||||
uint32_t bitToSet = 1u << remapMXPChannel(port->channel);
|
||||
|
||||
uint16_t specialFunctions =
|
||||
digitalSystem->readEnableMXPSpecialFunction(status);
|
||||
digitalSystem->writeEnableMXPSpecialFunction(specialFunctions & ~bitToSet,
|
||||
status);
|
||||
|
||||
if (input) {
|
||||
outputEnable.MXP =
|
||||
outputEnable.MXP & (~bitToSet); // clear the bit for read
|
||||
} else {
|
||||
outputEnable.MXP = outputEnable.MXP | bitToSet; // set the bit for write
|
||||
}
|
||||
}
|
||||
|
||||
digitalSystem->writeOutputEnable(outputEnable, status);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_CheckDIOChannel(int32_t channel) {
|
||||
return channel < kNumDigitalChannels && channel >= 0;
|
||||
}
|
||||
|
||||
void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
|
||||
auto port = digitalChannelHandles.Get(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
// no status, so no need to check for a proper free.
|
||||
digitalChannelHandles.Free(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) return;
|
||||
int32_t status = 0;
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
// Unset the SPI flag
|
||||
int32_t bitToUnset = 1 << remapSPIChannel(port->channel);
|
||||
uint16_t specialFunctions = spiSystem->readEnableDIO(&status);
|
||||
spiSystem->writeEnableDIO(specialFunctions & ~bitToUnset, &status);
|
||||
} else if (port->channel >= kNumDigitalHeaders) {
|
||||
// Unset the MXP flag
|
||||
uint32_t bitToUnset = 1u << remapMXPChannel(port->channel);
|
||||
|
||||
uint16_t specialFunctions =
|
||||
digitalSystem->readEnableMXPSpecialFunction(&status);
|
||||
digitalSystem->writeEnableMXPSpecialFunction(specialFunctions | bitToUnset,
|
||||
&status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a DO PWM Generator.
|
||||
* Allocate PWM generators so that they are not accidentally reused.
|
||||
*
|
||||
* @return PWM Generator handle
|
||||
*/
|
||||
HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
|
||||
auto handle = digitalPWMHandles.Allocate();
|
||||
if (handle == HAL_kInvalidHandle) {
|
||||
*status = NO_AVAILABLE_RESOURCES;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
auto id = digitalPWMHandles.Get(handle);
|
||||
if (id == nullptr) { // would only occur on thread issue.
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
*id = static_cast<uint8_t>(getHandleIndex(handle));
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the resource associated with a DO PWM generator.
|
||||
*
|
||||
* @param pwmGenerator The pwmGen to free that was allocated with
|
||||
* allocateDigitalPWM()
|
||||
*/
|
||||
void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status) {
|
||||
digitalPWMHandles.Free(pwmGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the frequency of the DO PWM generator.
|
||||
*
|
||||
* The valid range is from 0.6 Hz to 19 kHz. The frequency resolution is
|
||||
* logarithmic.
|
||||
*
|
||||
* @param rate The frequency to output all digital output PWM signals.
|
||||
*/
|
||||
void HAL_SetDigitalPWMRate(double rate, int32_t* status) {
|
||||
// Currently rounding in the log rate domain... heavy weight toward picking a
|
||||
// higher freq.
|
||||
// TODO: Round in the linear rate domain.
|
||||
initializeDigital(status);
|
||||
if (*status != 0) return;
|
||||
uint8_t pwmPeriodPower = static_cast<uint8_t>(
|
||||
std::log(1.0 / (pwmSystem->readLoopTiming(status) * 0.25E-6 * rate)) /
|
||||
std::log(2.0) +
|
||||
0.5);
|
||||
digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the duty-cycle of the PWM generator
|
||||
*
|
||||
* @param pwmGenerator The generator index reserved by allocateDigitalPWM()
|
||||
* @param dutyCycle The percent duty cycle to output [0..1].
|
||||
*/
|
||||
void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
|
||||
double dutyCycle, int32_t* status) {
|
||||
auto port = digitalPWMHandles.Get(pwmGenerator);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
int32_t id = *port;
|
||||
if (dutyCycle > 1.0) dutyCycle = 1.0;
|
||||
if (dutyCycle < 0.0) dutyCycle = 0.0;
|
||||
double rawDutyCycle = 256.0 * dutyCycle;
|
||||
if (rawDutyCycle > 255.5) rawDutyCycle = 255.5;
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalPwmMutex);
|
||||
uint16_t pwmPeriodPower = digitalSystem->readPWMPeriodPower(status);
|
||||
if (pwmPeriodPower < 4) {
|
||||
// The resolution of the duty cycle drops close to the highest
|
||||
// frequencies.
|
||||
rawDutyCycle = rawDutyCycle / std::pow(2.0, 4 - pwmPeriodPower);
|
||||
}
|
||||
if (id < 4)
|
||||
digitalSystem->writePWMDutyCycleA(id, static_cast<uint8_t>(rawDutyCycle),
|
||||
status);
|
||||
else
|
||||
digitalSystem->writePWMDutyCycleB(
|
||||
id - 4, static_cast<uint8_t>(rawDutyCycle), status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure which DO channel the PWM signal is output on
|
||||
*
|
||||
* @param pwmGenerator The generator index reserved by allocateDigitalPWM()
|
||||
* @param channel The Digital Output channel to output on
|
||||
*/
|
||||
void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
|
||||
int32_t channel, int32_t* status) {
|
||||
auto port = digitalPWMHandles.Get(pwmGenerator);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
int32_t id = *port;
|
||||
if (channel >= kNumDigitalHeaders &&
|
||||
channel <
|
||||
kNumDigitalHeaders + kNumDigitalMXPChannels) { // If it is on the MXP
|
||||
/* Then to write as a digital PWM channel an offset is needed to write on
|
||||
* the correct channel
|
||||
*/
|
||||
channel += kMXPDigitalPWMOffset;
|
||||
}
|
||||
digitalSystem->writePWMOutputSelect(id, channel, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a digital I/O bit to the FPGA.
|
||||
* Set a single value on a digital I/O channel.
|
||||
*
|
||||
* @param channel The Digital I/O channel
|
||||
* @param value The state to set the digital channel (if it is configured as an
|
||||
* output)
|
||||
*/
|
||||
void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (value != 0 && value != 1) {
|
||||
if (value != 0) value = 1;
|
||||
}
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
tDIO::tDO currentDIO = digitalSystem->readDO(status);
|
||||
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
if (value == 0) {
|
||||
currentDIO.SPIPort =
|
||||
currentDIO.SPIPort & ~(1u << remapSPIChannel(port->channel));
|
||||
} else if (value == 1) {
|
||||
currentDIO.SPIPort =
|
||||
currentDIO.SPIPort | (1u << remapSPIChannel(port->channel));
|
||||
}
|
||||
} else if (port->channel < kNumDigitalHeaders) {
|
||||
if (value == 0) {
|
||||
currentDIO.Headers = currentDIO.Headers & ~(1u << port->channel);
|
||||
} else if (value == 1) {
|
||||
currentDIO.Headers = currentDIO.Headers | (1u << port->channel);
|
||||
}
|
||||
} else {
|
||||
if (value == 0) {
|
||||
currentDIO.MXP =
|
||||
currentDIO.MXP & ~(1u << remapMXPChannel(port->channel));
|
||||
} else if (value == 1) {
|
||||
currentDIO.MXP =
|
||||
currentDIO.MXP | (1u << remapMXPChannel(port->channel));
|
||||
}
|
||||
}
|
||||
digitalSystem->writeDO(currentDIO, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a digital I/O bit from the FPGA.
|
||||
* Get a single value from a digital I/O channel.
|
||||
*
|
||||
* @param channel The digital I/O channel
|
||||
* @return The state of the specified channel
|
||||
*/
|
||||
HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
tDIO::tDI currentDIO = digitalSystem->readDI(status);
|
||||
// Shift 00000001 over channel-1 places.
|
||||
// AND it against the currentDIO
|
||||
// if it == 0, then return false
|
||||
// else return true
|
||||
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
return ((currentDIO.SPIPort >> remapSPIChannel(port->channel)) & 1) != 0;
|
||||
} else if (port->channel < kNumDigitalHeaders) {
|
||||
return ((currentDIO.Headers >> port->channel) & 1) != 0;
|
||||
} else {
|
||||
return ((currentDIO.MXP >> remapMXPChannel(port->channel)) & 1) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the direction of a the Digital I/O lines
|
||||
* A 1 bit means output and a 0 bit means input.
|
||||
*
|
||||
* @param channel The digital I/O channel
|
||||
* @return The direction of the specified channel
|
||||
*/
|
||||
HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
tDIO::tOutputEnable currentOutputEnable =
|
||||
digitalSystem->readOutputEnable(status);
|
||||
// Shift 00000001 over port->channel-1 places.
|
||||
// AND it against the currentOutputEnable
|
||||
// if it == 0, then return false
|
||||
// else return true
|
||||
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
return ((currentOutputEnable.SPIPort >> remapSPIChannel(port->channel)) &
|
||||
1) != 0;
|
||||
} else if (port->channel < kNumDigitalHeaders) {
|
||||
return ((currentOutputEnable.Headers >> port->channel) & 1) != 0;
|
||||
} else {
|
||||
return ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) & 1) !=
|
||||
0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a single pulse.
|
||||
* Write a pulse to the specified digital output channel. There can only be a
|
||||
* single pulse going at any time.
|
||||
*
|
||||
* @param channel The Digital Output channel that the pulse should be output on
|
||||
* @param pulseLength The active length of the pulse (in seconds)
|
||||
*/
|
||||
void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
tDIO::tPulse pulse;
|
||||
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
pulse.SPIPort = 1u << remapSPIChannel(port->channel);
|
||||
} else if (port->channel < kNumDigitalHeaders) {
|
||||
pulse.Headers = 1u << port->channel;
|
||||
} else {
|
||||
pulse.MXP = 1u << remapMXPChannel(port->channel);
|
||||
}
|
||||
|
||||
digitalSystem->writePulseLength(
|
||||
static_cast<uint8_t>(1.0e9 * pulseLength /
|
||||
(pwmSystem->readLoopTiming(status) * 25)),
|
||||
status);
|
||||
digitalSystem->writePulse(pulse, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a DIO line to see if it is currently generating a pulse.
|
||||
*
|
||||
* @return A pulse is in progress
|
||||
*/
|
||||
HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
|
||||
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
return (pulseRegister.SPIPort & (1 << remapSPIChannel(port->channel))) != 0;
|
||||
} else if (port->channel < kNumDigitalHeaders) {
|
||||
return (pulseRegister.Headers & (1 << port->channel)) != 0;
|
||||
} else {
|
||||
return (pulseRegister.MXP & (1 << remapMXPChannel(port->channel))) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any DIO line is currently generating a pulse.
|
||||
*
|
||||
* @return A pulse on some line is in progress
|
||||
*/
|
||||
HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
|
||||
initializeDigital(status);
|
||||
if (*status != 0) return false;
|
||||
tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
|
||||
return pulseRegister.Headers != 0 && pulseRegister.MXP != 0 &&
|
||||
pulseRegister.SPIPort != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the filter index from the FPGA.
|
||||
* Set the filter index used to filter out short pulses.
|
||||
*
|
||||
* @param dioPortHandle Handle to the digital I/O channel
|
||||
* @param filterIndex The filter index. Must be in the range 0 - 3, where 0
|
||||
* means "none" and 1 - 3 means filter # filterIndex - 1.
|
||||
*/
|
||||
void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
// Channels 10-15 are SPI channels, so subtract our MXP channels
|
||||
digitalSystem->writeFilterSelectHdr(port->channel - kNumDigitalMXPChannels,
|
||||
filterIndex, status);
|
||||
} else if (port->channel < kNumDigitalHeaders) {
|
||||
digitalSystem->writeFilterSelectHdr(port->channel, filterIndex, status);
|
||||
} else {
|
||||
digitalSystem->writeFilterSelectMXP(remapMXPChannel(port->channel),
|
||||
filterIndex, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the filter index from the FPGA.
|
||||
* Get the filter index used to filter out short pulses.
|
||||
*
|
||||
* @param dioPortHandle Handle to the digital I/O channel
|
||||
* @return filterIndex The filter index. Must be in the range 0 - 3,
|
||||
* where 0 means "none" and 1 - 3 means filter # filterIndex - 1.
|
||||
*/
|
||||
int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(dioPortHandle, HAL_HandleEnum::DIO);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
// Channels 10-15 are SPI channels, so subtract our MXP channels
|
||||
return digitalSystem->readFilterSelectHdr(
|
||||
port->channel - kNumDigitalMXPChannels, status);
|
||||
} else if (port->channel < kNumDigitalHeaders) {
|
||||
return digitalSystem->readFilterSelectHdr(port->channel, status);
|
||||
} else {
|
||||
return digitalSystem->readFilterSelectMXP(remapMXPChannel(port->channel),
|
||||
status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter period for the specified filter index.
|
||||
*
|
||||
* Set the filter period in FPGA cycles. Even though there are 2 different
|
||||
* filter index domains (MXP vs HDR), ignore that distinction for now since it
|
||||
* compilicates the interface. That can be changed later.
|
||||
*
|
||||
* @param filterIndex The filter index, 0 - 2.
|
||||
* @param value The number of cycles that the signal must not transition to be
|
||||
* counted as a transition.
|
||||
*/
|
||||
void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
|
||||
initializeDigital(status);
|
||||
if (*status != 0) return;
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
digitalSystem->writeFilterPeriodHdr(filterIndex, value, status);
|
||||
if (*status == 0) {
|
||||
digitalSystem->writeFilterPeriodMXP(filterIndex, value, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter period for the specified filter index.
|
||||
*
|
||||
* Get the filter period in FPGA cycles. Even though there are 2 different
|
||||
* filter index domains (MXP vs HDR), ignore that distinction for now since it
|
||||
* compilicates the interface. Set status to NiFpga_Status_SoftwareFault if the
|
||||
* filter values miss-match.
|
||||
*
|
||||
* @param filterIndex The filter index, 0 - 2.
|
||||
* @param value The number of cycles that the signal must not transition to be
|
||||
* counted as a transition.
|
||||
*/
|
||||
int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
|
||||
initializeDigital(status);
|
||||
if (*status != 0) return 0;
|
||||
uint32_t hdrPeriod = 0;
|
||||
uint32_t mxpPeriod = 0;
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
hdrPeriod = digitalSystem->readFilterPeriodHdr(filterIndex, status);
|
||||
if (*status == 0) {
|
||||
mxpPeriod = digitalSystem->readFilterPeriodMXP(filterIndex, status);
|
||||
}
|
||||
}
|
||||
if (hdrPeriod != mxpPeriod) {
|
||||
*status = NiFpga_Status_SoftwareFault;
|
||||
return -1;
|
||||
}
|
||||
return hdrPeriod;
|
||||
}
|
||||
}
|
||||
160
hal/src/main/native/athena/DigitalInternal.cpp
Normal file
160
hal/src/main/native/athena/DigitalInternal.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "DigitalInternal.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "ConstantsInternal.h"
|
||||
#include "FRC_NetworkCommunication/LoadOut.h"
|
||||
#include "HAL/AnalogTrigger.h"
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/HAL.h"
|
||||
#include "HAL/Ports.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
namespace hal {
|
||||
// Create a mutex to protect changes to the DO PWM config
|
||||
priority_recursive_mutex digitalPwmMutex;
|
||||
|
||||
std::unique_ptr<tDIO> digitalSystem;
|
||||
std::unique_ptr<tRelay> relaySystem;
|
||||
std::unique_ptr<tPWM> pwmSystem;
|
||||
std::unique_ptr<tSPI> spiSystem;
|
||||
|
||||
static std::atomic<bool> digitalSystemsInitialized{false};
|
||||
static hal::priority_mutex initializeMutex;
|
||||
|
||||
DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
|
||||
kNumDigitalChannels + kNumPWMHeaders>
|
||||
digitalChannelHandles;
|
||||
|
||||
/**
|
||||
* Initialize the digital system.
|
||||
*/
|
||||
void initializeDigital(int32_t* status) {
|
||||
// Initial check, as if it's true initialization has finished
|
||||
if (digitalSystemsInitialized) return;
|
||||
|
||||
std::lock_guard<hal::priority_mutex> lock(initializeMutex);
|
||||
// Second check in case another thread was waiting
|
||||
if (digitalSystemsInitialized) return;
|
||||
|
||||
digitalSystem.reset(tDIO::create(status));
|
||||
|
||||
// Relay Setup
|
||||
relaySystem.reset(tRelay::create(status));
|
||||
|
||||
// Turn off all relay outputs.
|
||||
relaySystem->writeValue_Forward(0, status);
|
||||
relaySystem->writeValue_Reverse(0, status);
|
||||
|
||||
// PWM Setup
|
||||
pwmSystem.reset(tPWM::create(status));
|
||||
|
||||
// Make sure that the 9403 IONode has had a chance to initialize before
|
||||
// continuing.
|
||||
while (pwmSystem->readLoopTiming(status) == 0) std::this_thread::yield();
|
||||
|
||||
if (pwmSystem->readLoopTiming(status) != kExpectedLoopTiming) {
|
||||
*status = LOOP_TIMING_ERROR; // NOTE: Doesn't display the error
|
||||
}
|
||||
|
||||
// Calculate the length, in ms, of one DIO loop
|
||||
double loopTime = pwmSystem->readLoopTiming(status) /
|
||||
(kSystemClockTicksPerMicrosecond * 1e3);
|
||||
|
||||
pwmSystem->writeConfig_Period(
|
||||
static_cast<uint16_t>(kDefaultPwmPeriod / loopTime + .5), status);
|
||||
uint16_t minHigh = static_cast<uint16_t>(
|
||||
(kDefaultPwmCenter - kDefaultPwmStepsDown * loopTime) / loopTime + .5);
|
||||
pwmSystem->writeConfig_MinHigh(minHigh, status);
|
||||
// Ensure that PWM output values are set to OFF
|
||||
for (uint8_t pwmIndex = 0; pwmIndex < kNumPWMChannels; pwmIndex++) {
|
||||
// Copy of SetPWM
|
||||
if (pwmIndex < tPWM::kNumHdrRegisters) {
|
||||
pwmSystem->writeHdr(pwmIndex, kPwmDisabled, status);
|
||||
} else {
|
||||
pwmSystem->writeMXP(pwmIndex - tPWM::kNumHdrRegisters, kPwmDisabled,
|
||||
status);
|
||||
}
|
||||
|
||||
// Copy of SetPWMPeriodScale, set to 4x by default.
|
||||
if (pwmIndex < tPWM::kNumPeriodScaleHdrElements) {
|
||||
pwmSystem->writePeriodScaleHdr(pwmIndex, 3, status);
|
||||
} else {
|
||||
pwmSystem->writePeriodScaleMXP(
|
||||
pwmIndex - tPWM::kNumPeriodScaleHdrElements, 3, status);
|
||||
}
|
||||
}
|
||||
|
||||
// SPI setup
|
||||
spiSystem.reset(tSPI::create(status));
|
||||
|
||||
digitalSystemsInitialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map SPI channel numbers from their physical number (27 to 31) to their
|
||||
* position in the bit field.
|
||||
*/
|
||||
int32_t remapSPIChannel(int32_t channel) { return channel - 26; }
|
||||
|
||||
/**
|
||||
* Map DIO channel numbers from their physical number (10 to 26) to their
|
||||
* position in the bit field.
|
||||
*/
|
||||
int32_t remapMXPChannel(int32_t channel) { return channel - 10; }
|
||||
|
||||
int32_t remapMXPPWMChannel(int32_t channel) {
|
||||
if (channel < 14) {
|
||||
return channel - 10; // first block of 4 pwms (MXP 0-3)
|
||||
} else {
|
||||
return channel - 6; // block of PWMs after SPI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remap the digital source channel and set the module.
|
||||
* If it's an analog trigger, determine the module from the high order routing
|
||||
* channel else do normal digital input remapping based on channel number
|
||||
* (MXP)
|
||||
*/
|
||||
bool remapDigitalSource(HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
uint8_t& channel, uint8_t& module,
|
||||
bool& analogTrigger) {
|
||||
if (isHandleType(digitalSourceHandle, HAL_HandleEnum::AnalogTrigger)) {
|
||||
// If handle passed, index is not negative
|
||||
int32_t index = getHandleIndex(digitalSourceHandle);
|
||||
channel = (index << 2) + analogTriggerType;
|
||||
module = channel >> 4;
|
||||
analogTrigger = true;
|
||||
return true;
|
||||
} else if (isHandleType(digitalSourceHandle, HAL_HandleEnum::DIO)) {
|
||||
int32_t index = getHandleIndex(digitalSourceHandle);
|
||||
if (index > kNumDigitalHeaders + kNumDigitalMXPChannels) {
|
||||
// channels 10-15, so need to add headers to remap index
|
||||
channel = remapSPIChannel(index) + kNumDigitalHeaders;
|
||||
module = 0;
|
||||
} else if (index >= kNumDigitalHeaders) {
|
||||
channel = remapMXPChannel(index);
|
||||
module = 1;
|
||||
} else {
|
||||
channel = index;
|
||||
module = 0;
|
||||
}
|
||||
analogTrigger = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace hal
|
||||
89
hal/src/main/native/athena/DigitalInternal.h
Normal file
89
hal/src/main/native/athena/DigitalInternal.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/AnalogTrigger.h"
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/Ports.h"
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/handles/DigitalHandleResource.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
namespace hal {
|
||||
/**
|
||||
* MXP channels when used as digital output PWM are offset from actual value
|
||||
*/
|
||||
constexpr int32_t kMXPDigitalPWMOffset = 6;
|
||||
|
||||
constexpr int32_t kExpectedLoopTiming = 40;
|
||||
|
||||
/**
|
||||
* kDefaultPwmPeriod is in ms
|
||||
*
|
||||
* - 20ms periods (50 Hz) are the "safest" setting in that this works for all
|
||||
* devices
|
||||
* - 20ms periods seem to be desirable for Vex Motors
|
||||
* - 20ms periods are the specified period for HS-322HD servos, but work
|
||||
* reliably down to 10.0 ms; starting at about 8.5ms, the servo sometimes hums
|
||||
* and get hot; by 5.0ms the hum is nearly continuous
|
||||
* - 10ms periods work well for Victor 884
|
||||
* - 5ms periods allows higher update rates for Luminary Micro Jaguar speed
|
||||
* controllers. Due to the shipping firmware on the Jaguar, we can't run the
|
||||
* update period less than 5.05 ms.
|
||||
*
|
||||
* kDefaultPwmPeriod is the 1x period (5.05 ms). In hardware, the period
|
||||
* scaling is implemented as an output squelch to get longer periods for old
|
||||
* devices.
|
||||
*/
|
||||
constexpr double kDefaultPwmPeriod = 5.05;
|
||||
/**
|
||||
* kDefaultPwmCenter is the PWM range center in ms
|
||||
*/
|
||||
constexpr double kDefaultPwmCenter = 1.5;
|
||||
/**
|
||||
* kDefaultPWMStepsDown is the number of PWM steps below the centerpoint
|
||||
*/
|
||||
constexpr int32_t kDefaultPwmStepsDown = 1000;
|
||||
constexpr int32_t kPwmDisabled = 0;
|
||||
|
||||
// Create a mutex to protect changes to the DO PWM config
|
||||
extern priority_recursive_mutex digitalPwmMutex;
|
||||
|
||||
extern std::unique_ptr<tDIO> digitalSystem;
|
||||
extern std::unique_ptr<tRelay> relaySystem;
|
||||
extern std::unique_ptr<tPWM> pwmSystem;
|
||||
extern std::unique_ptr<tSPI> spiSystem;
|
||||
|
||||
struct DigitalPort {
|
||||
uint8_t channel;
|
||||
bool configSet = false;
|
||||
bool eliminateDeadband = false;
|
||||
int32_t maxPwm = 0;
|
||||
int32_t deadbandMaxPwm = 0;
|
||||
int32_t centerPwm = 0;
|
||||
int32_t deadbandMinPwm = 0;
|
||||
int32_t minPwm = 0;
|
||||
};
|
||||
|
||||
extern DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
|
||||
kNumDigitalChannels + kNumPWMHeaders>
|
||||
digitalChannelHandles;
|
||||
|
||||
void initializeDigital(int32_t* status);
|
||||
bool remapDigitalSource(HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
uint8_t& channel, uint8_t& module, bool& analogTrigger);
|
||||
int32_t remapSPIChannel(int32_t channel);
|
||||
int32_t remapMXPPWMChannel(int32_t channel);
|
||||
int32_t remapMXPChannel(int32_t channel);
|
||||
} // namespace hal
|
||||
448
hal/src/main/native/athena/Encoder.cpp
Normal file
448
hal/src/main/native/athena/Encoder.cpp
Normal file
@@ -0,0 +1,448 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Encoder.h"
|
||||
|
||||
#include "EncoderInternal.h"
|
||||
#include "FPGAEncoder.h"
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/Counter.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/handles/LimitedClassedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
Encoder::Encoder(HAL_Handle digitalSourceHandleA,
|
||||
HAL_AnalogTriggerType analogTriggerTypeA,
|
||||
HAL_Handle digitalSourceHandleB,
|
||||
HAL_AnalogTriggerType analogTriggerTypeB,
|
||||
bool reverseDirection, HAL_EncoderEncodingType encodingType,
|
||||
int32_t* status) {
|
||||
m_encodingType = encodingType;
|
||||
switch (encodingType) {
|
||||
case HAL_Encoder_k4X: {
|
||||
m_encodingScale = 4;
|
||||
m_encoder = HAL_InitializeFPGAEncoder(
|
||||
digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
|
||||
analogTriggerTypeB, reverseDirection, &m_index, status);
|
||||
if (*status != 0) {
|
||||
return;
|
||||
}
|
||||
m_counter = HAL_kInvalidHandle;
|
||||
SetMaxPeriod(.5, status);
|
||||
break;
|
||||
}
|
||||
case HAL_Encoder_k1X:
|
||||
case HAL_Encoder_k2X: {
|
||||
SetupCounter(digitalSourceHandleA, analogTriggerTypeA,
|
||||
digitalSourceHandleB, analogTriggerTypeB, reverseDirection,
|
||||
encodingType, status);
|
||||
|
||||
m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::SetupCounter(HAL_Handle digitalSourceHandleA,
|
||||
HAL_AnalogTriggerType analogTriggerTypeA,
|
||||
HAL_Handle digitalSourceHandleB,
|
||||
HAL_AnalogTriggerType analogTriggerTypeB,
|
||||
bool reverseDirection,
|
||||
HAL_EncoderEncodingType encodingType,
|
||||
int32_t* status) {
|
||||
m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2;
|
||||
m_counter =
|
||||
HAL_InitializeCounter(HAL_Counter_kExternalDirection, &m_index, status);
|
||||
if (*status != 0) return;
|
||||
HAL_SetCounterMaxPeriod(m_counter, 0.5, status);
|
||||
if (*status != 0) return;
|
||||
HAL_SetCounterUpSource(m_counter, digitalSourceHandleA, analogTriggerTypeA,
|
||||
status);
|
||||
if (*status != 0) return;
|
||||
HAL_SetCounterDownSource(m_counter, digitalSourceHandleB, analogTriggerTypeB,
|
||||
status);
|
||||
if (*status != 0) return;
|
||||
if (encodingType == HAL_Encoder_k1X) {
|
||||
HAL_SetCounterUpSourceEdge(m_counter, true, false, status);
|
||||
HAL_SetCounterAverageSize(m_counter, 1, status);
|
||||
} else {
|
||||
HAL_SetCounterUpSourceEdge(m_counter, true, true, status);
|
||||
HAL_SetCounterAverageSize(m_counter, 2, status);
|
||||
}
|
||||
HAL_SetCounterDownSourceEdge(m_counter, reverseDirection, true, status);
|
||||
}
|
||||
|
||||
Encoder::~Encoder() {
|
||||
if (m_counter != HAL_kInvalidHandle) {
|
||||
int32_t status = 0;
|
||||
HAL_FreeCounter(m_counter, &status);
|
||||
} else {
|
||||
int32_t status = 0;
|
||||
HAL_FreeFPGAEncoder(m_encoder, &status);
|
||||
}
|
||||
}
|
||||
|
||||
// CounterBase interface
|
||||
int32_t Encoder::Get(int32_t* status) const {
|
||||
return static_cast<int32_t>(GetRaw(status) * DecodingScaleFactor());
|
||||
}
|
||||
|
||||
int32_t Encoder::GetRaw(int32_t* status) const {
|
||||
if (m_counter) {
|
||||
return HAL_GetCounter(m_counter, status);
|
||||
} else {
|
||||
return HAL_GetFPGAEncoder(m_encoder, status);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Encoder::GetEncodingScale(int32_t* status) const {
|
||||
return m_encodingScale;
|
||||
}
|
||||
|
||||
void Encoder::Reset(int32_t* status) {
|
||||
if (m_counter) {
|
||||
HAL_ResetCounter(m_counter, status);
|
||||
} else {
|
||||
HAL_ResetFPGAEncoder(m_encoder, status);
|
||||
}
|
||||
}
|
||||
|
||||
double Encoder::GetPeriod(int32_t* status) const {
|
||||
if (m_counter) {
|
||||
return HAL_GetCounterPeriod(m_counter, status) / DecodingScaleFactor();
|
||||
} else {
|
||||
return HAL_GetFPGAEncoderPeriod(m_encoder, status);
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::SetMaxPeriod(double maxPeriod, int32_t* status) {
|
||||
if (m_counter) {
|
||||
HAL_SetCounterMaxPeriod(m_counter, maxPeriod, status);
|
||||
} else {
|
||||
HAL_SetFPGAEncoderMaxPeriod(m_encoder, maxPeriod, status);
|
||||
}
|
||||
}
|
||||
|
||||
bool Encoder::GetStopped(int32_t* status) const {
|
||||
if (m_counter) {
|
||||
return HAL_GetCounterStopped(m_counter, status);
|
||||
} else {
|
||||
return HAL_GetFPGAEncoderStopped(m_encoder, status);
|
||||
}
|
||||
}
|
||||
|
||||
bool Encoder::GetDirection(int32_t* status) const {
|
||||
if (m_counter) {
|
||||
return HAL_GetCounterDirection(m_counter, status);
|
||||
} else {
|
||||
return HAL_GetFPGAEncoderDirection(m_encoder, status);
|
||||
}
|
||||
}
|
||||
|
||||
double Encoder::GetDistance(int32_t* status) const {
|
||||
return GetRaw(status) * DecodingScaleFactor() * m_distancePerPulse;
|
||||
}
|
||||
|
||||
double Encoder::GetRate(int32_t* status) const {
|
||||
return m_distancePerPulse / GetPeriod(status);
|
||||
}
|
||||
|
||||
void Encoder::SetMinRate(double minRate, int32_t* status) {
|
||||
SetMaxPeriod(m_distancePerPulse / minRate, status);
|
||||
}
|
||||
|
||||
void Encoder::SetDistancePerPulse(double distancePerPulse, int32_t* status) {
|
||||
m_distancePerPulse = distancePerPulse;
|
||||
}
|
||||
|
||||
void Encoder::SetReverseDirection(bool reverseDirection, int32_t* status) {
|
||||
if (m_counter) {
|
||||
HAL_SetCounterReverseDirection(m_counter, reverseDirection, status);
|
||||
} else {
|
||||
HAL_SetFPGAEncoderReverseDirection(m_encoder, reverseDirection, status);
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::SetSamplesToAverage(int32_t samplesToAverage, int32_t* status) {
|
||||
if (samplesToAverage < 1 || samplesToAverage > 127) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return;
|
||||
}
|
||||
if (m_counter) {
|
||||
HAL_SetCounterSamplesToAverage(m_counter, samplesToAverage, status);
|
||||
} else {
|
||||
HAL_SetFPGAEncoderSamplesToAverage(m_encoder, samplesToAverage, status);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Encoder::GetSamplesToAverage(int32_t* status) const {
|
||||
if (m_counter) {
|
||||
return HAL_GetCounterSamplesToAverage(m_counter, status);
|
||||
} else {
|
||||
return HAL_GetFPGAEncoderSamplesToAverage(m_encoder, status);
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::SetIndexSource(HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
HAL_EncoderIndexingType type, int32_t* status) {
|
||||
if (m_counter) {
|
||||
*status = HAL_COUNTER_NOT_SUPPORTED;
|
||||
return;
|
||||
}
|
||||
bool activeHigh =
|
||||
(type == HAL_kResetWhileHigh) || (type == HAL_kResetOnRisingEdge);
|
||||
bool edgeSensitive =
|
||||
(type == HAL_kResetOnFallingEdge) || (type == HAL_kResetOnRisingEdge);
|
||||
HAL_SetFPGAEncoderIndexSource(m_encoder, digitalSourceHandle,
|
||||
analogTriggerType, activeHigh, edgeSensitive,
|
||||
status);
|
||||
}
|
||||
|
||||
double Encoder::DecodingScaleFactor() const {
|
||||
switch (m_encodingType) {
|
||||
case HAL_Encoder_k1X:
|
||||
return 1.0;
|
||||
case HAL_Encoder_k2X:
|
||||
return 0.5;
|
||||
case HAL_Encoder_k4X:
|
||||
return 0.25;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
static LimitedClassedHandleResource<HAL_EncoderHandle, Encoder,
|
||||
kNumEncoders + kNumCounters,
|
||||
HAL_HandleEnum::Encoder>
|
||||
encoderHandles;
|
||||
|
||||
extern "C" {
|
||||
HAL_EncoderHandle HAL_InitializeEncoder(
|
||||
HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
|
||||
HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
|
||||
HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
|
||||
int32_t* status) {
|
||||
auto encoder = std::make_shared<Encoder>(
|
||||
digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
|
||||
analogTriggerTypeB, reverseDirection, encodingType, status);
|
||||
if (*status != 0) return HAL_kInvalidHandle; // return in creation error
|
||||
auto handle = encoderHandles.Allocate(encoder);
|
||||
if (handle == HAL_kInvalidHandle) {
|
||||
*status = NO_AVAILABLE_RESOURCES;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
||||
encoderHandles.Free(encoderHandle);
|
||||
}
|
||||
|
||||
int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->Get(status);
|
||||
}
|
||||
|
||||
int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetRaw(status);
|
||||
}
|
||||
|
||||
int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetEncodingScale(status);
|
||||
}
|
||||
|
||||
void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->Reset(status);
|
||||
}
|
||||
|
||||
double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetPeriod(status);
|
||||
}
|
||||
|
||||
void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->SetMaxPeriod(maxPeriod, status);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetStopped(status);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetDirection(status);
|
||||
}
|
||||
|
||||
double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetDistance(status);
|
||||
}
|
||||
|
||||
double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetRate(status);
|
||||
}
|
||||
|
||||
void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->SetMinRate(minRate, status);
|
||||
}
|
||||
|
||||
void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
|
||||
double distancePerPulse, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->SetDistancePerPulse(distancePerPulse, status);
|
||||
}
|
||||
|
||||
void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
|
||||
HAL_Bool reverseDirection,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->SetReverseDirection(reverseDirection, status);
|
||||
}
|
||||
|
||||
void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
|
||||
int32_t samplesToAverage, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->SetSamplesToAverage(samplesToAverage, status);
|
||||
}
|
||||
|
||||
int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetSamplesToAverage(status);
|
||||
}
|
||||
|
||||
double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->DecodingScaleFactor();
|
||||
}
|
||||
|
||||
double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetDistancePerPulse();
|
||||
}
|
||||
|
||||
HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
|
||||
HAL_EncoderHandle encoderHandle, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_Encoder_k4X; // default to k4X
|
||||
}
|
||||
return encoder->GetEncodingType();
|
||||
}
|
||||
|
||||
void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
HAL_EncoderIndexingType type, int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->SetIndexSource(digitalSourceHandle, analogTriggerType, type, status);
|
||||
}
|
||||
|
||||
int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = encoderHandles.Get(encoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->GetFPGAIndex();
|
||||
}
|
||||
}
|
||||
76
hal/src/main/native/athena/EncoderInternal.h
Normal file
76
hal/src/main/native/athena/EncoderInternal.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Encoder.h"
|
||||
|
||||
namespace hal {
|
||||
class Encoder {
|
||||
public:
|
||||
Encoder(HAL_Handle digitalSourceHandleA,
|
||||
HAL_AnalogTriggerType analogTriggerTypeA,
|
||||
HAL_Handle digitalSourceHandleB,
|
||||
HAL_AnalogTriggerType analogTriggerTypeB, bool reverseDirection,
|
||||
HAL_EncoderEncodingType encodingType, int32_t* status);
|
||||
~Encoder();
|
||||
|
||||
// CounterBase interface
|
||||
int32_t Get(int32_t* status) const;
|
||||
int32_t GetRaw(int32_t* status) const;
|
||||
int32_t GetEncodingScale(int32_t* status) const;
|
||||
void Reset(int32_t* status);
|
||||
double GetPeriod(int32_t* status) const;
|
||||
void SetMaxPeriod(double maxPeriod, int32_t* status);
|
||||
bool GetStopped(int32_t* status) const;
|
||||
bool GetDirection(int32_t* status) const;
|
||||
|
||||
double GetDistance(int32_t* status) const;
|
||||
double GetRate(int32_t* status) const;
|
||||
void SetMinRate(double minRate, int32_t* status);
|
||||
void SetDistancePerPulse(double distancePerPulse, int32_t* status);
|
||||
void SetReverseDirection(bool reverseDirection, int32_t* status);
|
||||
void SetSamplesToAverage(int32_t samplesToAverage, int32_t* status);
|
||||
int32_t GetSamplesToAverage(int32_t* status) const;
|
||||
|
||||
void SetIndexSource(HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
HAL_EncoderIndexingType type, int32_t* status);
|
||||
|
||||
int32_t GetFPGAIndex() const { return m_index; }
|
||||
|
||||
int32_t GetEncodingScale() const { return m_encodingScale; }
|
||||
|
||||
double DecodingScaleFactor() const;
|
||||
|
||||
double GetDistancePerPulse() const { return m_distancePerPulse; }
|
||||
|
||||
HAL_EncoderEncodingType GetEncodingType() const { return m_encodingType; }
|
||||
|
||||
private:
|
||||
void SetupCounter(HAL_Handle digitalSourceHandleA,
|
||||
HAL_AnalogTriggerType analogTriggerTypeA,
|
||||
HAL_Handle digitalSourceHandleB,
|
||||
HAL_AnalogTriggerType analogTriggerTypeB,
|
||||
bool reverseDirection, HAL_EncoderEncodingType encodingType,
|
||||
int32_t* status);
|
||||
|
||||
HAL_FPGAEncoderHandle m_encoder = HAL_kInvalidHandle;
|
||||
|
||||
HAL_CounterHandle m_counter = HAL_kInvalidHandle;
|
||||
|
||||
int32_t m_index = 0;
|
||||
|
||||
double m_distancePerPulse = 1.0;
|
||||
|
||||
HAL_EncoderEncodingType m_encodingType;
|
||||
|
||||
int32_t m_encodingScale;
|
||||
};
|
||||
} // namespace hal
|
||||
296
hal/src/main/native/athena/FPGAEncoder.cpp
Normal file
296
hal/src/main/native/athena/FPGAEncoder.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "FPGAEncoder.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "DigitalInternal.h"
|
||||
#include "HAL/handles/LimitedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace {
|
||||
struct Encoder {
|
||||
std::unique_ptr<tEncoder> encoder;
|
||||
uint8_t index;
|
||||
};
|
||||
}
|
||||
|
||||
static const double DECODING_SCALING_FACTOR = 0.25;
|
||||
|
||||
static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
|
||||
HAL_HandleEnum::FPGAEncoder>
|
||||
fpgaEncoderHandles;
|
||||
|
||||
extern "C" {
|
||||
HAL_FPGAEncoderHandle HAL_InitializeFPGAEncoder(
|
||||
HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
|
||||
HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
|
||||
HAL_Bool reverseDirection, int32_t* index, int32_t* status) {
|
||||
bool routingAnalogTriggerA = false;
|
||||
uint8_t routingChannelA = 0;
|
||||
uint8_t routingModuleA = 0;
|
||||
bool successA = remapDigitalSource(digitalSourceHandleA, analogTriggerTypeA,
|
||||
routingChannelA, routingModuleA,
|
||||
routingAnalogTriggerA);
|
||||
bool routingAnalogTriggerB = false;
|
||||
uint8_t routingChannelB = 0;
|
||||
uint8_t routingModuleB = 0;
|
||||
bool successB = remapDigitalSource(digitalSourceHandleB, analogTriggerTypeB,
|
||||
routingChannelB, routingModuleB,
|
||||
routingAnalogTriggerB);
|
||||
|
||||
if (!successA || !successB) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
auto handle = fpgaEncoderHandles.Allocate();
|
||||
if (handle == HAL_kInvalidHandle) { // out of resources
|
||||
*status = NO_AVAILABLE_RESOURCES;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
auto encoder = fpgaEncoderHandles.Get(handle);
|
||||
if (encoder == nullptr) { // will only error on thread issue
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
encoder->index = static_cast<uint8_t>(getHandleIndex(handle));
|
||||
*index = encoder->index;
|
||||
// TODO: if (index == ~0ul) { CloneError(quadEncoders); return; }
|
||||
encoder->encoder.reset(tEncoder::create(encoder->index, status));
|
||||
encoder->encoder->writeConfig_ASource_Module(routingModuleA, status);
|
||||
encoder->encoder->writeConfig_ASource_Channel(routingChannelA, status);
|
||||
encoder->encoder->writeConfig_ASource_AnalogTrigger(routingAnalogTriggerA,
|
||||
status);
|
||||
encoder->encoder->writeConfig_BSource_Module(routingModuleB, status);
|
||||
encoder->encoder->writeConfig_BSource_Channel(routingChannelB, status);
|
||||
encoder->encoder->writeConfig_BSource_AnalogTrigger(routingAnalogTriggerB,
|
||||
status);
|
||||
encoder->encoder->strobeReset(status);
|
||||
encoder->encoder->writeConfig_Reverse(reverseDirection, status);
|
||||
encoder->encoder->writeTimerConfig_AverageSize(4, status);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_FreeFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status) {
|
||||
fpgaEncoderHandles.Free(fpgaEncoderHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the Encoder distance to zero.
|
||||
* Resets the current count to zero on the encoder.
|
||||
*/
|
||||
void HAL_ResetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->encoder->strobeReset(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fpga value from the encoder.
|
||||
* The fpga value is the actual count unscaled by the 1x, 2x, or 4x scale
|
||||
* factor.
|
||||
* @return Current fpga count from the encoder
|
||||
*/
|
||||
int32_t HAL_GetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->encoder->readOutput_Value(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the period of the most recent pulse.
|
||||
* Returns the period of the most recent Encoder pulse in seconds.
|
||||
* This method compenstates for the decoding type.
|
||||
*
|
||||
* @deprecated Use GetRate() in favor of this method. This returns unscaled
|
||||
* periods and GetRate() scales using value from SetDistancePerPulse().
|
||||
*
|
||||
* @return Period in seconds of the most recent pulse.
|
||||
*/
|
||||
double HAL_GetFPGAEncoderPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0.0;
|
||||
}
|
||||
tEncoder::tTimerOutput output = encoder->encoder->readTimerOutput(status);
|
||||
double value;
|
||||
if (output.Stalled) {
|
||||
// Return infinity
|
||||
double zero = 0.0;
|
||||
value = 1.0 / zero;
|
||||
} else {
|
||||
// output.Period is a fixed point number that counts by 2 (24 bits, 25
|
||||
// integer bits)
|
||||
value = static_cast<double>(output.Period << 1) /
|
||||
static_cast<double>(output.Count);
|
||||
}
|
||||
double measuredPeriod = value * 2.5e-8;
|
||||
return measuredPeriod / DECODING_SCALING_FACTOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum period for stopped detection.
|
||||
* Sets the value that represents the maximum period of the Encoder before it
|
||||
* will assume that the attached device is stopped. This timeout allows users
|
||||
* to determine if the wheels or other shaft has stopped rotating.
|
||||
* This method compensates for the decoding type.
|
||||
*
|
||||
* @deprecated Use SetMinRate() in favor of this method. This takes unscaled
|
||||
* periods and SetMinRate() scales using value from SetDistancePerPulse().
|
||||
*
|
||||
* @param maxPeriod The maximum time between rising and falling edges before the
|
||||
* FPGA will
|
||||
* report the device stopped. This is expressed in seconds.
|
||||
*/
|
||||
void HAL_SetFPGAEncoderMaxPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
double maxPeriod, int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->encoder->writeTimerConfig_StallPeriod(
|
||||
static_cast<uint32_t>(maxPeriod * 4.0e8 * DECODING_SCALING_FACTOR),
|
||||
status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the encoder is stopped.
|
||||
* Using the MaxPeriod value, a boolean is returned that is true if the encoder
|
||||
* is considered stopped and false if it is still moving. A stopped encoder is
|
||||
* one where the most recent pulse width exceeds the MaxPeriod.
|
||||
* @return True if the encoder is considered stopped.
|
||||
*/
|
||||
HAL_Bool HAL_GetFPGAEncoderStopped(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
return encoder->encoder->readTimerOutput_Stalled(status) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The last direction the encoder value changed.
|
||||
* @return The last direction the encoder value changed.
|
||||
*/
|
||||
HAL_Bool HAL_GetFPGAEncoderDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
return encoder->encoder->readOutput_Direction(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the direction sensing for this encoder.
|
||||
* This sets the direction sensing on the encoder so that it could count in the
|
||||
* correct software direction regardless of the mounting.
|
||||
* @param reverseDirection true if the encoder direction should be reversed
|
||||
*/
|
||||
void HAL_SetFPGAEncoderReverseDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
HAL_Bool reverseDirection,
|
||||
int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
encoder->encoder->writeConfig_Reverse(reverseDirection, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Samples to Average which specifies the number of samples of the timer
|
||||
* to average when calculating the period. Perform averaging to account for
|
||||
* mechanical imperfections or as oversampling to increase resolution.
|
||||
* @param samplesToAverage The number of samples to average from 1 to 127.
|
||||
*/
|
||||
void HAL_SetFPGAEncoderSamplesToAverage(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t samplesToAverage,
|
||||
int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (samplesToAverage < 1 || samplesToAverage > 127) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
encoder->encoder->writeTimerConfig_AverageSize(samplesToAverage, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Samples to Average which specifies the number of samples of the timer
|
||||
* to average when calculating the period. Perform averaging to account for
|
||||
* mechanical imperfections or as oversampling to increase resolution.
|
||||
* @return SamplesToAverage The number of samples being averaged (from 1 to 127)
|
||||
*/
|
||||
int32_t HAL_GetFPGAEncoderSamplesToAverage(
|
||||
HAL_FPGAEncoderHandle fpgaEncoderHandle, int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
return encoder->encoder->readTimerConfig_AverageSize(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an index source for an encoder, which is an input that resets the
|
||||
* encoder's count.
|
||||
*/
|
||||
void HAL_SetFPGAEncoderIndexSource(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
HAL_Bool activeHigh, HAL_Bool edgeSensitive,
|
||||
int32_t* status) {
|
||||
auto encoder = fpgaEncoderHandles.Get(fpgaEncoderHandle);
|
||||
if (encoder == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
bool routingAnalogTrigger = false;
|
||||
uint8_t routingChannel = 0;
|
||||
uint8_t routingModule = 0;
|
||||
bool success =
|
||||
remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
|
||||
routingModule, routingAnalogTrigger);
|
||||
if (!success) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
encoder->encoder->writeConfig_IndexSource_Channel(routingChannel, status);
|
||||
encoder->encoder->writeConfig_IndexSource_Module(routingModule, status);
|
||||
encoder->encoder->writeConfig_IndexSource_AnalogTrigger(routingAnalogTrigger,
|
||||
status);
|
||||
encoder->encoder->writeConfig_IndexActiveHigh(activeHigh, status);
|
||||
encoder->encoder->writeConfig_IndexEdgeSensitive(edgeSensitive, status);
|
||||
}
|
||||
}
|
||||
47
hal/src/main/native/athena/FPGAEncoder.h
Normal file
47
hal/src/main/native/athena/FPGAEncoder.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/AnalogTrigger.h"
|
||||
#include "HAL/Types.h"
|
||||
|
||||
extern "C" {
|
||||
HAL_FPGAEncoderHandle HAL_InitializeFPGAEncoder(
|
||||
HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
|
||||
HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
|
||||
HAL_Bool reverseDirection, int32_t* index, int32_t* status);
|
||||
void HAL_FreeFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status);
|
||||
void HAL_ResetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status); // Raw value
|
||||
double HAL_GetFPGAEncoderPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetFPGAEncoderMaxPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
double maxPeriod, int32_t* status);
|
||||
HAL_Bool HAL_GetFPGAEncoderStopped(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_GetFPGAEncoderDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetFPGAEncoderReverseDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
HAL_Bool reverseDirection,
|
||||
int32_t* status);
|
||||
void HAL_SetFPGAEncoderSamplesToAverage(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
int32_t samplesToAverage,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetFPGAEncoderSamplesToAverage(
|
||||
HAL_FPGAEncoderHandle fpgaEncoderHandle, int32_t* status);
|
||||
void HAL_SetFPGAEncoderIndexSource(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
HAL_Bool activeHigh, HAL_Bool edgeSensitive,
|
||||
int32_t* status);
|
||||
}
|
||||
343
hal/src/main/native/athena/FRCDriverStation.cpp
Normal file
343
hal/src/main/native/athena/FRCDriverStation.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
#include "FRC_NetworkCommunication/FRCComm.h"
|
||||
#include "HAL/DriverStation.h"
|
||||
#include "HAL/cpp/priority_condition_variable.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "llvm/raw_ostream.h"
|
||||
|
||||
static_assert(sizeof(int32_t) >= sizeof(int),
|
||||
"FRC_NetworkComm status variable is larger than 32 bits");
|
||||
|
||||
struct HAL_JoystickAxesInt {
|
||||
int16_t count;
|
||||
int16_t axes[HAL_kMaxJoystickAxes];
|
||||
};
|
||||
|
||||
static hal::priority_mutex msgMutex;
|
||||
static hal::priority_condition_variable newDSDataAvailableCond;
|
||||
static hal::priority_mutex newDSDataAvailableMutex;
|
||||
static int newDSDataAvailableCounter{0};
|
||||
|
||||
extern "C" {
|
||||
int32_t HAL_SetErrorData(const char* errors, int32_t errorsLength,
|
||||
int32_t waitMs) {
|
||||
return setErrorData(errors, errorsLength, waitMs);
|
||||
}
|
||||
|
||||
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) {
|
||||
// Avoid flooding console by keeping track of previous 5 error
|
||||
// messages and only printing again if they're longer than 1 second old.
|
||||
static constexpr int KEEP_MSGS = 5;
|
||||
std::lock_guard<hal::priority_mutex> lock(msgMutex);
|
||||
static std::string prevMsg[KEEP_MSGS];
|
||||
static std::chrono::time_point<std::chrono::steady_clock>
|
||||
prevMsgTime[KEEP_MSGS];
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
for (int i = 0; i < KEEP_MSGS; i++) {
|
||||
prevMsgTime[i] =
|
||||
std::chrono::steady_clock::now() - std::chrono::seconds(2);
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
auto curTime = std::chrono::steady_clock::now();
|
||||
int i;
|
||||
for (i = 0; i < KEEP_MSGS; ++i) {
|
||||
if (prevMsg[i] == details) break;
|
||||
}
|
||||
int retval = 0;
|
||||
if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
|
||||
retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
|
||||
details, location, callStack);
|
||||
if (printMsg) {
|
||||
if (location && location[0] != '\0') {
|
||||
llvm::errs() << (isError ? "Error" : "Warning") << " at " << location
|
||||
<< ": ";
|
||||
}
|
||||
llvm::errs() << details << "\n";
|
||||
if (callStack && callStack[0] != '\0') {
|
||||
llvm::errs() << callStack << "\n";
|
||||
}
|
||||
}
|
||||
if (i == KEEP_MSGS) {
|
||||
// replace the oldest one
|
||||
i = 0;
|
||||
auto first = prevMsgTime[0];
|
||||
for (int j = 1; j < KEEP_MSGS; ++j) {
|
||||
if (prevMsgTime[j] < first) {
|
||||
first = prevMsgTime[j];
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
prevMsg[i] = details;
|
||||
}
|
||||
prevMsgTime[i] = curTime;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
|
||||
std::memset(controlWord, 0, sizeof(HAL_ControlWord));
|
||||
return FRC_NetworkCommunication_getControlWord(
|
||||
reinterpret_cast<ControlWord_t*>(controlWord));
|
||||
}
|
||||
|
||||
HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
|
||||
HAL_AllianceStationID allianceStation;
|
||||
*status = FRC_NetworkCommunication_getAllianceStation(
|
||||
reinterpret_cast<AllianceStationID_t*>(&allianceStation));
|
||||
return allianceStation;
|
||||
}
|
||||
|
||||
int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
|
||||
HAL_JoystickAxesInt axesInt;
|
||||
|
||||
int retVal = FRC_NetworkCommunication_getJoystickAxes(
|
||||
joystickNum, reinterpret_cast<JoystickAxes_t*>(&axesInt),
|
||||
HAL_kMaxJoystickAxes);
|
||||
|
||||
// copy integer values to double values
|
||||
axes->count = axesInt.count;
|
||||
// current scaling is -128 to 127, can easily be patched in the future by
|
||||
// changing this function.
|
||||
for (int32_t i = 0; i < axesInt.count; i++) {
|
||||
int8_t value = axesInt.axes[i];
|
||||
if (value < 0) {
|
||||
axes->axes[i] = value / 128.0;
|
||||
} else {
|
||||
axes->axes[i] = value / 127.0;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
|
||||
return FRC_NetworkCommunication_getJoystickPOVs(
|
||||
joystickNum, reinterpret_cast<JoystickPOV_t*>(povs),
|
||||
HAL_kMaxJoystickPOVs);
|
||||
}
|
||||
|
||||
int32_t HAL_GetJoystickButtons(int32_t joystickNum,
|
||||
HAL_JoystickButtons* buttons) {
|
||||
return FRC_NetworkCommunication_getJoystickButtons(
|
||||
joystickNum, &buttons->buttons, &buttons->count);
|
||||
}
|
||||
/**
|
||||
* Retrieve the Joystick Descriptor for particular slot
|
||||
* @param desc [out] 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++ Driverstation 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) {
|
||||
desc->isXbox = 0;
|
||||
desc->type = std::numeric_limits<uint8_t>::max();
|
||||
desc->name[0] = '\0';
|
||||
desc->axisCount =
|
||||
HAL_kMaxJoystickAxes; /* set to the desc->axisTypes's capacity */
|
||||
desc->buttonCount = 0;
|
||||
desc->povCount = 0;
|
||||
int retval = FRC_NetworkCommunication_getJoystickDesc(
|
||||
joystickNum, &desc->isXbox, &desc->type,
|
||||
reinterpret_cast<char*>(&desc->name), &desc->axisCount,
|
||||
reinterpret_cast<uint8_t*>(&desc->axisTypes), &desc->buttonCount,
|
||||
&desc->povCount);
|
||||
/* check the return, if there is an error and the RIOimage predates FRC2017,
|
||||
* then axisCount needs to be cleared */
|
||||
if (retval != 0) {
|
||||
/* set count to zero so downstream code doesn't decode invalid axisTypes. */
|
||||
desc->axisCount = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum) {
|
||||
HAL_JoystickDescriptor joystickDesc;
|
||||
if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return joystickDesc.isXbox;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t HAL_GetJoystickType(int32_t joystickNum) {
|
||||
HAL_JoystickDescriptor joystickDesc;
|
||||
if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return joystickDesc.type;
|
||||
}
|
||||
}
|
||||
|
||||
char* HAL_GetJoystickName(int32_t joystickNum) {
|
||||
HAL_JoystickDescriptor joystickDesc;
|
||||
if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
|
||||
char* name = static_cast<char*>(std::malloc(1));
|
||||
name[0] = '\0';
|
||||
return name;
|
||||
} else {
|
||||
size_t len = std::strlen(joystickDesc.name);
|
||||
char* name = static_cast<char*>(std::malloc(len + 1));
|
||||
std::strncpy(name, joystickDesc.name, len);
|
||||
name[len] = '\0';
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_FreeJoystickName(char* name) { std::free(name); }
|
||||
|
||||
int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) {
|
||||
HAL_JoystickDescriptor joystickDesc;
|
||||
if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return joystickDesc.axisTypes[axis];
|
||||
}
|
||||
}
|
||||
|
||||
int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
|
||||
int32_t leftRumble, int32_t rightRumble) {
|
||||
return FRC_NetworkCommunication_setJoystickOutputs(joystickNum, outputs,
|
||||
leftRumble, rightRumble);
|
||||
}
|
||||
|
||||
double HAL_GetMatchTime(int32_t* status) {
|
||||
float matchTime;
|
||||
*status = FRC_NetworkCommunication_getMatchTime(&matchTime);
|
||||
return matchTime;
|
||||
}
|
||||
|
||||
void HAL_ObserveUserProgramStarting(void) {
|
||||
FRC_NetworkCommunication_observeUserProgramStarting();
|
||||
}
|
||||
|
||||
void HAL_ObserveUserProgramDisabled(void) {
|
||||
FRC_NetworkCommunication_observeUserProgramDisabled();
|
||||
}
|
||||
|
||||
void HAL_ObserveUserProgramAutonomous(void) {
|
||||
FRC_NetworkCommunication_observeUserProgramAutonomous();
|
||||
}
|
||||
|
||||
void HAL_ObserveUserProgramTeleop(void) {
|
||||
FRC_NetworkCommunication_observeUserProgramTeleop();
|
||||
}
|
||||
|
||||
void HAL_ObserveUserProgramTest(void) {
|
||||
FRC_NetworkCommunication_observeUserProgramTest();
|
||||
}
|
||||
|
||||
bool HAL_IsNewControlData(void) {
|
||||
// There is a rollover error condition here. At Packet# = n * (uintmax), this
|
||||
// will return false when instead it should return true. However, this at a
|
||||
// 20ms rate occurs once every 2.7 years of DS connected runtime, so not
|
||||
// worth the cycles to check.
|
||||
thread_local int lastCount{-1};
|
||||
int currentCount = 0;
|
||||
{
|
||||
std::unique_lock<hal::priority_mutex> lock(newDSDataAvailableMutex);
|
||||
currentCount = newDSDataAvailableCounter;
|
||||
}
|
||||
if (lastCount == currentCount) return false;
|
||||
lastCount = currentCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the newest DS packet to arrive. Note that this is a blocking call.
|
||||
*/
|
||||
void HAL_WaitForDSData(void) { HAL_WaitForDSDataTimeout(0); }
|
||||
|
||||
/**
|
||||
* Waits for the newest DS packet to arrive. If timeout is <= 0, this will wait
|
||||
* forever. Otherwise, it will wait until either a new packet, or the timeout
|
||||
* time has passed. Returns true on new data, false on timeout.
|
||||
*/
|
||||
HAL_Bool HAL_WaitForDSDataTimeout(double timeout) {
|
||||
auto timeoutTime =
|
||||
std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
|
||||
|
||||
std::unique_lock<hal::priority_mutex> lock(newDSDataAvailableMutex);
|
||||
int currentCount = newDSDataAvailableCounter;
|
||||
while (newDSDataAvailableCounter == currentCount) {
|
||||
if (timeout > 0) {
|
||||
auto timedOut = newDSDataAvailableCond.wait_until(lock, timeoutTime);
|
||||
if (timedOut == std::cv_status::timeout) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
newDSDataAvailableCond.wait(lock);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Internal NetComm function to set new packet callback
|
||||
extern int NetCommRPCProxy_SetOccurFuncPointer(
|
||||
int32_t (*occurFunc)(uint32_t refNum));
|
||||
|
||||
// Constant number to be used for our occur handle
|
||||
constexpr int32_t refNumber = 42;
|
||||
|
||||
static int32_t newDataOccur(uint32_t refNum) {
|
||||
// Since we could get other values, require our specific handle
|
||||
// to signal our threads
|
||||
if (refNum != refNumber) return 0;
|
||||
std::lock_guard<hal::priority_mutex> lock(newDSDataAvailableMutex);
|
||||
// Nofify all threads
|
||||
newDSDataAvailableCounter++;
|
||||
newDSDataAvailableCond.notify_all();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this to initialize the driver station communication. This will properly
|
||||
* handle multiple calls. However note that this CANNOT be called from a library
|
||||
* that interfaces with LabVIEW.
|
||||
*/
|
||||
void HAL_InitializeDriverStation(void) {
|
||||
static std::atomic_bool initialized{false};
|
||||
static hal::priority_mutex initializeMutex;
|
||||
// Initial check, as if it's true initialization has finished
|
||||
if (initialized) return;
|
||||
|
||||
std::lock_guard<hal::priority_mutex> lock(initializeMutex);
|
||||
// Second check in case another thread was waiting
|
||||
if (initialized) return;
|
||||
|
||||
// Set up the occur function internally with NetComm
|
||||
NetCommRPCProxy_SetOccurFuncPointer(newDataOccur);
|
||||
// Set up our occur reference number
|
||||
setNewDataOccurRef(refNumber);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Releases the DS Mutex to allow proper shutdown of any threads that are
|
||||
* waiting on it.
|
||||
*/
|
||||
void HAL_ReleaseDSMutex(void) { newDataOccur(refNumber); }
|
||||
|
||||
} // extern "C"
|
||||
393
hal/src/main/native/athena/HAL.cpp
Normal file
393
hal/src/main/native/athena/HAL.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
|
||||
#include <signal.h> // linux for kill
|
||||
#include <sys/prctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "FRC_NetworkCommunication/CANSessionMux.h"
|
||||
#include "FRC_NetworkCommunication/FRCComm.h"
|
||||
#include "FRC_NetworkCommunication/LoadOut.h"
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/DriverStation.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Notifier.h"
|
||||
#include "HAL/cpp/NotifierInternal.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "ctre/ctre.h"
|
||||
#include "llvm/raw_ostream.h"
|
||||
#include "visa/visa.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static std::unique_ptr<tGlobal> global;
|
||||
static std::unique_ptr<tSysWatchdog> watchdog;
|
||||
|
||||
static hal::priority_mutex timeMutex;
|
||||
static uint32_t timeEpoch = 0;
|
||||
static uint32_t prevFPGATime = 0;
|
||||
static HAL_NotifierHandle rolloverNotifier = 0;
|
||||
|
||||
using namespace hal;
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_PortHandle HAL_GetPort(int32_t channel) {
|
||||
// Dont allow a number that wouldn't fit in a uint8_t
|
||||
if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
|
||||
return createPortHandle(channel, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Uses module numbers
|
||||
*/
|
||||
HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
|
||||
// Dont allow a number that wouldn't fit in a uint8_t
|
||||
if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
|
||||
if (module < 0 || module >= 255) return HAL_kInvalidHandle;
|
||||
return createPortHandle(channel, module);
|
||||
}
|
||||
|
||||
const char* HAL_GetErrorMessage(int32_t code) {
|
||||
switch (code) {
|
||||
case 0:
|
||||
return "";
|
||||
case CTR_RxTimeout:
|
||||
return CTR_RxTimeout_MESSAGE;
|
||||
case CTR_TxTimeout:
|
||||
return CTR_TxTimeout_MESSAGE;
|
||||
case CTR_InvalidParamValue:
|
||||
return CTR_InvalidParamValue_MESSAGE;
|
||||
case CTR_UnexpectedArbId:
|
||||
return CTR_UnexpectedArbId_MESSAGE;
|
||||
case CTR_TxFailed:
|
||||
return CTR_TxFailed_MESSAGE;
|
||||
case CTR_SigNotUpdated:
|
||||
return CTR_SigNotUpdated_MESSAGE;
|
||||
case NiFpga_Status_FifoTimeout:
|
||||
return NiFpga_Status_FifoTimeout_MESSAGE;
|
||||
case NiFpga_Status_TransferAborted:
|
||||
return NiFpga_Status_TransferAborted_MESSAGE;
|
||||
case NiFpga_Status_MemoryFull:
|
||||
return NiFpga_Status_MemoryFull_MESSAGE;
|
||||
case NiFpga_Status_SoftwareFault:
|
||||
return NiFpga_Status_SoftwareFault_MESSAGE;
|
||||
case NiFpga_Status_InvalidParameter:
|
||||
return NiFpga_Status_InvalidParameter_MESSAGE;
|
||||
case NiFpga_Status_ResourceNotFound:
|
||||
return NiFpga_Status_ResourceNotFound_MESSAGE;
|
||||
case NiFpga_Status_ResourceNotInitialized:
|
||||
return NiFpga_Status_ResourceNotInitialized_MESSAGE;
|
||||
case NiFpga_Status_HardwareFault:
|
||||
return NiFpga_Status_HardwareFault_MESSAGE;
|
||||
case NiFpga_Status_IrqTimeout:
|
||||
return NiFpga_Status_IrqTimeout_MESSAGE;
|
||||
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 ERR_CANSessionMux_InvalidBuffer:
|
||||
return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
|
||||
case ERR_CANSessionMux_MessageNotFound:
|
||||
return ERR_CANSessionMux_MessageNotFound_MESSAGE;
|
||||
case WARN_CANSessionMux_NoToken:
|
||||
return WARN_CANSessionMux_NoToken_MESSAGE;
|
||||
case ERR_CANSessionMux_NotAllowed:
|
||||
return ERR_CANSessionMux_NotAllowed_MESSAGE;
|
||||
case ERR_CANSessionMux_NotInitialized:
|
||||
return ERR_CANSessionMux_NotInitialized_MESSAGE;
|
||||
case VI_ERROR_SYSTEM_ERROR:
|
||||
return VI_ERROR_SYSTEM_ERROR_MESSAGE;
|
||||
case VI_ERROR_INV_OBJECT:
|
||||
return VI_ERROR_INV_OBJECT_MESSAGE;
|
||||
case VI_ERROR_RSRC_LOCKED:
|
||||
return VI_ERROR_RSRC_LOCKED_MESSAGE;
|
||||
case VI_ERROR_RSRC_NFOUND:
|
||||
return VI_ERROR_RSRC_NFOUND_MESSAGE;
|
||||
case VI_ERROR_INV_RSRC_NAME:
|
||||
return VI_ERROR_INV_RSRC_NAME_MESSAGE;
|
||||
case VI_ERROR_QUEUE_OVERFLOW:
|
||||
return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
|
||||
case VI_ERROR_IO:
|
||||
return VI_ERROR_IO_MESSAGE;
|
||||
case VI_ERROR_ASRL_PARITY:
|
||||
return VI_ERROR_ASRL_PARITY_MESSAGE;
|
||||
case VI_ERROR_ASRL_FRAMING:
|
||||
return VI_ERROR_ASRL_FRAMING_MESSAGE;
|
||||
case VI_ERROR_ASRL_OVERRUN:
|
||||
return VI_ERROR_ASRL_OVERRUN_MESSAGE;
|
||||
case VI_ERROR_RSRC_BUSY:
|
||||
return VI_ERROR_RSRC_BUSY_MESSAGE;
|
||||
case VI_ERROR_INV_PARAMETER:
|
||||
return VI_ERROR_INV_PARAMETER_MESSAGE;
|
||||
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;
|
||||
default:
|
||||
return "Unknown error status";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the runtime type of this HAL
|
||||
*/
|
||||
HAL_RuntimeType HAL_GetRuntimeType() { return HAL_Athena; }
|
||||
|
||||
/**
|
||||
* Return the FPGA Version number.
|
||||
* For now, expect this to be competition year.
|
||||
* @return FPGA Version number.
|
||||
*/
|
||||
int32_t HAL_GetFPGAVersion(int32_t* status) {
|
||||
if (!global) {
|
||||
*status = NiFpga_Status_ResourceNotInitialized;
|
||||
return 0;
|
||||
}
|
||||
return global->readVersion(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FPGA Revision number.
|
||||
* The format of the revision is 3 numbers.
|
||||
* The 12 most significant bits are the Major Revision.
|
||||
* the next 8 bits are the Minor Revision.
|
||||
* The 12 least significant bits are the Build Number.
|
||||
* @return FPGA Revision number.
|
||||
*/
|
||||
int64_t HAL_GetFPGARevision(int32_t* status) {
|
||||
if (!global) {
|
||||
*status = NiFpga_Status_ResourceNotInitialized;
|
||||
return 0;
|
||||
}
|
||||
return global->readRevision(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the microsecond-resolution timer on the FPGA.
|
||||
*
|
||||
* @return The current time in microseconds according to the FPGA (since FPGA
|
||||
* reset).
|
||||
*/
|
||||
uint64_t HAL_GetFPGATime(int32_t* status) {
|
||||
if (!global) {
|
||||
*status = NiFpga_Status_ResourceNotInitialized;
|
||||
return 0;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> lock(timeMutex);
|
||||
uint32_t fpgaTime = global->readLocalTime(status);
|
||||
if (*status != 0) return 0;
|
||||
// check for rollover
|
||||
if (fpgaTime < prevFPGATime) ++timeEpoch;
|
||||
prevFPGATime = fpgaTime;
|
||||
return static_cast<uint64_t>(timeEpoch) << 32 |
|
||||
static_cast<uint64_t>(fpgaTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of the "USER" button on the roboRIO
|
||||
* @return true if the button is currently pressed down
|
||||
*/
|
||||
HAL_Bool HAL_GetFPGAButton(int32_t* status) {
|
||||
if (!global) {
|
||||
*status = NiFpga_Status_ResourceNotInitialized;
|
||||
return false;
|
||||
}
|
||||
return global->readUserButton(status);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetSystemActive(int32_t* status) {
|
||||
if (!watchdog) {
|
||||
*status = NiFpga_Status_ResourceNotInitialized;
|
||||
return false;
|
||||
}
|
||||
return watchdog->readStatus_SystemActive(status);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetBrownedOut(int32_t* status) {
|
||||
if (!watchdog) {
|
||||
*status = NiFpga_Status_ResourceNotInitialized;
|
||||
return false;
|
||||
}
|
||||
return !(watchdog->readStatus_PowerAlive(status));
|
||||
}
|
||||
|
||||
static void timerRollover(uint64_t currentTime, HAL_NotifierHandle handle) {
|
||||
// reschedule timer for next rollover
|
||||
int32_t status = 0;
|
||||
HAL_UpdateNotifierAlarm(handle, currentTime + 0x80000000ULL, &status);
|
||||
}
|
||||
|
||||
void HAL_BaseInitialize(int32_t* status) {
|
||||
static std::atomic_bool initialized{false};
|
||||
static hal::priority_mutex initializeMutex;
|
||||
// Initial check, as if it's true initialization has finished
|
||||
if (initialized) return;
|
||||
|
||||
std::lock_guard<hal::priority_mutex> lock(initializeMutex);
|
||||
// Second check in case another thread was waiting
|
||||
if (initialized) return;
|
||||
// image 4; Fixes errors caused by multiple processes. Talk to NI about this
|
||||
nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
|
||||
nLoadOut::kTargetClass_RoboRIO;
|
||||
|
||||
global.reset(tGlobal::create(status));
|
||||
watchdog.reset(tSysWatchdog::create(status));
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
static bool killExistingProgram(int timeout, int mode) {
|
||||
// Kill any previous robot programs
|
||||
std::fstream fs;
|
||||
// By making this both in/out, it won't give us an error if it doesnt exist
|
||||
fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
|
||||
if (fs.bad()) return false;
|
||||
|
||||
pid_t pid = 0;
|
||||
if (!fs.eof() && !fs.fail()) {
|
||||
fs >> pid;
|
||||
// see if the pid is around, but we don't want to mess with init id=1, or
|
||||
// ourselves
|
||||
if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid()) {
|
||||
llvm::outs() << "Killing previously running FRC program...\n";
|
||||
kill(pid, SIGTERM); // try to kill it
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
|
||||
if (kill(pid, 0) == 0) {
|
||||
// still not successfull
|
||||
if (mode == 0) {
|
||||
llvm::outs() << "FRC pid " << pid << " did not die within " << timeout
|
||||
<< "ms. Aborting\n";
|
||||
return 0; // just fail
|
||||
} else if (mode == 1) { // kill -9 it
|
||||
kill(pid, SIGKILL);
|
||||
} else {
|
||||
llvm::outs() << "WARNING: FRC pid " << pid << " did not die within "
|
||||
<< timeout << "ms.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fs.close();
|
||||
// we will re-open it write only to truncate the file
|
||||
fs.open("/var/lock/frc.pid", std::fstream::out | std::fstream::trunc);
|
||||
fs.seekp(0);
|
||||
pid = getpid();
|
||||
fs << pid << std::endl;
|
||||
fs.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to start up HAL. This is required for robot programs.
|
||||
*/
|
||||
HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
|
||||
setlinebuf(stdin);
|
||||
setlinebuf(stdout);
|
||||
|
||||
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||
|
||||
// Return false if program failed to kill an existing program
|
||||
if (!killExistingProgram(timeout, mode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FRC_NetworkCommunication_Reserve(nullptr);
|
||||
|
||||
std::atexit([]() {
|
||||
// Unregister our new data condition variable.
|
||||
setNewDataSem(nullptr);
|
||||
});
|
||||
|
||||
int32_t status = 0;
|
||||
HAL_BaseInitialize(&status);
|
||||
|
||||
if (!rolloverNotifier)
|
||||
rolloverNotifier = HAL_InitializeNotifierNonThreadedUnsafe(
|
||||
timerRollover, nullptr, &status);
|
||||
if (status == 0) {
|
||||
uint64_t curTime = HAL_GetFPGATime(&status);
|
||||
if (status == 0) {
|
||||
HAL_UpdateNotifierAlarm(rolloverNotifier, curTime + 0x80000000ULL,
|
||||
&status);
|
||||
} else {
|
||||
// return false if status failed.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// return false if status failed.
|
||||
return false;
|
||||
}
|
||||
|
||||
HAL_InitializeDriverStation();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
|
||||
const char* feature) {
|
||||
if (feature == nullptr) {
|
||||
feature = "";
|
||||
}
|
||||
|
||||
return FRC_NetworkCommunication_nUsageReporting_report(
|
||||
resource, instanceNumber, context, feature);
|
||||
}
|
||||
|
||||
// TODO: HACKS
|
||||
// No need for header definitions, as we should not run from user code.
|
||||
void NumericArrayResize() {}
|
||||
void RTSetCleanupProc() {}
|
||||
void EDVR_CreateReference() {}
|
||||
|
||||
} // extern "C"
|
||||
183
hal/src/main/native/athena/I2C.cpp
Normal file
183
hal/src/main/native/athena/I2C.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/I2C.h"
|
||||
|
||||
#include "DigitalInternal.h"
|
||||
#include "HAL/DIO.h"
|
||||
#include "HAL/HAL.h"
|
||||
#include "i2clib/i2c-lib.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static priority_recursive_mutex digitalI2COnBoardMutex;
|
||||
static priority_recursive_mutex digitalI2CMXPMutex;
|
||||
|
||||
static uint8_t i2COnboardObjCount = 0;
|
||||
static uint8_t i2CMXPObjCount = 0;
|
||||
static uint8_t i2COnBoardHandle = 0;
|
||||
static uint8_t i2CMXPHandle = 0;
|
||||
|
||||
static HAL_DigitalHandle i2CMXPDigitalHandle1 = HAL_kInvalidHandle;
|
||||
static HAL_DigitalHandle i2CMXPDigitalHandle2 = HAL_kInvalidHandle;
|
||||
|
||||
extern "C" {
|
||||
/*
|
||||
* Initialize the I2C port. Opens the port if necessary and saves the handle.
|
||||
* If opening the MXP port, also sets up the channel functions appropriately
|
||||
* @param port The port to open, 0 for the on-board, 1 for the MXP.
|
||||
*/
|
||||
void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status) {
|
||||
initializeDigital(status);
|
||||
if (*status != 0) return;
|
||||
|
||||
if (port > 1) {
|
||||
// Set port out of range error here
|
||||
return;
|
||||
}
|
||||
|
||||
priority_recursive_mutex& lock =
|
||||
port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(lock);
|
||||
if (port == 0) {
|
||||
i2COnboardObjCount++;
|
||||
if (i2COnBoardHandle > 0) return;
|
||||
i2COnBoardHandle = i2clib_open("/dev/i2c-2");
|
||||
} else if (port == 1) {
|
||||
i2CMXPObjCount++;
|
||||
if (i2CMXPHandle > 0) return;
|
||||
if ((i2CMXPDigitalHandle1 = HAL_InitializeDIOPort(
|
||||
HAL_GetPort(24), false, status)) == HAL_kInvalidHandle) {
|
||||
return;
|
||||
}
|
||||
if ((i2CMXPDigitalHandle2 = HAL_InitializeDIOPort(
|
||||
HAL_GetPort(25), false, status)) == HAL_kInvalidHandle) {
|
||||
HAL_FreeDIOPort(i2CMXPDigitalHandle1); // free the first port allocated
|
||||
return;
|
||||
}
|
||||
digitalSystem->writeEnableMXPSpecialFunction(
|
||||
digitalSystem->readEnableMXPSpecialFunction(status) | 0xC000, status);
|
||||
i2CMXPHandle = i2clib_open("/dev/i2c-1");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic transaction.
|
||||
*
|
||||
* This is a lower-level interface to the I2C hardware giving you more control
|
||||
* over each transaction.
|
||||
*
|
||||
* @param dataToSend Buffer of data to send as part of the transaction.
|
||||
* @param sendSize Number of bytes to send as part of the transaction.
|
||||
* @param dataReceived Buffer to read data into.
|
||||
* @param receiveSize Number of bytes to read from the device.
|
||||
* @return >= 0 on success or -1 on transfer abort.
|
||||
*/
|
||||
int32_t HAL_TransactionI2C(HAL_I2CPort port, int32_t deviceAddress,
|
||||
uint8_t* dataToSend, int32_t sendSize,
|
||||
uint8_t* dataReceived, int32_t receiveSize) {
|
||||
if (port > 1) {
|
||||
// Set port out of range error here
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t handle = port == 0 ? i2COnBoardHandle : i2CMXPHandle;
|
||||
priority_recursive_mutex& lock =
|
||||
port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
|
||||
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(lock);
|
||||
return i2clib_writeread(
|
||||
handle, deviceAddress, reinterpret_cast<const char*>(dataToSend),
|
||||
static_cast<int32_t>(sendSize), reinterpret_cast<char*>(dataReceived),
|
||||
static_cast<int32_t>(receiveSize));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a write transaction with the device.
|
||||
*
|
||||
* Write a single byte to a register on a device and wait until the
|
||||
* transaction is complete.
|
||||
*
|
||||
* @param registerAddress The address of the register on the device to be
|
||||
* written.
|
||||
* @param data The byte to write to the register on the device.
|
||||
* @return >= 0 on success or -1 on transfer abort.
|
||||
*/
|
||||
int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress,
|
||||
uint8_t* dataToSend, int32_t sendSize) {
|
||||
if (port > 1) {
|
||||
// Set port out of range error here
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t handle = port == 0 ? i2COnBoardHandle : i2CMXPHandle;
|
||||
priority_recursive_mutex& lock =
|
||||
port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(lock);
|
||||
return i2clib_write(handle, deviceAddress,
|
||||
reinterpret_cast<const char*>(dataToSend), sendSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a read transaction with the device.
|
||||
*
|
||||
* Read bytes from a device.
|
||||
* Most I2C devices will auto-increment the register pointer internally allowing
|
||||
* you to read consecutive registers on a device in a single transaction.
|
||||
*
|
||||
* @param registerAddress The register to read first in the transaction.
|
||||
* @param count The number of bytes to read in the transaction.
|
||||
* @param buffer A pointer to the array of bytes to store the data read from the
|
||||
* device.
|
||||
* @return >= 0 on success or -1 on transfer abort.
|
||||
*/
|
||||
int32_t HAL_ReadI2C(HAL_I2CPort port, int32_t deviceAddress, uint8_t* buffer,
|
||||
int32_t count) {
|
||||
if (port > 1) {
|
||||
// Set port out of range error here
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t handle = port == 0 ? i2COnBoardHandle : i2CMXPHandle;
|
||||
priority_recursive_mutex& lock =
|
||||
port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(lock);
|
||||
return i2clib_read(handle, deviceAddress, reinterpret_cast<char*>(buffer),
|
||||
static_cast<int32_t>(count));
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_CloseI2C(HAL_I2CPort port) {
|
||||
if (port > 1) {
|
||||
// Set port out of range error here
|
||||
return;
|
||||
}
|
||||
priority_recursive_mutex& lock =
|
||||
port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(lock);
|
||||
if ((port == 0 ? i2COnboardObjCount-- : i2CMXPObjCount--) == 0) {
|
||||
int32_t handle = port == 0 ? i2COnBoardHandle : i2CMXPHandle;
|
||||
i2clib_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
if (port == 1) {
|
||||
HAL_FreeDIOPort(i2CMXPDigitalHandle1);
|
||||
HAL_FreeDIOPort(i2CMXPDigitalHandle2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
258
hal/src/main/native/athena/Interrupts.cpp
Normal file
258
hal/src/main/native/athena/Interrupts.cpp
Normal file
@@ -0,0 +1,258 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Interrupts.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "DigitalInternal.h"
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "HAL/handles/LimitedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
#include "support/SafeThread.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace {
|
||||
struct Interrupt {
|
||||
std::unique_ptr<tInterrupt> anInterrupt;
|
||||
std::unique_ptr<tInterruptManager> manager;
|
||||
};
|
||||
|
||||
// Safe thread to allow callbacks to run on their own thread
|
||||
class InterruptThread : public wpi::SafeThread {
|
||||
public:
|
||||
void Main() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
while (m_active) {
|
||||
m_cond.wait(lock, [&] { return !m_active || m_notify; });
|
||||
if (!m_active) break;
|
||||
m_notify = false;
|
||||
HAL_InterruptHandlerFunction handler = m_handler;
|
||||
uint32_t mask = m_mask;
|
||||
void* param = m_param;
|
||||
lock.unlock(); // don't hold mutex during callback execution
|
||||
handler(mask, param);
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
bool m_notify = false;
|
||||
HAL_InterruptHandlerFunction m_handler;
|
||||
void* m_param;
|
||||
uint32_t m_mask;
|
||||
};
|
||||
|
||||
class InterruptThreadOwner : public wpi::SafeThreadOwner<InterruptThread> {
|
||||
public:
|
||||
void SetFunc(HAL_InterruptHandlerFunction handler, void* param) {
|
||||
auto thr = GetThread();
|
||||
if (!thr) return;
|
||||
thr->m_handler = handler;
|
||||
thr->m_param = param;
|
||||
}
|
||||
|
||||
void Notify(uint32_t mask) {
|
||||
auto thr = GetThread();
|
||||
if (!thr) return;
|
||||
thr->m_mask = mask;
|
||||
thr->m_notify = true;
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static void threadedInterruptHandler(uint32_t mask, void* param) {
|
||||
static_cast<InterruptThreadOwner*>(param)->Notify(mask);
|
||||
}
|
||||
|
||||
static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
|
||||
HAL_HandleEnum::Interrupt>
|
||||
interruptHandles;
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
|
||||
int32_t* status) {
|
||||
HAL_InterruptHandle handle = interruptHandles.Allocate();
|
||||
if (handle == HAL_kInvalidHandle) {
|
||||
*status = NO_AVAILABLE_RESOURCES;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
auto anInterrupt = interruptHandles.Get(handle);
|
||||
uint32_t interruptIndex = static_cast<uint32_t>(getHandleIndex(handle));
|
||||
// Expects the calling leaf class to allocate an interrupt index.
|
||||
anInterrupt->anInterrupt.reset(tInterrupt::create(interruptIndex, status));
|
||||
anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
|
||||
anInterrupt->manager = std::make_unique<tInterruptManager>(
|
||||
(1u << interruptIndex) | (1u << (interruptIndex + 8u)), watcher, status);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status) {
|
||||
interruptHandles.Free(interruptHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* In synchronous mode, wait for the defined interrupt to occur.
|
||||
* @param timeout Timeout in seconds
|
||||
* @param ignorePrevious If true, ignore interrupts that happened before
|
||||
* waitForInterrupt was called.
|
||||
* @return The mask of interrupts that fired.
|
||||
*/
|
||||
int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
|
||||
double timeout, HAL_Bool ignorePrevious,
|
||||
int32_t* status) {
|
||||
uint32_t result;
|
||||
auto anInterrupt = interruptHandles.Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = anInterrupt->manager->watch(static_cast<int32_t>(timeout * 1e3),
|
||||
ignorePrevious, status);
|
||||
|
||||
// Don't report a timeout as an error - the return code is enough to tell
|
||||
// that a timeout happened.
|
||||
if (*status == -NiFpga_Status_IrqTimeout) {
|
||||
*status = NiFpga_Status_Success;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable interrupts to occur on this input.
|
||||
* Interrupts are disabled when the RequestInterrupt call is made. This gives
|
||||
* time to do the setup of the other options before starting to field
|
||||
* interrupts.
|
||||
*/
|
||||
void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles.Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
anInterrupt->manager->enable(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Interrupts without without deallocating structures.
|
||||
*/
|
||||
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles.Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
anInterrupt->manager->disable(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the timestamp for the rising interrupt that occurred most recently.
|
||||
* This is in the same time domain as GetClock().
|
||||
* @return Timestamp in seconds since boot.
|
||||
*/
|
||||
double HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles.Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
uint32_t timestamp = anInterrupt->anInterrupt->readRisingTimeStamp(status);
|
||||
return timestamp * 1e-6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the timestamp for the falling interrupt that occurred most recently.
|
||||
* This is in the same time domain as GetClock().
|
||||
* @return Timestamp in seconds since boot.
|
||||
*/
|
||||
double HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles.Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
uint32_t timestamp = anInterrupt->anInterrupt->readFallingTimeStamp(status);
|
||||
return timestamp * 1e-6;
|
||||
}
|
||||
|
||||
void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles.Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
|
||||
bool routingAnalogTrigger = false;
|
||||
uint8_t routingChannel = 0;
|
||||
uint8_t routingModule = 0;
|
||||
bool success =
|
||||
remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
|
||||
routingModule, routingAnalogTrigger);
|
||||
if (!success) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
anInterrupt->anInterrupt->writeConfig_Source_AnalogTrigger(
|
||||
routingAnalogTrigger, status);
|
||||
anInterrupt->anInterrupt->writeConfig_Source_Channel(routingChannel, status);
|
||||
anInterrupt->anInterrupt->writeConfig_Source_Module(routingModule, status);
|
||||
}
|
||||
|
||||
void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status) {
|
||||
auto anInterrupt = interruptHandles.Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
anInterrupt->manager->registerHandler(handler, param, status);
|
||||
}
|
||||
|
||||
void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interrupt_handle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status) {
|
||||
InterruptThreadOwner* intr = new InterruptThreadOwner;
|
||||
intr->Start();
|
||||
intr->SetFunc(handler, param);
|
||||
|
||||
HAL_AttachInterruptHandler(interrupt_handle, threadedInterruptHandler, intr,
|
||||
status);
|
||||
|
||||
if (*status != 0) {
|
||||
delete intr;
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
|
||||
HAL_Bool risingEdge, HAL_Bool fallingEdge,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles.Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
anInterrupt->anInterrupt->writeConfig_RisingEdge(risingEdge, status);
|
||||
anInterrupt->anInterrupt->writeConfig_FallingEdge(fallingEdge, status);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
300
hal/src/main/native/athena/Notifier.cpp
Normal file
300
hal/src/main/native/athena/Notifier.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Notifier.h"
|
||||
|
||||
// For std::atexit()
|
||||
#include <cstdlib>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/HAL.h"
|
||||
#include "HAL/cpp/NotifierInternal.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/UnlimitedHandleResource.h"
|
||||
#include "support/SafeThread.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static const int32_t kTimerInterruptNumber = 28;
|
||||
|
||||
static hal::priority_mutex notifierInterruptMutex;
|
||||
static priority_recursive_mutex notifierMutex;
|
||||
static std::unique_ptr<tAlarm> notifierAlarm;
|
||||
static std::unique_ptr<tInterruptManager> notifierManager;
|
||||
static uint64_t closestTrigger = UINT64_MAX;
|
||||
|
||||
namespace {
|
||||
struct Notifier {
|
||||
std::shared_ptr<Notifier> prev, next;
|
||||
void* param;
|
||||
HAL_NotifierProcessFunction process;
|
||||
uint64_t triggerTime = UINT64_MAX;
|
||||
HAL_NotifierHandle handle;
|
||||
bool threaded;
|
||||
};
|
||||
|
||||
// Safe thread to allow callbacks to run on their own thread
|
||||
class NotifierThread : public wpi::SafeThread {
|
||||
public:
|
||||
void Main() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
while (m_active) {
|
||||
m_cond.wait(lock, [&] { return !m_active || m_notify; });
|
||||
if (!m_active) break;
|
||||
m_notify = false;
|
||||
uint64_t currentTime = m_currentTime;
|
||||
HAL_NotifierHandle handle = m_handle;
|
||||
HAL_NotifierProcessFunction process = m_process;
|
||||
lock.unlock(); // don't hold mutex during callback execution
|
||||
process(currentTime, handle);
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
bool m_notify = false;
|
||||
HAL_NotifierHandle m_handle = HAL_kInvalidHandle;
|
||||
HAL_NotifierProcessFunction m_process;
|
||||
uint64_t m_currentTime;
|
||||
};
|
||||
|
||||
class NotifierThreadOwner : public wpi::SafeThreadOwner<NotifierThread> {
|
||||
public:
|
||||
void SetFunc(HAL_NotifierProcessFunction process, void* param) {
|
||||
auto thr = GetThread();
|
||||
if (!thr) return;
|
||||
thr->m_process = process;
|
||||
m_param = param;
|
||||
}
|
||||
|
||||
void Notify(uint64_t currentTime, HAL_NotifierHandle handle) {
|
||||
auto thr = GetThread();
|
||||
if (!thr) return;
|
||||
thr->m_currentTime = currentTime;
|
||||
thr->m_handle = handle;
|
||||
thr->m_notify = true;
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
|
||||
void* m_param;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static std::shared_ptr<Notifier> notifiers;
|
||||
static std::atomic_flag notifierAtexitRegistered = ATOMIC_FLAG_INIT;
|
||||
static std::atomic_int notifierRefCount{0};
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static UnlimitedHandleResource<HAL_NotifierHandle, Notifier,
|
||||
HAL_HandleEnum::Notifier>
|
||||
notifierHandles;
|
||||
|
||||
// internal version of updateAlarm used during the alarmCallback when we know
|
||||
// that the pointer is a valid pointer.
|
||||
void updateNotifierAlarmInternal(std::shared_ptr<Notifier> notifierPointer,
|
||||
uint64_t triggerTime, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
|
||||
|
||||
auto notifier = notifierPointer;
|
||||
// no need for a null check, as this must always be a valid pointer.
|
||||
notifier->triggerTime = triggerTime;
|
||||
bool wasActive = (closestTrigger != UINT64_MAX);
|
||||
|
||||
if (!notifierInterruptMutex.try_lock() || notifierRefCount == 0 ||
|
||||
!notifierAlarm)
|
||||
return;
|
||||
|
||||
// Update alarm time if closer than current.
|
||||
if (triggerTime < closestTrigger) {
|
||||
closestTrigger = triggerTime;
|
||||
// Simply truncate the hardware trigger time to 32-bit.
|
||||
notifierAlarm->writeTriggerTime(static_cast<uint32_t>(triggerTime), status);
|
||||
}
|
||||
// Enable the alarm. The hardware disables itself after each alarm.
|
||||
if (!wasActive) notifierAlarm->writeEnable(true, status);
|
||||
|
||||
notifierInterruptMutex.unlock();
|
||||
}
|
||||
|
||||
static void alarmCallback(uint32_t, void*) {
|
||||
std::unique_lock<priority_recursive_mutex> sync(notifierMutex);
|
||||
|
||||
int32_t status = 0;
|
||||
uint64_t currentTime = 0;
|
||||
|
||||
// the hardware disables itself after each alarm
|
||||
closestTrigger = UINT64_MAX;
|
||||
|
||||
// process all notifiers
|
||||
std::shared_ptr<Notifier> notifier = notifiers;
|
||||
while (notifier) {
|
||||
if (notifier->triggerTime != UINT64_MAX) {
|
||||
if (currentTime == 0) currentTime = HAL_GetFPGATime(&status);
|
||||
if (notifier->triggerTime < currentTime) {
|
||||
notifier->triggerTime = UINT64_MAX;
|
||||
auto process = notifier->process;
|
||||
auto handle = notifier->handle;
|
||||
sync.unlock();
|
||||
process(currentTime, handle);
|
||||
sync.lock();
|
||||
} else if (notifier->triggerTime < closestTrigger) {
|
||||
updateNotifierAlarmInternal(notifier, notifier->triggerTime, &status);
|
||||
}
|
||||
}
|
||||
notifier = notifier->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanupNotifierAtExit() {
|
||||
notifierAlarm = nullptr;
|
||||
notifierManager = nullptr;
|
||||
}
|
||||
|
||||
static void threadedNotifierHandler(uint64_t currentTimeInt,
|
||||
HAL_NotifierHandle handle) {
|
||||
// Grab notifier and get handler param
|
||||
auto notifier = notifierHandles.Get(handle);
|
||||
if (!notifier) return;
|
||||
auto notifierPointer = notifier->param;
|
||||
if (notifierPointer == nullptr) return;
|
||||
NotifierThreadOwner* owner =
|
||||
static_cast<NotifierThreadOwner*>(notifierPointer);
|
||||
owner->Notify(currentTimeInt, handle);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_NotifierHandle HAL_InitializeNotifierNonThreadedUnsafe(
|
||||
HAL_NotifierProcessFunction process, void* param, int32_t* status) {
|
||||
if (!process) {
|
||||
*status = NULL_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
if (!notifierAtexitRegistered.test_and_set())
|
||||
std::atexit(cleanupNotifierAtExit);
|
||||
if (notifierRefCount.fetch_add(1) == 0) {
|
||||
std::lock_guard<hal::priority_mutex> sync(notifierInterruptMutex);
|
||||
// create manager and alarm if not already created
|
||||
if (!notifierManager) {
|
||||
notifierManager = std::make_unique<tInterruptManager>(
|
||||
1 << kTimerInterruptNumber, false, status);
|
||||
notifierManager->registerHandler(alarmCallback, nullptr, status);
|
||||
notifierManager->enable(status);
|
||||
}
|
||||
if (!notifierAlarm) notifierAlarm.reset(tAlarm::create(status));
|
||||
}
|
||||
|
||||
std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
|
||||
std::shared_ptr<Notifier> notifier = std::make_shared<Notifier>();
|
||||
HAL_NotifierHandle handle = notifierHandles.Allocate(notifier);
|
||||
if (handle == HAL_kInvalidHandle) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
// create notifier structure and add to list
|
||||
notifier->next = notifiers;
|
||||
if (notifier->next) notifier->next->prev = notifier;
|
||||
notifier->param = param;
|
||||
notifier->process = process;
|
||||
notifier->handle = handle;
|
||||
notifier->threaded = false;
|
||||
notifiers = notifier;
|
||||
return handle;
|
||||
}
|
||||
|
||||
HAL_NotifierHandle HAL_InitializeNotifier(HAL_NotifierProcessFunction process,
|
||||
void* param, int32_t* status) {
|
||||
NotifierThreadOwner* notify = new NotifierThreadOwner;
|
||||
notify->Start();
|
||||
notify->SetFunc(process, param);
|
||||
|
||||
auto notifierHandle = HAL_InitializeNotifierNonThreadedUnsafe(
|
||||
threadedNotifierHandler, notify, status);
|
||||
|
||||
if (notifierHandle == HAL_kInvalidHandle || *status != 0) {
|
||||
delete notify;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
auto notifier = notifierHandles.Get(notifierHandle);
|
||||
if (!notifier) {
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
notifier->threaded = true;
|
||||
|
||||
return notifierHandle;
|
||||
}
|
||||
|
||||
void HAL_CleanNotifier(HAL_NotifierHandle notifierHandle, int32_t* status) {
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
|
||||
auto notifier = notifierHandles.Get(notifierHandle);
|
||||
if (!notifier) return;
|
||||
|
||||
// remove from list
|
||||
if (notifier->prev) notifier->prev->next = notifier->next;
|
||||
if (notifier->next) notifier->next->prev = notifier->prev;
|
||||
if (notifiers == notifier) notifiers = notifier->next;
|
||||
notifierHandles.Free(notifierHandle);
|
||||
|
||||
if (notifier->threaded) {
|
||||
NotifierThreadOwner* owner =
|
||||
static_cast<NotifierThreadOwner*>(notifier->param);
|
||||
delete owner;
|
||||
}
|
||||
}
|
||||
|
||||
if (notifierRefCount.fetch_sub(1) == 1) {
|
||||
std::lock_guard<hal::priority_mutex> sync(notifierInterruptMutex);
|
||||
// if this was the last notifier, clean up alarm and manager
|
||||
if (notifierAlarm) {
|
||||
notifierAlarm->writeEnable(false, status);
|
||||
notifierAlarm = nullptr;
|
||||
}
|
||||
if (notifierManager) {
|
||||
notifierManager->disable(status);
|
||||
notifierManager = nullptr;
|
||||
}
|
||||
closestTrigger = UINT64_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void* HAL_GetNotifierParam(HAL_NotifierHandle notifierHandle, int32_t* status) {
|
||||
auto notifier = notifierHandles.Get(notifierHandle);
|
||||
if (!notifier) return nullptr;
|
||||
if (notifier->threaded) {
|
||||
// If threaded, return thread param rather then notifier param
|
||||
NotifierThreadOwner* owner =
|
||||
static_cast<NotifierThreadOwner*>(notifier->param);
|
||||
return owner->m_param;
|
||||
}
|
||||
return notifier->param;
|
||||
}
|
||||
|
||||
void HAL_UpdateNotifierAlarm(HAL_NotifierHandle notifierHandle,
|
||||
uint64_t triggerTime, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
|
||||
|
||||
auto notifier = notifierHandles.Get(notifierHandle);
|
||||
if (!notifier) return;
|
||||
updateNotifierAlarmInternal(notifier, triggerTime, status);
|
||||
}
|
||||
|
||||
void HAL_StopNotifierAlarm(HAL_NotifierHandle notifierHandle, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
|
||||
auto notifier = notifierHandles.Get(notifierHandle);
|
||||
if (!notifier) return;
|
||||
notifier->triggerTime = UINT64_MAX;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
232
hal/src/main/native/athena/OSSerialPort.cpp
Normal file
232
hal/src/main/native/athena/OSSerialPort.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/OSSerialPort.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/cpp/SerialHelper.h"
|
||||
|
||||
static int portHandles[4]{-1, -1, -1, -1};
|
||||
static std::chrono::milliseconds portTimeouts[4]{
|
||||
std::chrono::milliseconds(0), std::chrono::milliseconds(0),
|
||||
std::chrono::milliseconds(0), std::chrono::milliseconds(0)};
|
||||
|
||||
extern "C" {
|
||||
|
||||
void HAL_InitializeOSSerialPort(HAL_SerialPort port, int32_t* status) {
|
||||
std::string portName;
|
||||
|
||||
hal::SerialHelper serialHelper;
|
||||
|
||||
portName = serialHelper.GetOSSerialPortName(port, status);
|
||||
|
||||
if (*status < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fs = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (fs == -1) {
|
||||
*status = HAL_SERIAL_PORT_OPEN_ERROR;
|
||||
return;
|
||||
}
|
||||
portHandles[port] = fs;
|
||||
|
||||
struct termios options;
|
||||
tcgetattr(fs, &options);
|
||||
options.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
|
||||
options.c_iflag = 0;
|
||||
options.c_oflag = 0;
|
||||
options.c_lflag = 0;
|
||||
tcflush(fs, TCIFLUSH);
|
||||
tcsetattr(fs, TCSANOW, &options);
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialBaudRate(HAL_SerialPort port, int32_t baud,
|
||||
int32_t* status) {
|
||||
int baudRate = -1;
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
baudRate = B9600;
|
||||
break;
|
||||
case 19200:
|
||||
baudRate = B19200;
|
||||
break;
|
||||
case 38400:
|
||||
baudRate = B38400;
|
||||
break;
|
||||
case 57600:
|
||||
baudRate = B57600;
|
||||
break;
|
||||
case 115200:
|
||||
baudRate = B115200;
|
||||
break;
|
||||
default:
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return;
|
||||
}
|
||||
|
||||
struct termios options;
|
||||
tcgetattr(portHandles[port], &options);
|
||||
auto set = cfsetospeed(&options, baudRate);
|
||||
if (set != 0) {
|
||||
*status = HAL_SERIAL_PORT_ERROR;
|
||||
return;
|
||||
}
|
||||
set = tcsetattr(portHandles[port], TCSANOW, &options);
|
||||
if (set != 0) {
|
||||
*status = HAL_SERIAL_PORT_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialDataBits(HAL_SerialPort port, int32_t bits,
|
||||
int32_t* status) {
|
||||
int numBits = -1;
|
||||
switch (bits) {
|
||||
case 5:
|
||||
numBits = CS5;
|
||||
break;
|
||||
case 6:
|
||||
numBits = CS6;
|
||||
break;
|
||||
case 7:
|
||||
numBits = CS7;
|
||||
break;
|
||||
case 8:
|
||||
numBits = CS8;
|
||||
break;
|
||||
default:
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return;
|
||||
}
|
||||
|
||||
struct termios options;
|
||||
tcgetattr(portHandles[port], &options);
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= numBits;
|
||||
auto set = tcsetattr(portHandles[port], TCSANOW, &options);
|
||||
if (set != 0) {
|
||||
*status = HAL_SERIAL_PORT_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialParity(HAL_SerialPort port, int32_t parity,
|
||||
int32_t* status) {
|
||||
// Just set none parity
|
||||
struct termios options;
|
||||
tcgetattr(portHandles[port], &options);
|
||||
options.c_cflag &= ~PARENB;
|
||||
auto set = tcsetattr(portHandles[port], TCSANOW, &options);
|
||||
if (set != 0) {
|
||||
*status = HAL_SERIAL_PORT_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialStopBits(HAL_SerialPort port, int32_t stopBits,
|
||||
int32_t* status) {
|
||||
// Force 1 stop bit
|
||||
struct termios options;
|
||||
tcgetattr(portHandles[port], &options);
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
auto set = tcsetattr(portHandles[port], TCSANOW, &options);
|
||||
if (set != 0) {
|
||||
*status = HAL_SERIAL_PORT_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialWriteMode(HAL_SerialPort port, int32_t mode,
|
||||
int32_t* status) {
|
||||
// No op
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialFlowControl(HAL_SerialPort port, int32_t flow,
|
||||
int32_t* status) {
|
||||
// No op
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialTimeout(HAL_SerialPort port, double timeout,
|
||||
int32_t* status) {
|
||||
// Convert to millis
|
||||
int t = timeout / 1000;
|
||||
portTimeouts[port] = std::chrono::milliseconds(t);
|
||||
}
|
||||
|
||||
void HAL_EnableOSSerialTermination(HAL_SerialPort port, char terminator,
|
||||
int32_t* status) {
|
||||
// \n is hardcoded for now. Will fix later
|
||||
// Seems like a VISA only setting, need to check
|
||||
}
|
||||
|
||||
void HAL_DisableOSSerialTermination(HAL_SerialPort port, int32_t* status) {
|
||||
// Seems like a VISA only setting, need to check
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialReadBufferSize(HAL_SerialPort port, int32_t size,
|
||||
int32_t* status) {
|
||||
// No op
|
||||
}
|
||||
|
||||
void HAL_SetOSSerialWriteBufferSize(HAL_SerialPort port, int32_t size,
|
||||
int32_t* status) {
|
||||
// No op
|
||||
}
|
||||
|
||||
int32_t HAL_GetOSSerialBytesReceived(HAL_SerialPort port, int32_t* status) {
|
||||
int bytes = 0;
|
||||
ioctl(portHandles[port], FIONREAD, &bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int32_t HAL_ReadOSSerial(HAL_SerialPort port, char* buffer, int32_t count,
|
||||
int32_t* status) {
|
||||
auto endTime = std::chrono::steady_clock::now() + portTimeouts[port];
|
||||
|
||||
int bytesRead = 0;
|
||||
|
||||
unsigned char buf[256];
|
||||
|
||||
do {
|
||||
int rx = read(portHandles[port], buf, count - bytesRead);
|
||||
std::memcpy(&buffer[bytesRead], buf, rx);
|
||||
bytesRead += rx;
|
||||
if (bytesRead >= count) break;
|
||||
llvm::StringRef tmp(buffer, bytesRead);
|
||||
auto loc = tmp.find('\n');
|
||||
if (loc != llvm::StringRef::npos) {
|
||||
bytesRead = loc;
|
||||
break;
|
||||
}
|
||||
} while (std::chrono::steady_clock::now() < endTime);
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
int32_t HAL_WriteOSSerial(HAL_SerialPort port, const char* buffer,
|
||||
int32_t count, int32_t* status) {
|
||||
return write(portHandles[port], buffer, count);
|
||||
}
|
||||
void HAL_FlushOSSerial(HAL_SerialPort port, int32_t* status) {
|
||||
tcdrain(portHandles[port]);
|
||||
}
|
||||
void HAL_ClearOSSerial(HAL_SerialPort port, int32_t* status) {
|
||||
tcflush(portHandles[port], TCIOFLUSH);
|
||||
}
|
||||
void HAL_CloseOSSerial(HAL_SerialPort port, int32_t* status) {
|
||||
close(portHandles[port]);
|
||||
}
|
||||
}
|
||||
27
hal/src/main/native/athena/PCMInternal.cpp
Normal file
27
hal/src/main/native/athena/PCMInternal.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "PCMInternal.h"
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Solenoid.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
namespace hal {
|
||||
std::unique_ptr<PCM> PCM_modules[kNumPCMModules];
|
||||
|
||||
void initializePCM(int32_t module, int32_t* status) {
|
||||
if (!HAL_CheckSolenoidModule(module)) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
return;
|
||||
}
|
||||
if (!PCM_modules[module]) {
|
||||
PCM_modules[module] = std::make_unique<PCM>(module);
|
||||
}
|
||||
}
|
||||
} // namespace hal
|
||||
36
hal/src/main/native/athena/PCMInternal.h
Normal file
36
hal/src/main/native/athena/PCMInternal.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Ports.h"
|
||||
#include "HAL/Solenoid.h"
|
||||
#include "PortsInternal.h"
|
||||
#include "ctre/PCM.h"
|
||||
|
||||
namespace hal {
|
||||
extern std::unique_ptr<PCM> PCM_modules[kNumPCMModules];
|
||||
|
||||
static inline bool checkPCMInit(int32_t module, int32_t* status) {
|
||||
if (!HAL_CheckSolenoidModule(module)) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if (!PCM_modules[module]) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void initializePCM(int32_t module, int32_t* status);
|
||||
} // namespace hal
|
||||
127
hal/src/main/native/athena/PDP.cpp
Normal file
127
hal/src/main/native/athena/PDP.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/PDP.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Ports.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "PortsInternal.h"
|
||||
#include "ctre/PDP.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static std::unique_ptr<PDP> pdp[kNumPDPModules];
|
||||
|
||||
static inline bool checkPDPInit(int32_t module, int32_t* status) {
|
||||
if (!HAL_CheckPDPModule(module)) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if (!pdp[module]) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void HAL_InitializePDP(int32_t module, int32_t* status) {
|
||||
if (!HAL_CheckPDPModule(module)) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
return;
|
||||
}
|
||||
if (!pdp[module]) {
|
||||
pdp[module] = std::make_unique<PDP>(module);
|
||||
}
|
||||
}
|
||||
|
||||
HAL_Bool HAL_CheckPDPModule(int32_t module) {
|
||||
return module < kNumPDPModules && module >= 0;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_CheckPDPChannel(int32_t channel) {
|
||||
return channel < kNumPDPChannels && channel >= 0;
|
||||
}
|
||||
|
||||
double HAL_GetPDPTemperature(int32_t module, int32_t* status) {
|
||||
if (!checkPDPInit(module, status)) return 0;
|
||||
|
||||
double temperature;
|
||||
|
||||
*status = pdp[module]->GetTemperature(temperature);
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
double HAL_GetPDPVoltage(int32_t module, int32_t* status) {
|
||||
if (!checkPDPInit(module, status)) return 0;
|
||||
|
||||
double voltage;
|
||||
|
||||
*status = pdp[module]->GetVoltage(voltage);
|
||||
|
||||
return voltage;
|
||||
}
|
||||
|
||||
double HAL_GetPDPChannelCurrent(int32_t module, int32_t channel,
|
||||
int32_t* status) {
|
||||
if (!checkPDPInit(module, status)) return 0;
|
||||
|
||||
double current;
|
||||
|
||||
*status = pdp[module]->GetChannelCurrent(channel, current);
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
double HAL_GetPDPTotalCurrent(int32_t module, int32_t* status) {
|
||||
if (!checkPDPInit(module, status)) return 0;
|
||||
|
||||
double current;
|
||||
|
||||
*status = pdp[module]->GetTotalCurrent(current);
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
double HAL_GetPDPTotalPower(int32_t module, int32_t* status) {
|
||||
if (!checkPDPInit(module, status)) return 0;
|
||||
|
||||
double power;
|
||||
|
||||
*status = pdp[module]->GetTotalPower(power);
|
||||
|
||||
return power;
|
||||
}
|
||||
|
||||
double HAL_GetPDPTotalEnergy(int32_t module, int32_t* status) {
|
||||
if (!checkPDPInit(module, status)) return 0;
|
||||
|
||||
double energy;
|
||||
|
||||
*status = pdp[module]->GetTotalEnergy(energy);
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
void HAL_ResetPDPTotalEnergy(int32_t module, int32_t* status) {
|
||||
if (!checkPDPInit(module, status)) return;
|
||||
|
||||
*status = pdp[module]->ResetEnergy();
|
||||
}
|
||||
|
||||
void HAL_ClearPDPStickyFaults(int32_t module, int32_t* status) {
|
||||
if (!checkPDPInit(module, status)) return;
|
||||
|
||||
*status = pdp[module]->ClearStickyFaults();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
452
hal/src/main/native/athena/PWM.cpp
Normal file
452
hal/src/main/native/athena/PWM.cpp
Normal file
@@ -0,0 +1,452 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/PWM.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "ConstantsInternal.h"
|
||||
#include "DigitalInternal.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static inline int32_t GetMaxPositivePwm(DigitalPort* port) {
|
||||
return port->maxPwm;
|
||||
}
|
||||
static inline int32_t GetMinPositivePwm(DigitalPort* port) {
|
||||
return port->eliminateDeadband ? port->deadbandMaxPwm : port->centerPwm + 1;
|
||||
}
|
||||
static inline int32_t GetCenterPwm(DigitalPort* port) {
|
||||
return port->centerPwm;
|
||||
}
|
||||
static inline int32_t GetMaxNegativePwm(DigitalPort* port) {
|
||||
return port->eliminateDeadband ? port->deadbandMinPwm : port->centerPwm - 1;
|
||||
}
|
||||
static inline int32_t GetMinNegativePwm(DigitalPort* port) {
|
||||
return port->minPwm;
|
||||
}
|
||||
static inline int32_t GetPositiveScaleFactor(DigitalPort* port) {
|
||||
return GetMaxPositivePwm(port) - GetMinPositivePwm(port);
|
||||
} ///< The scale for positive speeds.
|
||||
static inline int32_t GetNegativeScaleFactor(DigitalPort* port) {
|
||||
return GetMaxNegativePwm(port) - GetMinNegativePwm(port);
|
||||
} ///< The scale for negative speeds.
|
||||
static inline int32_t GetFullRangeScaleFactor(DigitalPort* port) {
|
||||
return GetMaxPositivePwm(port) - GetMinNegativePwm(port);
|
||||
} ///< The scale for positions.
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
|
||||
int32_t* status) {
|
||||
initializeDigital(status);
|
||||
|
||||
if (*status != 0) return HAL_kInvalidHandle;
|
||||
|
||||
int16_t channel = getPortHandleChannel(portHandle);
|
||||
if (channel == InvalidHandleIndex || channel >= kNumPWMChannels) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
uint8_t origChannel = static_cast<uint8_t>(channel);
|
||||
|
||||
if (origChannel < kNumPWMHeaders) {
|
||||
channel += kNumDigitalChannels; // remap Headers to end of allocations
|
||||
} else {
|
||||
channel = remapMXPPWMChannel(channel) + 10; // remap MXP to proper channel
|
||||
}
|
||||
|
||||
auto handle =
|
||||
digitalChannelHandles.Allocate(channel, HAL_HandleEnum::PWM, status);
|
||||
|
||||
if (*status != 0)
|
||||
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
||||
|
||||
auto port = digitalChannelHandles.Get(handle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) { // would only occur on thread issue.
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
port->channel = origChannel;
|
||||
|
||||
int32_t bitToSet = 1 << remapMXPPWMChannel(port->channel);
|
||||
uint16_t specialFunctions =
|
||||
digitalSystem->readEnableMXPSpecialFunction(status);
|
||||
digitalSystem->writeEnableMXPSpecialFunction(specialFunctions | bitToSet,
|
||||
status);
|
||||
|
||||
return handle;
|
||||
}
|
||||
void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (port->channel > tPWM::kNumHdrRegisters - 1) {
|
||||
int32_t bitToUnset = 1 << remapMXPPWMChannel(port->channel);
|
||||
uint16_t specialFunctions =
|
||||
digitalSystem->readEnableMXPSpecialFunction(status);
|
||||
digitalSystem->writeEnableMXPSpecialFunction(specialFunctions & ~bitToUnset,
|
||||
status);
|
||||
}
|
||||
|
||||
digitalChannelHandles.Free(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_CheckPWMChannel(int32_t channel) {
|
||||
return channel < kNumPWMChannels && channel >= 0;
|
||||
}
|
||||
|
||||
void HAL_SetPWMConfig(HAL_DigitalHandle pwmPortHandle, double max,
|
||||
double deadbandMax, double center, double deadbandMin,
|
||||
double min, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate the loop time in milliseconds
|
||||
double loopTime =
|
||||
HAL_GetLoopTiming(status) / (kSystemClockTicksPerMicrosecond * 1e3);
|
||||
if (*status != 0) return;
|
||||
|
||||
int32_t maxPwm = static_cast<int32_t>((max - kDefaultPwmCenter) / loopTime +
|
||||
kDefaultPwmStepsDown - 1);
|
||||
int32_t deadbandMaxPwm = static_cast<int32_t>(
|
||||
(deadbandMax - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
|
||||
int32_t centerPwm = static_cast<int32_t>(
|
||||
(center - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
|
||||
int32_t deadbandMinPwm = static_cast<int32_t>(
|
||||
(deadbandMin - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
|
||||
int32_t minPwm = static_cast<int32_t>((min - kDefaultPwmCenter) / loopTime +
|
||||
kDefaultPwmStepsDown - 1);
|
||||
|
||||
port->maxPwm = maxPwm;
|
||||
port->deadbandMaxPwm = deadbandMaxPwm;
|
||||
port->deadbandMinPwm = deadbandMinPwm;
|
||||
port->centerPwm = centerPwm;
|
||||
port->minPwm = minPwm;
|
||||
port->configSet = true;
|
||||
}
|
||||
|
||||
void HAL_SetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t maxPwm,
|
||||
int32_t deadbandMaxPwm, int32_t centerPwm,
|
||||
int32_t deadbandMinPwm, int32_t minPwm,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
port->maxPwm = maxPwm;
|
||||
port->deadbandMaxPwm = deadbandMaxPwm;
|
||||
port->deadbandMinPwm = deadbandMinPwm;
|
||||
port->centerPwm = centerPwm;
|
||||
port->minPwm = minPwm;
|
||||
}
|
||||
|
||||
void HAL_GetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t* maxPwm,
|
||||
int32_t* deadbandMaxPwm, int32_t* centerPwm,
|
||||
int32_t* deadbandMinPwm, int32_t* minPwm,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
*maxPwm = port->maxPwm;
|
||||
*deadbandMaxPwm = port->deadbandMaxPwm;
|
||||
*deadbandMinPwm = port->deadbandMinPwm;
|
||||
*centerPwm = port->centerPwm;
|
||||
*minPwm = port->minPwm;
|
||||
}
|
||||
|
||||
void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
|
||||
HAL_Bool eliminateDeadband, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
port->eliminateDeadband = eliminateDeadband;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
return port->eliminateDeadband;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a PWM channel to the desired value. The values range from 0 to 255 and
|
||||
* the period is controlled
|
||||
* by the PWM Period and MinHigh registers.
|
||||
*
|
||||
* @param channel The PWM channel to set.
|
||||
* @param value The PWM value to set.
|
||||
*/
|
||||
void HAL_SetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t value,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (port->channel < tPWM::kNumHdrRegisters) {
|
||||
pwmSystem->writeHdr(port->channel, value, status);
|
||||
} else {
|
||||
pwmSystem->writeMXP(port->channel - tPWM::kNumHdrRegisters, value, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a PWM channel to the desired scaled value. The values range from -1 to 1
|
||||
* and
|
||||
* the period is controlled
|
||||
* by the PWM Period and MinHigh registers.
|
||||
*
|
||||
* @param channel The PWM channel to set.
|
||||
* @param value The scaled PWM value to set.
|
||||
*/
|
||||
void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (!port->configSet) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return;
|
||||
}
|
||||
|
||||
DigitalPort* dPort = port.get();
|
||||
|
||||
if (speed < -1.0) {
|
||||
speed = -1.0;
|
||||
} else if (speed > 1.0) {
|
||||
speed = 1.0;
|
||||
} else if (!std::isfinite(speed)) {
|
||||
speed = 0.0;
|
||||
}
|
||||
|
||||
// calculate the desired output pwm value by scaling the speed appropriately
|
||||
int32_t rawValue;
|
||||
if (speed == 0.0) {
|
||||
rawValue = GetCenterPwm(dPort);
|
||||
} else if (speed > 0.0) {
|
||||
rawValue = static_cast<int32_t>(
|
||||
speed * static_cast<double>(GetPositiveScaleFactor(dPort)) +
|
||||
static_cast<double>(GetMinPositivePwm(dPort)) + 0.5);
|
||||
} else {
|
||||
rawValue = static_cast<int32_t>(
|
||||
speed * static_cast<double>(GetNegativeScaleFactor(dPort)) +
|
||||
static_cast<double>(GetMaxNegativePwm(dPort)) + 0.5);
|
||||
}
|
||||
|
||||
if (!((rawValue >= GetMinNegativePwm(dPort)) &&
|
||||
(rawValue <= GetMaxPositivePwm(dPort))) ||
|
||||
rawValue == kPwmDisabled) {
|
||||
*status = HAL_PWM_SCALE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_SetPWMRaw(pwmPortHandle, rawValue, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a PWM channel to the desired position value. The values range from 0 to 1
|
||||
* and
|
||||
* the period is controlled
|
||||
* by the PWM Period and MinHigh registers.
|
||||
*
|
||||
* @param channel The PWM channel to set.
|
||||
* @param value The scaled PWM value to set.
|
||||
*/
|
||||
void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double pos,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (!port->configSet) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return;
|
||||
}
|
||||
DigitalPort* dPort = port.get();
|
||||
|
||||
if (pos < 0.0) {
|
||||
pos = 0.0;
|
||||
} else if (pos > 1.0) {
|
||||
pos = 1.0;
|
||||
}
|
||||
|
||||
// note, need to perform the multiplication below as floating point before
|
||||
// converting to int
|
||||
int32_t rawValue = static_cast<int32_t>(
|
||||
(pos * static_cast<double>(GetFullRangeScaleFactor(dPort))) +
|
||||
GetMinNegativePwm(dPort));
|
||||
|
||||
if (rawValue == kPwmDisabled) {
|
||||
*status = HAL_PWM_SCALE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_SetPWMRaw(pwmPortHandle, rawValue, status);
|
||||
}
|
||||
|
||||
void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
HAL_SetPWMRaw(pwmPortHandle, kPwmDisabled, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from a PWM channel. The values range from 0 to 255.
|
||||
*
|
||||
* @param channel The PWM channel to read from.
|
||||
* @return The raw PWM value.
|
||||
*/
|
||||
int32_t HAL_GetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (port->channel < tPWM::kNumHdrRegisters) {
|
||||
return pwmSystem->readHdr(port->channel, status);
|
||||
} else {
|
||||
return pwmSystem->readMXP(port->channel - tPWM::kNumHdrRegisters, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a scaled value from a PWM channel. The values range from -1 to 1.
|
||||
*
|
||||
* @param channel The PWM channel to read from.
|
||||
* @return The scaled PWM value.
|
||||
*/
|
||||
double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (!port->configSet) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t value = HAL_GetPWMRaw(pwmPortHandle, status);
|
||||
if (*status != 0) return 0;
|
||||
DigitalPort* dPort = port.get();
|
||||
|
||||
if (value == kPwmDisabled) {
|
||||
return 0.0;
|
||||
} else if (value > GetMaxPositivePwm(dPort)) {
|
||||
return 1.0;
|
||||
} else if (value < GetMinNegativePwm(dPort)) {
|
||||
return -1.0;
|
||||
} else if (value > GetMinPositivePwm(dPort)) {
|
||||
return static_cast<double>(value - GetMinPositivePwm(dPort)) /
|
||||
static_cast<double>(GetPositiveScaleFactor(dPort));
|
||||
} else if (value < GetMaxNegativePwm(dPort)) {
|
||||
return static_cast<double>(value - GetMaxNegativePwm(dPort)) /
|
||||
static_cast<double>(GetNegativeScaleFactor(dPort));
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a position value from a PWM channel. The values range from 0 to 1.
|
||||
*
|
||||
* @param channel The PWM channel to read from.
|
||||
* @return The scaled PWM value.
|
||||
*/
|
||||
double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (!port->configSet) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t value = HAL_GetPWMRaw(pwmPortHandle, status);
|
||||
if (*status != 0) return 0;
|
||||
DigitalPort* dPort = port.get();
|
||||
|
||||
if (value < GetMinNegativePwm(dPort)) {
|
||||
return 0.0;
|
||||
} else if (value > GetMaxPositivePwm(dPort)) {
|
||||
return 1.0;
|
||||
} else {
|
||||
return static_cast<double>(value - GetMinNegativePwm(dPort)) /
|
||||
static_cast<double>(GetFullRangeScaleFactor(dPort));
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
pwmSystem->writeZeroLatch(port->channel, true, status);
|
||||
pwmSystem->writeZeroLatch(port->channel, false, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set how how often the PWM signal is squelched, thus scaling the period.
|
||||
*
|
||||
* @param channel The PWM channel to configure.
|
||||
* @param squelchMask The 2-bit mask of outputs to squelch.
|
||||
*/
|
||||
void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles.Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (port->channel < tPWM::kNumPeriodScaleHdrElements) {
|
||||
pwmSystem->writePeriodScaleHdr(port->channel, squelchMask, status);
|
||||
} else {
|
||||
pwmSystem->writePeriodScaleMXP(
|
||||
port->channel - tPWM::kNumPeriodScaleHdrElements, squelchMask, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the loop timing of the PWM system
|
||||
*
|
||||
* @return The loop time
|
||||
*/
|
||||
int32_t HAL_GetLoopTiming(int32_t* status) {
|
||||
initializeDigital(status);
|
||||
if (*status != 0) return 0;
|
||||
return pwmSystem->readLoopTiming(status);
|
||||
}
|
||||
}
|
||||
33
hal/src/main/native/athena/Ports.cpp
Normal file
33
hal/src/main/native/athena/Ports.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Ports.h"
|
||||
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
extern "C" {
|
||||
int32_t HAL_GetNumAccumulators(void) { return kNumAccumulators; }
|
||||
int32_t HAL_GetNumAnalogTriggers(void) { return kNumAnalogTriggers; }
|
||||
int32_t HAL_GetNumAnalogInputs(void) { return kNumAnalogInputs; }
|
||||
int32_t HAL_GetNumAnalogOutputs(void) { return kNumAnalogOutputs; }
|
||||
int32_t HAL_GetNumCounters(void) { return kNumCounters; }
|
||||
int32_t HAL_GetNumDigitalHeaders(void) { return kNumDigitalHeaders; }
|
||||
int32_t HAL_GetNumPWMHeaders(void) { return kNumPWMHeaders; }
|
||||
int32_t HAL_GetNumDigitalChannels(void) { return kNumDigitalChannels; }
|
||||
int32_t HAL_GetNumPWMChannels(void) { return kNumPWMChannels; }
|
||||
int32_t HAL_GetNumDigitalPWMOutputs(void) { return kNumDigitalPWMOutputs; }
|
||||
int32_t HAL_GetNumEncoders(void) { return kNumEncoders; }
|
||||
int32_t HAL_GetNumInterrupts(void) { return kNumInterrupts; }
|
||||
int32_t HAL_GetNumRelayChannels(void) { return kNumRelayChannels; }
|
||||
int32_t HAL_GetNumRelayHeaders(void) { return kNumRelayHeaders; }
|
||||
int32_t HAL_GetNumPCMModules(void) { return kNumPCMModules; }
|
||||
int32_t HAL_GetNumSolenoidChannels(void) { return kNumSolenoidChannels; }
|
||||
int32_t HAL_GetNumPDPModules(void) { return kNumPDPModules; }
|
||||
int32_t HAL_GetNumPDPChannels(void) { return kNumPDPChannels; }
|
||||
}
|
||||
37
hal/src/main/native/athena/PortsInternal.h
Normal file
37
hal/src/main/native/athena/PortsInternal.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/ChipObject.h"
|
||||
|
||||
namespace hal {
|
||||
constexpr int32_t kNumAccumulators = tAccumulator::kNumSystems;
|
||||
constexpr int32_t kNumAnalogTriggers = tAnalogTrigger::kNumSystems;
|
||||
constexpr int32_t kNumAnalogInputs = 8;
|
||||
constexpr int32_t kNumAnalogOutputs = tAO::kNumMXPRegisters;
|
||||
constexpr int32_t kNumCounters = tCounter::kNumSystems;
|
||||
constexpr int32_t kNumDigitalHeaders = 10;
|
||||
constexpr int32_t kNumDigitalMXPChannels = 16;
|
||||
constexpr int32_t kNumDigitalSPIPortChannels = 5;
|
||||
constexpr int32_t kNumPWMHeaders = tPWM::kNumHdrRegisters;
|
||||
constexpr int32_t kNumDigitalChannels =
|
||||
kNumDigitalHeaders + kNumDigitalMXPChannels + kNumDigitalSPIPortChannels;
|
||||
constexpr int32_t kNumPWMChannels = tPWM::kNumMXPRegisters + kNumPWMHeaders;
|
||||
constexpr int32_t kNumDigitalPWMOutputs =
|
||||
tDIO::kNumPWMDutyCycleAElements + tDIO::kNumPWMDutyCycleBElements;
|
||||
constexpr int32_t kNumEncoders = tEncoder::kNumSystems;
|
||||
constexpr int32_t kNumInterrupts = tInterrupt::kNumSystems;
|
||||
constexpr int32_t kNumRelayChannels = 8;
|
||||
constexpr int32_t kNumRelayHeaders = kNumRelayChannels / 2;
|
||||
constexpr int32_t kNumPCMModules = 63;
|
||||
constexpr int32_t kNumSolenoidChannels = 8;
|
||||
constexpr int32_t kNumPDPModules = 63;
|
||||
constexpr int32_t kNumPDPChannels = 16;
|
||||
} // namespace hal
|
||||
145
hal/src/main/native/athena/Power.cpp
Normal file
145
hal/src/main/native/athena/Power.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Power.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/ChipObject.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace hal {
|
||||
|
||||
static std::unique_ptr<tPower> power;
|
||||
|
||||
static void initializePower(int32_t* status) {
|
||||
if (power == nullptr) {
|
||||
power.reset(tPower::create(status));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* Get the roboRIO input voltage
|
||||
*/
|
||||
double HAL_GetVinVoltage(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readVinVoltage(status) / 4.096 * 0.025733 - 0.029;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the roboRIO input current
|
||||
*/
|
||||
double HAL_GetVinCurrent(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readVinCurrent(status) / 4.096 * 0.017042 - 0.071;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 6V rail voltage
|
||||
*/
|
||||
double HAL_GetUserVoltage6V(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readUserVoltage6V(status) / 4.096 * 0.007019 - 0.014;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 6V rail current
|
||||
*/
|
||||
double HAL_GetUserCurrent6V(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readUserCurrent6V(status) / 4.096 * 0.005566 - 0.009;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active state of the 6V rail
|
||||
*/
|
||||
HAL_Bool HAL_GetUserActive6V(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readStatus_User6V(status) == 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fault count for the 6V rail
|
||||
*/
|
||||
int32_t HAL_GetUserCurrentFaults6V(int32_t* status) {
|
||||
initializePower(status);
|
||||
return static_cast<int32_t>(
|
||||
power->readFaultCounts_OverCurrentFaultCount6V(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 5V rail voltage
|
||||
*/
|
||||
double HAL_GetUserVoltage5V(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readUserVoltage5V(status) / 4.096 * 0.005962 - 0.013;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 5V rail current
|
||||
*/
|
||||
double HAL_GetUserCurrent5V(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readUserCurrent5V(status) / 4.096 * 0.001996 - 0.002;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active state of the 5V rail
|
||||
*/
|
||||
HAL_Bool HAL_GetUserActive5V(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readStatus_User5V(status) == 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fault count for the 5V rail
|
||||
*/
|
||||
int32_t HAL_GetUserCurrentFaults5V(int32_t* status) {
|
||||
initializePower(status);
|
||||
return static_cast<int32_t>(
|
||||
power->readFaultCounts_OverCurrentFaultCount5V(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 3.3V rail voltage
|
||||
*/
|
||||
double HAL_GetUserVoltage3V3(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readUserVoltage3V3(status) / 4.096 * 0.004902 - 0.01;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 3.3V rail current
|
||||
*/
|
||||
double HAL_GetUserCurrent3V3(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readUserCurrent3V3(status) / 4.096 * 0.002486 - 0.003;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active state of the 3.3V rail
|
||||
*/
|
||||
HAL_Bool HAL_GetUserActive3V3(int32_t* status) {
|
||||
initializePower(status);
|
||||
return power->readStatus_User3V3(status) == 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fault count for the 3.3V rail
|
||||
*/
|
||||
int32_t HAL_GetUserCurrentFaults3V3(int32_t* status) {
|
||||
initializePower(status);
|
||||
return static_cast<int32_t>(
|
||||
power->readFaultCounts_OverCurrentFaultCount3V3(status));
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
134
hal/src/main/native/athena/Relay.cpp
Normal file
134
hal/src/main/native/athena/Relay.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Relay.h"
|
||||
|
||||
#include "DigitalInternal.h"
|
||||
#include "HAL/handles/IndexedHandleResource.h"
|
||||
#include "PortsInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace {
|
||||
struct Relay {
|
||||
uint8_t channel;
|
||||
bool fwd;
|
||||
};
|
||||
}
|
||||
|
||||
static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
|
||||
HAL_HandleEnum::Relay>
|
||||
relayHandles;
|
||||
|
||||
// Create a mutex to protect changes to the relay values
|
||||
static priority_recursive_mutex digitalRelayMutex;
|
||||
|
||||
extern "C" {
|
||||
HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
|
||||
int32_t* status) {
|
||||
initializeDigital(status);
|
||||
|
||||
if (*status != 0) return HAL_kInvalidHandle;
|
||||
|
||||
int16_t channel = getPortHandleChannel(portHandle);
|
||||
if (channel == InvalidHandleIndex) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
if (!fwd) channel += kNumRelayHeaders; // add 4 to reverse channels
|
||||
|
||||
auto handle = relayHandles.Allocate(channel, status);
|
||||
|
||||
if (*status != 0)
|
||||
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
||||
|
||||
auto port = relayHandles.Get(handle);
|
||||
if (port == nullptr) { // would only occur on thread issue.
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
if (!fwd) {
|
||||
// Subtract number of headers to put channel in range
|
||||
channel -= kNumRelayHeaders;
|
||||
|
||||
port->fwd = false; // set to reverse
|
||||
} else {
|
||||
port->fwd = true; // set to forward
|
||||
}
|
||||
|
||||
port->channel = static_cast<uint8_t>(channel);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle) {
|
||||
// no status, so no need to check for a proper free.
|
||||
relayHandles.Free(relayPortHandle);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_CheckRelayChannel(int32_t channel) {
|
||||
// roboRIO only has 4 headers, and the FPGA has
|
||||
// seperate functions for forward and reverse,
|
||||
// instead of seperate channel IDs
|
||||
return channel < kNumRelayHeaders && channel >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of a relay.
|
||||
* Set the state of a relay output.
|
||||
*/
|
||||
void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
|
||||
int32_t* status) {
|
||||
auto port = relayHandles.Get(relayPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalRelayMutex);
|
||||
uint8_t relays = 0;
|
||||
if (port->fwd) {
|
||||
relays = relaySystem->readValue_Forward(status);
|
||||
} else {
|
||||
relays = relaySystem->readValue_Reverse(status);
|
||||
}
|
||||
|
||||
if (*status != 0) return; // bad status read
|
||||
|
||||
if (on) {
|
||||
relays |= 1 << port->channel;
|
||||
} else {
|
||||
relays &= ~(1 << port->channel);
|
||||
}
|
||||
|
||||
if (port->fwd) {
|
||||
relaySystem->writeValue_Forward(relays, status);
|
||||
} else {
|
||||
relaySystem->writeValue_Reverse(relays, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current state of the relay channel
|
||||
*/
|
||||
HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status) {
|
||||
auto port = relayHandles.Get(relayPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t relays = 0;
|
||||
if (port->fwd) {
|
||||
relays = relaySystem->readValue_Forward(status);
|
||||
} else {
|
||||
relays = relaySystem->readValue_Reverse(status);
|
||||
}
|
||||
|
||||
return (relays & (1 << port->channel)) != 0;
|
||||
}
|
||||
}
|
||||
673
hal/src/main/native/athena/SPI.cpp
Normal file
673
hal/src/main/native/athena/SPI.cpp
Normal file
@@ -0,0 +1,673 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/SPI.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "DigitalInternal.h"
|
||||
#include "HAL/DIO.h"
|
||||
#include "HAL/HAL.h"
|
||||
#include "HAL/Notifier.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "llvm/raw_ostream.h"
|
||||
#include "spilib/spi-lib.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static int32_t m_spiCS0Handle = 0;
|
||||
static int32_t m_spiCS1Handle = 0;
|
||||
static int32_t m_spiCS2Handle = 0;
|
||||
static int32_t m_spiCS3Handle = 0;
|
||||
static int32_t m_spiMXPHandle = 0;
|
||||
static priority_recursive_mutex spiOnboardMutex;
|
||||
static priority_recursive_mutex spiMXPMutex;
|
||||
|
||||
// MXP SPI does not count towards this
|
||||
std::atomic<int32_t> spiPortCount{0};
|
||||
|
||||
static HAL_DigitalHandle digitalHandles[9]{HAL_kInvalidHandle};
|
||||
|
||||
/**
|
||||
* Get the semaphore for a SPI port
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
* @return The semaphore for the SPI port.
|
||||
*/
|
||||
static priority_recursive_mutex& spiGetMutex(HAL_SPIPort port) {
|
||||
if (port < 4)
|
||||
return spiOnboardMutex;
|
||||
else
|
||||
return spiMXPMutex;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct SPIAccumulator {
|
||||
std::atomic<HAL_NotifierHandle> notifier{0};
|
||||
uint64_t triggerTime;
|
||||
int32_t period;
|
||||
|
||||
int64_t value = 0;
|
||||
uint32_t count = 0;
|
||||
int32_t lastValue = 0;
|
||||
|
||||
int32_t center = 0;
|
||||
int32_t deadband = 0;
|
||||
|
||||
uint8_t cmd[4]; // command to send (up to 4 bytes)
|
||||
int32_t validMask;
|
||||
int32_t validValue;
|
||||
int32_t dataMax; // one more than max data value
|
||||
int32_t dataMsbMask; // data field MSB mask (for signed)
|
||||
uint8_t dataShift; // data field shift right amount, in bits
|
||||
uint8_t xferSize; // SPI transfer size, in bytes (up to 4)
|
||||
HAL_SPIPort port;
|
||||
bool isSigned; // is data field signed?
|
||||
bool bigEndian; // is response big endian?
|
||||
};
|
||||
std::unique_ptr<SPIAccumulator> spiAccumulators[5];
|
||||
|
||||
static void CommonSPIPortInit(int32_t* status) {
|
||||
// All false cases will set
|
||||
if (spiPortCount.fetch_add(1) == 0) {
|
||||
// Have not been initialized yet
|
||||
initializeDigital(status);
|
||||
if (*status != 0) return;
|
||||
// MISO
|
||||
if ((digitalHandles[3] = HAL_InitializeDIOPort(createPortHandleForSPI(29),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
std::printf("Failed to allocate DIO 29 (MISO)\n");
|
||||
return;
|
||||
}
|
||||
// MOSI
|
||||
if ((digitalHandles[4] = HAL_InitializeDIOPort(createPortHandleForSPI(30),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
std::printf("Failed to allocate DIO 30 (MOSI)\n");
|
||||
HAL_FreeDIOPort(digitalHandles[3]); // free the first port allocated
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CommonSPIPortFree() {
|
||||
if (spiPortCount.fetch_sub(1) == 1) {
|
||||
// Clean up SPI Handles
|
||||
HAL_FreeDIOPort(digitalHandles[3]);
|
||||
HAL_FreeDIOPort(digitalHandles[4]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the spi port. Opens the port if necessary and saves the handle.
|
||||
* If opening the MXP port, also sets up the channel functions appropriately
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS3, 4 for MXP
|
||||
*/
|
||||
void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
|
||||
if (HAL_GetSPIHandle(port) != 0) return;
|
||||
switch (port) {
|
||||
case 0:
|
||||
CommonSPIPortInit(status);
|
||||
if (*status != 0) return;
|
||||
// CS0 is not a DIO port, so nothing to allocate
|
||||
HAL_SetSPIHandle(HAL_SPI_kOnboardCS0, spilib_open("/dev/spidev0.0"));
|
||||
break;
|
||||
case 1:
|
||||
CommonSPIPortInit(status);
|
||||
if (*status != 0) return;
|
||||
// CS1, Allocate
|
||||
if ((digitalHandles[0] = HAL_InitializeDIOPort(createPortHandleForSPI(26),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
std::printf("Failed to allocate DIO 26 (CS1)\n");
|
||||
CommonSPIPortFree();
|
||||
return;
|
||||
}
|
||||
HAL_SetSPIHandle(HAL_SPI_kOnboardCS1, spilib_open("/dev/spidev0.1"));
|
||||
break;
|
||||
case 2:
|
||||
CommonSPIPortInit(status);
|
||||
if (*status != 0) return;
|
||||
// CS2, Allocate
|
||||
if ((digitalHandles[1] = HAL_InitializeDIOPort(createPortHandleForSPI(27),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
std::printf("Failed to allocate DIO 27 (CS2)\n");
|
||||
CommonSPIPortFree();
|
||||
return;
|
||||
}
|
||||
HAL_SetSPIHandle(HAL_SPI_kOnboardCS2, spilib_open("/dev/spidev0.2"));
|
||||
break;
|
||||
case 3:
|
||||
CommonSPIPortInit(status);
|
||||
if (*status != 0) return;
|
||||
// CS3, Allocate
|
||||
if ((digitalHandles[2] = HAL_InitializeDIOPort(createPortHandleForSPI(28),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
std::printf("Failed to allocate DIO 28 (CS3)\n");
|
||||
CommonSPIPortFree();
|
||||
return;
|
||||
}
|
||||
HAL_SetSPIHandle(HAL_SPI_kOnboardCS3, spilib_open("/dev/spidev0.3"));
|
||||
break;
|
||||
case 4:
|
||||
initializeDigital(status);
|
||||
if (*status != 0) return;
|
||||
if ((digitalHandles[5] = HAL_InitializeDIOPort(createPortHandleForSPI(14),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
llvm::outs() << "Failed to allocate DIO 14\n";
|
||||
return;
|
||||
}
|
||||
if ((digitalHandles[6] = HAL_InitializeDIOPort(createPortHandleForSPI(15),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
llvm::outs() << "Failed to allocate DIO 15\n";
|
||||
HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated
|
||||
return;
|
||||
}
|
||||
if ((digitalHandles[7] = HAL_InitializeDIOPort(createPortHandleForSPI(16),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
llvm::outs() << "Failed to allocate DIO 16\n";
|
||||
HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated
|
||||
HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated
|
||||
return;
|
||||
}
|
||||
if ((digitalHandles[8] = HAL_InitializeDIOPort(createPortHandleForSPI(17),
|
||||
false, status)) ==
|
||||
HAL_kInvalidHandle) {
|
||||
llvm::outs() << "Failed to allocate DIO 17\n";
|
||||
HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated
|
||||
HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated
|
||||
HAL_FreeDIOPort(digitalHandles[7]); // free the third port allocated
|
||||
return;
|
||||
}
|
||||
digitalSystem->writeEnableMXPSpecialFunction(
|
||||
digitalSystem->readEnableMXPSpecialFunction(status) | 0x00F0, status);
|
||||
HAL_SetSPIHandle(HAL_SPI_kMXP, spilib_open("/dev/spidev1.0"));
|
||||
break;
|
||||
default:
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic transaction.
|
||||
*
|
||||
* This is a lower-level interface to the spi hardware giving you more control
|
||||
* over each transaction.
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
* @param dataToSend Buffer of data to send as part of the transaction.
|
||||
* @param dataReceived Buffer to read data into.
|
||||
* @param size Number of bytes to transfer. [0..7]
|
||||
* @return Number of bytes transferred, -1 for error
|
||||
*/
|
||||
int32_t HAL_TransactionSPI(HAL_SPIPort port, uint8_t* dataToSend,
|
||||
uint8_t* dataReceived, int32_t size) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
return spilib_writeread(
|
||||
HAL_GetSPIHandle(port), reinterpret_cast<const char*>(dataToSend),
|
||||
reinterpret_cast<char*>(dataReceived), static_cast<int32_t>(size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a write transaction with the device.
|
||||
*
|
||||
* Write to a device and wait until the transaction is complete.
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
* @param datToSend The data to write to the register on the device.
|
||||
* @param sendSize The number of bytes to be written
|
||||
* @return The number of bytes written. -1 for an error
|
||||
*/
|
||||
int32_t HAL_WriteSPI(HAL_SPIPort port, uint8_t* dataToSend, int32_t sendSize) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
return spilib_write(HAL_GetSPIHandle(port),
|
||||
reinterpret_cast<const char*>(dataToSend),
|
||||
static_cast<int32_t>(sendSize));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a read from the device.
|
||||
*
|
||||
* This method does not write any data out to the device
|
||||
* Most spi devices will require a register address to be written before
|
||||
* they begin returning data
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
* @param buffer A pointer to the array of bytes to store the data read from the
|
||||
* device.
|
||||
* @param count The number of bytes to read in the transaction. [1..7]
|
||||
* @return Number of bytes read. -1 for error.
|
||||
*/
|
||||
int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
return spilib_read(HAL_GetSPIHandle(port), reinterpret_cast<char*>(buffer),
|
||||
static_cast<int32_t>(count));
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the SPI port
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
*/
|
||||
void HAL_CloseSPI(HAL_SPIPort port) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
if (spiAccumulators[port]) {
|
||||
int32_t status = 0;
|
||||
HAL_FreeSPIAccumulator(port, &status);
|
||||
}
|
||||
spilib_close(HAL_GetSPIHandle(port));
|
||||
HAL_SetSPIHandle(port, 0);
|
||||
if (port < 4) {
|
||||
CommonSPIPortFree();
|
||||
}
|
||||
switch (port) {
|
||||
// Case 0 does not need to do anything
|
||||
case 1:
|
||||
HAL_FreeDIOPort(digitalHandles[0]);
|
||||
break;
|
||||
case 2:
|
||||
HAL_FreeDIOPort(digitalHandles[1]);
|
||||
break;
|
||||
case 3:
|
||||
HAL_FreeDIOPort(digitalHandles[2]);
|
||||
break;
|
||||
case 4:
|
||||
HAL_FreeDIOPort(digitalHandles[5]);
|
||||
HAL_FreeDIOPort(digitalHandles[6]);
|
||||
HAL_FreeDIOPort(digitalHandles[7]);
|
||||
HAL_FreeDIOPort(digitalHandles[8]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock speed for the SPI bus.
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
* @param speed The speed in Hz (0-1MHz)
|
||||
*/
|
||||
void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
spilib_setspeed(HAL_GetSPIHandle(port), speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SPI options
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
* @param msbFirst True to write the MSB first, False for LSB first
|
||||
* @param sampleOnTrailing True to sample on the trailing edge, False to sample
|
||||
* on the leading edge
|
||||
* @param clkIdleHigh True to set the clock to active low, False to set the
|
||||
* clock active high
|
||||
*/
|
||||
void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst,
|
||||
HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
spilib_setopts(HAL_GetSPIHandle(port), msbFirst, sampleOnTrailing,
|
||||
clkIdleHigh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CS Active high for a SPI port
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
*/
|
||||
void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
if (port < 4) {
|
||||
spiSystem->writeChipSelectActiveHigh_Hdr(
|
||||
spiSystem->readChipSelectActiveHigh_Hdr(status) | (1 << port), status);
|
||||
} else {
|
||||
spiSystem->writeChipSelectActiveHigh_MXP(1, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CS Active low for a SPI port
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
*/
|
||||
void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
if (port < 4) {
|
||||
spiSystem->writeChipSelectActiveHigh_Hdr(
|
||||
spiSystem->readChipSelectActiveHigh_Hdr(status) & ~(1 << port), status);
|
||||
} else {
|
||||
spiSystem->writeChipSelectActiveHigh_MXP(0, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored handle for a SPI port
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
|
||||
* @return The stored handle for the SPI port. 0 represents no stored handle.
|
||||
*/
|
||||
int32_t HAL_GetSPIHandle(HAL_SPIPort port) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
switch (port) {
|
||||
case 0:
|
||||
return m_spiCS0Handle;
|
||||
case 1:
|
||||
return m_spiCS1Handle;
|
||||
case 2:
|
||||
return m_spiCS2Handle;
|
||||
case 3:
|
||||
return m_spiCS3Handle;
|
||||
case 4:
|
||||
return m_spiMXPHandle;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the stored handle for a SPI port
|
||||
*
|
||||
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
|
||||
* MXP.
|
||||
* @param handle The value of the handle for the port.
|
||||
*/
|
||||
void HAL_SetSPIHandle(HAL_SPIPort port, int32_t handle) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
switch (port) {
|
||||
case 0:
|
||||
m_spiCS0Handle = handle;
|
||||
break;
|
||||
case 1:
|
||||
m_spiCS1Handle = handle;
|
||||
break;
|
||||
case 2:
|
||||
m_spiCS2Handle = handle;
|
||||
break;
|
||||
case 3:
|
||||
m_spiCS3Handle = handle;
|
||||
break;
|
||||
case 4:
|
||||
m_spiMXPHandle = handle;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void spiAccumulatorProcess(uint64_t currentTime,
|
||||
HAL_NotifierHandle handle) {
|
||||
int32_t status = 0;
|
||||
auto param = HAL_GetNotifierParam(handle, &status);
|
||||
if (param == nullptr) return;
|
||||
SPIAccumulator* accum = static_cast<SPIAccumulator*>(param);
|
||||
|
||||
// perform SPI transaction
|
||||
uint8_t resp_b[4];
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(accum->port));
|
||||
spilib_writeread(
|
||||
HAL_GetSPIHandle(accum->port), reinterpret_cast<const char*>(accum->cmd),
|
||||
reinterpret_cast<char*>(resp_b), static_cast<int32_t>(accum->xferSize));
|
||||
|
||||
// convert from bytes
|
||||
uint32_t resp = 0;
|
||||
if (accum->bigEndian) {
|
||||
for (int32_t i = 0; i < accum->xferSize; ++i) {
|
||||
resp <<= 8;
|
||||
resp |= resp_b[i] & 0xff;
|
||||
}
|
||||
} else {
|
||||
for (int32_t i = accum->xferSize - 1; i >= 0; --i) {
|
||||
resp <<= 8;
|
||||
resp |= resp_b[i] & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// process response
|
||||
if ((resp & accum->validMask) == static_cast<uint32_t>(accum->validValue)) {
|
||||
// valid sensor data; extract data field
|
||||
int32_t data = static_cast<int32_t>(resp >> accum->dataShift);
|
||||
data &= accum->dataMax - 1;
|
||||
// 2s complement conversion if signed MSB is set
|
||||
if (accum->isSigned && (data & accum->dataMsbMask) != 0)
|
||||
data -= accum->dataMax;
|
||||
// center offset
|
||||
data -= accum->center;
|
||||
// only accumulate if outside deadband
|
||||
if (data < -accum->deadband || data > accum->deadband) accum->value += data;
|
||||
++accum->count;
|
||||
accum->lastValue = data;
|
||||
} else {
|
||||
// no data from the sensor; just clear the last value
|
||||
accum->lastValue = 0;
|
||||
}
|
||||
|
||||
// reschedule timer
|
||||
accum->triggerTime += accum->period;
|
||||
// handle timer slip
|
||||
if (accum->triggerTime < currentTime)
|
||||
accum->triggerTime = currentTime + accum->period;
|
||||
status = 0;
|
||||
HAL_UpdateNotifierAlarm(accum->notifier, accum->triggerTime, &status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a SPI accumulator.
|
||||
*
|
||||
* @param port SPI port
|
||||
* @param period Time between reads, in us
|
||||
* @param cmd SPI command to send to request data
|
||||
* @param xferSize SPI transfer size, in bytes
|
||||
* @param validMask Mask to apply to received data for validity checking
|
||||
* @param valid_data After validMask is applied, required matching value for
|
||||
* validity checking
|
||||
* @param dataShift Bit shift to apply to received data to get actual data
|
||||
* value
|
||||
* @param dataSize Size (in bits) of data field
|
||||
* @param isSigned Is data field signed?
|
||||
* @param bigEndian Is device big endian?
|
||||
*/
|
||||
void HAL_InitSPIAccumulator(HAL_SPIPort port, int32_t period, int32_t cmd,
|
||||
int32_t xferSize, int32_t validMask,
|
||||
int32_t validValue, int32_t dataShift,
|
||||
int32_t dataSize, HAL_Bool isSigned,
|
||||
HAL_Bool bigEndian, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
if (port > 4) return;
|
||||
if (!spiAccumulators[port])
|
||||
spiAccumulators[port] = std::make_unique<SPIAccumulator>();
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (bigEndian) {
|
||||
for (int32_t i = xferSize - 1; i >= 0; --i) {
|
||||
accum->cmd[i] = cmd & 0xff;
|
||||
cmd >>= 8;
|
||||
}
|
||||
} else {
|
||||
accum->cmd[0] = cmd & 0xff;
|
||||
cmd >>= 8;
|
||||
accum->cmd[1] = cmd & 0xff;
|
||||
cmd >>= 8;
|
||||
accum->cmd[2] = cmd & 0xff;
|
||||
cmd >>= 8;
|
||||
accum->cmd[3] = cmd & 0xff;
|
||||
}
|
||||
accum->period = period;
|
||||
accum->xferSize = xferSize;
|
||||
accum->validMask = validMask;
|
||||
accum->validValue = validValue;
|
||||
accum->dataShift = dataShift;
|
||||
accum->dataMax = (1 << dataSize);
|
||||
accum->dataMsbMask = (1 << (dataSize - 1));
|
||||
accum->isSigned = isSigned;
|
||||
accum->bigEndian = bigEndian;
|
||||
accum->port = port;
|
||||
if (!accum->notifier) {
|
||||
accum->notifier =
|
||||
HAL_InitializeNotifier(spiAccumulatorProcess, accum, status);
|
||||
accum->triggerTime = HAL_GetFPGATime(status) + period;
|
||||
if (*status != 0) return;
|
||||
HAL_UpdateNotifierAlarm(accum->notifier, accum->triggerTime, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a SPI accumulator.
|
||||
*/
|
||||
void HAL_FreeSPIAccumulator(HAL_SPIPort port, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (!accum) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
HAL_NotifierHandle handle = accum->notifier.exchange(0);
|
||||
HAL_CleanNotifier(handle, status);
|
||||
spiAccumulators[port] = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the accumulator to zero.
|
||||
*/
|
||||
void HAL_ResetSPIAccumulator(HAL_SPIPort port, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (!accum) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
accum->value = 0;
|
||||
accum->count = 0;
|
||||
accum->lastValue = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the center value of the accumulator.
|
||||
*
|
||||
* The center value is subtracted from each value before it is added to the
|
||||
* accumulator. This
|
||||
* is used for the center value of devices like gyros and accelerometers to make
|
||||
* integration work
|
||||
* and to take the device offset into account when integrating.
|
||||
*/
|
||||
void HAL_SetSPIAccumulatorCenter(HAL_SPIPort port, int32_t center,
|
||||
int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (!accum) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
accum->center = center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the accumulator's deadband.
|
||||
*/
|
||||
void HAL_SetSPIAccumulatorDeadband(HAL_SPIPort port, int32_t deadband,
|
||||
int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (!accum) {
|
||||
*status = NULL_PARAMETER;
|
||||
return;
|
||||
}
|
||||
accum->deadband = deadband;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the last value read by the accumulator engine.
|
||||
*/
|
||||
int32_t HAL_GetSPIAccumulatorLastValue(HAL_SPIPort port, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (!accum) {
|
||||
*status = NULL_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
return accum->lastValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the accumulated value.
|
||||
*
|
||||
* @return The 64-bit value accumulated since the last Reset().
|
||||
*/
|
||||
int64_t HAL_GetSPIAccumulatorValue(HAL_SPIPort port, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (!accum) {
|
||||
*status = NULL_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
return accum->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the number of accumulated values.
|
||||
*
|
||||
* Read the count of the accumulated values since the accumulator was last
|
||||
* Reset().
|
||||
*
|
||||
* @return The number of times samples from the channel were accumulated.
|
||||
*/
|
||||
int64_t HAL_GetSPIAccumulatorCount(HAL_SPIPort port, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (!accum) {
|
||||
*status = NULL_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
return accum->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the average of the accumulated value.
|
||||
*
|
||||
* @return The accumulated average value (value / count).
|
||||
*/
|
||||
double HAL_GetSPIAccumulatorAverage(HAL_SPIPort port, int32_t* status) {
|
||||
int64_t value;
|
||||
int64_t count;
|
||||
HAL_GetSPIAccumulatorOutput(port, &value, &count, status);
|
||||
if (count == 0) return 0.0;
|
||||
return static_cast<double>(value) / count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the accumulated value and the number of accumulated values atomically.
|
||||
*
|
||||
* This function reads the value and count atomically.
|
||||
* This can be used for averaging.
|
||||
*
|
||||
* @param value Pointer to the 64-bit accumulated output.
|
||||
* @param count Pointer to the number of accumulation cycles.
|
||||
*/
|
||||
void HAL_GetSPIAccumulatorOutput(HAL_SPIPort port, int64_t* value,
|
||||
int64_t* count, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(spiGetMutex(port));
|
||||
SPIAccumulator* accum = spiAccumulators[port].get();
|
||||
if (!accum) {
|
||||
*status = NULL_PARAMETER;
|
||||
*value = 0;
|
||||
*count = 0;
|
||||
return;
|
||||
}
|
||||
*value = accum->value;
|
||||
*count = accum->count;
|
||||
}
|
||||
}
|
||||
159
hal/src/main/native/athena/SerialPort.cpp
Normal file
159
hal/src/main/native/athena/SerialPort.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/SerialPort.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "HAL/cpp/SerialHelper.h"
|
||||
#include "visa/visa.h"
|
||||
|
||||
static int32_t resourceManagerHandle;
|
||||
static HAL_SerialPort portHandles[4];
|
||||
|
||||
extern "C" {
|
||||
|
||||
void HAL_InitializeSerialPort(HAL_SerialPort port, int32_t* status) {
|
||||
std::string portName;
|
||||
|
||||
if (resourceManagerHandle == 0)
|
||||
viOpenDefaultRM(reinterpret_cast<ViSession*>(&resourceManagerHandle));
|
||||
|
||||
hal::SerialHelper serialHelper;
|
||||
|
||||
portName = serialHelper.GetVISASerialPortName(port, status);
|
||||
|
||||
if (*status < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
*status = viOpen(resourceManagerHandle, const_cast<char*>(portName.c_str()),
|
||||
VI_NULL, VI_NULL,
|
||||
reinterpret_cast<ViSession*>(&portHandles[port]));
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialBaudRate(HAL_SerialPort port, int32_t baud, int32_t* status) {
|
||||
*status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_BAUD, baud);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialDataBits(HAL_SerialPort port, int32_t bits, int32_t* status) {
|
||||
*status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_DATA_BITS, bits);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialParity(HAL_SerialPort port, int32_t parity, int32_t* status) {
|
||||
*status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_PARITY, parity);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialStopBits(HAL_SerialPort port, int32_t stopBits,
|
||||
int32_t* status) {
|
||||
*status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_STOP_BITS, stopBits);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialWriteMode(HAL_SerialPort port, int32_t mode,
|
||||
int32_t* status) {
|
||||
*status = viSetAttribute(portHandles[port], VI_ATTR_WR_BUF_OPER_MODE, mode);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialFlowControl(HAL_SerialPort port, int32_t flow,
|
||||
int32_t* status) {
|
||||
*status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_FLOW_CNTRL, flow);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialTimeout(HAL_SerialPort port, double timeout,
|
||||
int32_t* status) {
|
||||
*status = viSetAttribute(portHandles[port], VI_ATTR_TMO_VALUE,
|
||||
static_cast<uint32_t>(timeout * 1e3));
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_EnableSerialTermination(HAL_SerialPort port, char terminator,
|
||||
int32_t* status) {
|
||||
viSetAttribute(portHandles[port], VI_ATTR_TERMCHAR_EN, VI_TRUE);
|
||||
viSetAttribute(portHandles[port], VI_ATTR_TERMCHAR, terminator);
|
||||
*status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_END_IN,
|
||||
VI_ASRL_END_TERMCHAR);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_DisableSerialTermination(HAL_SerialPort port, int32_t* status) {
|
||||
viSetAttribute(portHandles[port], VI_ATTR_TERMCHAR_EN, VI_FALSE);
|
||||
*status =
|
||||
viSetAttribute(portHandles[port], VI_ATTR_ASRL_END_IN, VI_ASRL_END_NONE);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialReadBufferSize(HAL_SerialPort port, int32_t size,
|
||||
int32_t* status) {
|
||||
*status = viSetBuf(portHandles[port], VI_READ_BUF, size);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_SetSerialWriteBufferSize(HAL_SerialPort port, int32_t size,
|
||||
int32_t* status) {
|
||||
*status = viSetBuf(portHandles[port], VI_WRITE_BUF, size);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
int32_t HAL_GetSerialBytesReceived(HAL_SerialPort port, int32_t* status) {
|
||||
int32_t bytes = 0;
|
||||
|
||||
*status = viGetAttribute(portHandles[port], VI_ATTR_ASRL_AVAIL_NUM, &bytes);
|
||||
if (*status > 0) *status = 0;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int32_t HAL_ReadSerial(HAL_SerialPort port, char* buffer, int32_t count,
|
||||
int32_t* status) {
|
||||
uint32_t retCount = 0;
|
||||
|
||||
*status =
|
||||
viRead(portHandles[port], (ViPBuf)buffer, count, (ViPUInt32)&retCount);
|
||||
|
||||
if (*status == VI_ERROR_IO || *status == VI_ERROR_ASRL_OVERRUN ||
|
||||
*status == VI_ERROR_ASRL_FRAMING || *status == VI_ERROR_ASRL_PARITY) {
|
||||
int32_t localStatus = 0;
|
||||
HAL_ClearSerial(port, &localStatus);
|
||||
}
|
||||
|
||||
if (*status == VI_ERROR_TMO || *status > 0) *status = 0;
|
||||
return static_cast<int32_t>(retCount);
|
||||
}
|
||||
|
||||
int32_t HAL_WriteSerial(HAL_SerialPort port, const char* buffer, int32_t count,
|
||||
int32_t* status) {
|
||||
uint32_t retCount = 0;
|
||||
|
||||
*status =
|
||||
viWrite(portHandles[port], (ViPBuf)buffer, count, (ViPUInt32)&retCount);
|
||||
|
||||
if (*status > 0) *status = 0;
|
||||
return static_cast<int32_t>(retCount);
|
||||
}
|
||||
|
||||
void HAL_FlushSerial(HAL_SerialPort port, int32_t* status) {
|
||||
*status = viFlush(portHandles[port], VI_WRITE_BUF);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_ClearSerial(HAL_SerialPort port, int32_t* status) {
|
||||
*status = viClear(portHandles[port]);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
void HAL_CloseSerial(HAL_SerialPort port, int32_t* status) {
|
||||
*status = viClose(portHandles[port]);
|
||||
if (*status > 0) *status = 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
154
hal/src/main/native/athena/Solenoid.cpp
Normal file
154
hal/src/main/native/athena/Solenoid.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Solenoid.h"
|
||||
|
||||
#include "FRC_NetworkCommunication/LoadOut.h"
|
||||
#include "HAL/ChipObject.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Ports.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
#include "HAL/handles/IndexedHandleResource.h"
|
||||
#include "PCMInternal.h"
|
||||
#include "PortsInternal.h"
|
||||
#include "ctre/PCM.h"
|
||||
|
||||
namespace {
|
||||
struct Solenoid {
|
||||
uint8_t module;
|
||||
uint8_t channel;
|
||||
};
|
||||
}
|
||||
|
||||
using namespace hal;
|
||||
|
||||
static IndexedHandleResource<HAL_SolenoidHandle, Solenoid,
|
||||
kNumPCMModules * kNumSolenoidChannels,
|
||||
HAL_HandleEnum::Solenoid>
|
||||
solenoidHandles;
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle,
|
||||
int32_t* status) {
|
||||
int16_t channel = getPortHandleChannel(portHandle);
|
||||
int16_t module = getPortHandleModule(portHandle);
|
||||
if (channel == InvalidHandleIndex) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
// initializePCM will check the module
|
||||
if (!HAL_CheckSolenoidChannel(channel)) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
initializePCM(module, status);
|
||||
if (*status != 0) {
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
auto handle =
|
||||
solenoidHandles.Allocate(module * kNumSolenoidChannels + channel, status);
|
||||
if (*status != 0) {
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
auto solenoidPort = solenoidHandles.Get(handle);
|
||||
if (solenoidPort == nullptr) { // would only occur on thread issues
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
solenoidPort->module = static_cast<uint8_t>(module);
|
||||
solenoidPort->channel = static_cast<uint8_t>(channel);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_FreeSolenoidPort(HAL_SolenoidHandle solenoidPortHandle) {
|
||||
solenoidHandles.Free(solenoidPortHandle);
|
||||
}
|
||||
|
||||
HAL_Bool HAL_CheckSolenoidModule(int32_t module) {
|
||||
return module < kNumPCMModules && module >= 0;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_CheckSolenoidChannel(int32_t channel) {
|
||||
return channel < kNumSolenoidChannels && channel >= 0;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetSolenoid(HAL_SolenoidHandle solenoidPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = solenoidHandles.Get(solenoidPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[port->module]->GetSolenoid(port->channel, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int32_t HAL_GetAllSolenoids(int32_t module, int32_t* status) {
|
||||
if (!checkPCMInit(module, status)) return 0;
|
||||
uint8_t value;
|
||||
|
||||
*status = PCM_modules[module]->GetAllSolenoids(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void HAL_SetSolenoid(HAL_SolenoidHandle solenoidPortHandle, HAL_Bool value,
|
||||
int32_t* status) {
|
||||
auto port = solenoidHandles.Get(solenoidPortHandle);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
*status = PCM_modules[port->module]->SetSolenoid(port->channel, value);
|
||||
}
|
||||
|
||||
void HAL_SetAllSolenoids(int32_t module, int32_t state, int32_t* status) {
|
||||
if (!checkPCMInit(module, status)) return;
|
||||
|
||||
*status = PCM_modules[module]->SetAllSolenoids(state);
|
||||
}
|
||||
|
||||
int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status) {
|
||||
if (!checkPCMInit(module, status)) return 0;
|
||||
uint8_t value;
|
||||
|
||||
*status = PCM_modules[module]->GetSolenoidBlackList(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status) {
|
||||
if (!checkPCMInit(module, status)) return 0;
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[module]->GetSolenoidStickyFault(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status) {
|
||||
if (!checkPCMInit(module, status)) return false;
|
||||
bool value;
|
||||
|
||||
*status = PCM_modules[module]->GetSolenoidFault(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status) {
|
||||
if (!checkPCMInit(module, status)) return;
|
||||
|
||||
*status = PCM_modules[module]->ClearStickyFaults();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
122
hal/src/main/native/athena/Threads.cpp
Normal file
122
hal/src/main/native/athena/Threads.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/Threads.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
|
||||
extern "C" {
|
||||
/**
|
||||
* Get the thread priority for the specified thread.
|
||||
*
|
||||
* @param handle Native handle pointer to the thread to get the priority for
|
||||
* @param isRealTime Set to true if thread is realtime, otherwise false
|
||||
* @param status Error status variable. 0 on success
|
||||
* @return The current thread priority. Scaled 1-99, with 1 being highest.
|
||||
*/
|
||||
int32_t HAL_GetThreadPriority(NativeThreadHandle handle, HAL_Bool* isRealTime,
|
||||
int32_t* status) {
|
||||
sched_param sch;
|
||||
int policy;
|
||||
int success = pthread_getschedparam(*handle, &policy, &sch);
|
||||
if (success == 0) {
|
||||
*status = 0;
|
||||
} else {
|
||||
*status = HAL_THREAD_PRIORITY_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (policy == SCHED_FIFO || policy == SCHED_RR) {
|
||||
*isRealTime = true;
|
||||
return sch.sched_priority;
|
||||
} else {
|
||||
*isRealTime = false;
|
||||
// 0 is the only suppored priority for non-realtime, so scale to 1
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the thread priority for the current thread.
|
||||
*
|
||||
* @param handle Native handle pointer to the thread to get the priority for
|
||||
* @param isRealTime Set to true if thread is realtime, otherwise false
|
||||
* @param status Error status variable. 0 on success
|
||||
* @return The current thread priority. Scaled 1-99, with 1 being highest.
|
||||
*/
|
||||
int32_t HAL_GetCurrentThreadPriority(HAL_Bool* isRealTime, int32_t* status) {
|
||||
auto thread = pthread_self();
|
||||
return HAL_GetThreadPriority(&thread, isRealTime, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the thread priority for the specified thread
|
||||
*
|
||||
* @param thread Reference to the thread to set the priority of
|
||||
* @param realTime Set to true to set a realtime priority, false for standard
|
||||
* priority
|
||||
* @param priority Priority to set the thread to. Scaled 1-99, with 1 being
|
||||
* highest
|
||||
* @param status Error status variable. 0 on success
|
||||
*
|
||||
* @return The success state of setting the priority
|
||||
*/
|
||||
HAL_Bool HAL_SetThreadPriority(NativeThreadHandle handle, HAL_Bool realTime,
|
||||
int32_t priority, int32_t* status) {
|
||||
if (handle == nullptr) {
|
||||
*status = NULL_PARAMETER;
|
||||
return false;
|
||||
}
|
||||
|
||||
int scheduler = realTime ? SCHED_FIFO : SCHED_OTHER;
|
||||
if (realTime) {
|
||||
// We don't support setting priorities for non RT threads
|
||||
// so we don't need to check for proper range
|
||||
if (priority < sched_get_priority_min(scheduler) ||
|
||||
priority > sched_get_priority_max(scheduler)) {
|
||||
*status = HAL_THREAD_PRIORITY_RANGE_ERROR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sched_param sch;
|
||||
int policy;
|
||||
pthread_getschedparam(*handle, &policy, &sch);
|
||||
if (scheduler == SCHED_FIFO || scheduler == SCHED_RR)
|
||||
sch.sched_priority = priority;
|
||||
else
|
||||
// Only need to set 0 priority for non RT thread
|
||||
sch.sched_priority = 0;
|
||||
if (pthread_setschedparam(*handle, scheduler, &sch)) {
|
||||
*status = HAL_THREAD_PRIORITY_ERROR;
|
||||
return false;
|
||||
} else {
|
||||
*status = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the thread priority for the current thread
|
||||
*
|
||||
* @param thread Reference to the thread to set the priority of
|
||||
* @param realTime Set to true to set a realtime priority, false for standard
|
||||
* priority
|
||||
* @param priority Priority to set the thread to. Scaled 1-99, with 1 being
|
||||
* highest
|
||||
* @param status Error status variable. 0 on success
|
||||
*
|
||||
* @return The success state of setting the priority
|
||||
*/
|
||||
HAL_Bool HAL_SetCurrentThreadPriority(HAL_Bool realTime, int32_t priority,
|
||||
int32_t* status) {
|
||||
auto thread = pthread_self();
|
||||
return HAL_SetThreadPriority(&thread, realTime, priority, status);
|
||||
}
|
||||
}
|
||||
343
hal/src/main/native/athena/cpp/SerialHelper.cpp
Normal file
343
hal/src/main/native/athena/cpp/SerialHelper.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "HAL/cpp/SerialHelper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "../visa/visa.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
constexpr const char* OnboardResourceVISA = "ASRL1::INSTR";
|
||||
constexpr const char* MxpResourceVISA = "ASRL2::INSTR";
|
||||
|
||||
constexpr const char* OnboardResourceOS = "/dev/ttyS0";
|
||||
constexpr const char* MxpResourceOS = "/dev/ttyS1";
|
||||
|
||||
namespace hal {
|
||||
std::string SerialHelper::m_usbNames[2]{"", ""};
|
||||
|
||||
priority_mutex SerialHelper::m_nameMutex;
|
||||
|
||||
SerialHelper::SerialHelper() {
|
||||
viOpenDefaultRM(reinterpret_cast<ViSession*>(&m_resourceHandle));
|
||||
}
|
||||
|
||||
std::string SerialHelper::GetVISASerialPortName(HAL_SerialPort port,
|
||||
int32_t* status) {
|
||||
if (port == HAL_SerialPort::HAL_SerialPort_Onboard) {
|
||||
return OnboardResourceVISA;
|
||||
} else if (port == HAL_SerialPort::HAL_SerialPort_MXP) {
|
||||
return MxpResourceVISA;
|
||||
}
|
||||
|
||||
QueryHubPaths(status);
|
||||
|
||||
// If paths are empty or status error, return error
|
||||
if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
|
||||
m_sortedHubPath.empty()) {
|
||||
*status = HAL_SERIAL_PORT_NOT_FOUND;
|
||||
return "";
|
||||
}
|
||||
|
||||
int32_t visaIndex = GetIndexForPort(port, status);
|
||||
if (visaIndex == -1) {
|
||||
*status = HAL_SERIAL_PORT_NOT_FOUND;
|
||||
return "";
|
||||
// Error
|
||||
} else {
|
||||
return m_visaResource[visaIndex].str();
|
||||
}
|
||||
}
|
||||
|
||||
std::string SerialHelper::GetOSSerialPortName(HAL_SerialPort port,
|
||||
int32_t* status) {
|
||||
if (port == HAL_SerialPort::HAL_SerialPort_Onboard) {
|
||||
return OnboardResourceOS;
|
||||
} else if (port == HAL_SerialPort::HAL_SerialPort_MXP) {
|
||||
return MxpResourceOS;
|
||||
}
|
||||
|
||||
QueryHubPaths(status);
|
||||
|
||||
// If paths are empty or status error, return error
|
||||
if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
|
||||
m_sortedHubPath.empty()) {
|
||||
*status = HAL_SERIAL_PORT_NOT_FOUND;
|
||||
return "";
|
||||
}
|
||||
|
||||
int32_t osIndex = GetIndexForPort(port, status);
|
||||
if (osIndex == -1) {
|
||||
*status = HAL_SERIAL_PORT_NOT_FOUND;
|
||||
return "";
|
||||
// Error
|
||||
} else {
|
||||
return m_osResource[osIndex].str();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> SerialHelper::GetVISASerialPortList(int32_t* status) {
|
||||
std::vector<std::string> retVec;
|
||||
|
||||
// Always add 2 onboard ports
|
||||
retVec.emplace_back(OnboardResourceVISA);
|
||||
retVec.emplace_back(MxpResourceVISA);
|
||||
|
||||
QueryHubPaths(status);
|
||||
|
||||
// If paths are empty or status error, return only onboard list
|
||||
if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
|
||||
m_sortedHubPath.empty()) {
|
||||
*status = 0;
|
||||
return retVec;
|
||||
}
|
||||
|
||||
for (auto& i : m_visaResource) {
|
||||
retVec.emplace_back(i.str());
|
||||
}
|
||||
|
||||
return retVec;
|
||||
}
|
||||
|
||||
std::vector<std::string> SerialHelper::GetOSSerialPortList(int32_t* status) {
|
||||
std::vector<std::string> retVec;
|
||||
|
||||
// Always add 2 onboard ports
|
||||
retVec.emplace_back(OnboardResourceOS);
|
||||
retVec.emplace_back(MxpResourceOS);
|
||||
|
||||
QueryHubPaths(status);
|
||||
|
||||
// If paths are empty or status error, return only onboard list
|
||||
if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
|
||||
m_sortedHubPath.empty()) {
|
||||
*status = 0;
|
||||
return retVec;
|
||||
}
|
||||
|
||||
for (auto& i : m_osResource) {
|
||||
retVec.emplace_back(i.str());
|
||||
}
|
||||
|
||||
return retVec;
|
||||
}
|
||||
|
||||
void SerialHelper::SortHubPathVector() {
|
||||
m_sortedHubPath.clear();
|
||||
m_sortedHubPath = m_unsortedHubPath;
|
||||
std::sort(m_sortedHubPath.begin(), m_sortedHubPath.end(),
|
||||
[](const llvm::SmallVectorImpl<char>& lhs,
|
||||
const llvm::SmallVectorImpl<char>& rhs) -> int {
|
||||
llvm::StringRef lhsRef(lhs.begin(), lhs.size());
|
||||
llvm::StringRef rhsRef(rhs.begin(), rhs.size());
|
||||
return lhsRef.compare(rhsRef);
|
||||
});
|
||||
}
|
||||
|
||||
void SerialHelper::CoiteratedSort(
|
||||
llvm::SmallVectorImpl<llvm::SmallString<16>>& vec) {
|
||||
llvm::SmallVector<llvm::SmallString<16>, 4> sortedVec;
|
||||
for (auto& str : m_sortedHubPath) {
|
||||
for (size_t i = 0; i < m_unsortedHubPath.size(); i++) {
|
||||
if (llvm::StringRef{m_unsortedHubPath[i].begin(),
|
||||
m_unsortedHubPath[i].size()}
|
||||
.equals(llvm::StringRef{str.begin(), str.size()})) {
|
||||
sortedVec.push_back(vec[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vec = sortedVec;
|
||||
}
|
||||
|
||||
void SerialHelper::QueryHubPaths(int32_t* status) {
|
||||
// VISA resource matching string
|
||||
const char* str = "?*";
|
||||
// Items needed for VISA
|
||||
ViUInt32 retCnt = 0;
|
||||
ViFindList viList = 0;
|
||||
ViChar desc[VI_FIND_BUFLEN];
|
||||
*status = viFindRsrc(m_resourceHandle, const_cast<char*>(str), &viList,
|
||||
&retCnt, desc);
|
||||
|
||||
if (*status < 0) {
|
||||
// Handle the bad status elsewhere
|
||||
// Note let positive statii (warnings) continue
|
||||
goto done;
|
||||
}
|
||||
// Status might be positive, so reset it to 0
|
||||
*status = 0;
|
||||
|
||||
// Storage buffers for Visa calls and system exec calls
|
||||
char osName[256];
|
||||
char execBuffer[128];
|
||||
|
||||
// Loop through all returned VISA objects.
|
||||
// Increment the internal VISA ptr every loop
|
||||
for (size_t i = 0; i < retCnt; i++, viFindNext(viList, desc)) {
|
||||
// Ignore any matches to the 2 onboard ports
|
||||
if (std::strcmp(OnboardResourceVISA, desc) == 0 ||
|
||||
std::strcmp(MxpResourceVISA, desc) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Open the resource, grab its interface name, and close it.
|
||||
ViSession vSession;
|
||||
*status = viOpen(m_resourceHandle, desc, VI_NULL, VI_NULL, &vSession);
|
||||
if (*status < 0) goto done;
|
||||
*status = 0;
|
||||
|
||||
*status = viGetAttribute(vSession, VI_ATTR_INTF_INST_NAME, &osName);
|
||||
// Ignore an error here, as we want to close the session on an error
|
||||
// Use a seperate close variable so we can check
|
||||
ViStatus closeStatus = viClose(vSession);
|
||||
if (*status < 0) goto done;
|
||||
if (closeStatus < 0) goto done;
|
||||
*status = 0;
|
||||
|
||||
// split until (/dev/
|
||||
llvm::StringRef devNameRef = llvm::StringRef{osName}.split("(/dev/").second;
|
||||
// String not found, continue
|
||||
if (devNameRef.equals("")) continue;
|
||||
|
||||
// Split at )
|
||||
llvm::StringRef matchString = devNameRef.split(')').first;
|
||||
if (matchString.equals(devNameRef)) continue;
|
||||
|
||||
// Run find using pipe to get a list of system accessors
|
||||
llvm::SmallString<128> val(
|
||||
"sh -c \"find /sys/devices/soc0 | grep amba | grep usb | grep ");
|
||||
val += matchString;
|
||||
val += "\"";
|
||||
|
||||
// Pipe code found on StackOverflow
|
||||
// http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c-using-posix
|
||||
|
||||
// Using std::string because this is guarenteed to be large
|
||||
std::string output = "";
|
||||
|
||||
std::shared_ptr<FILE> pipe(popen(val.c_str(), "r"), pclose);
|
||||
// Just check the next item on a pipe failure
|
||||
if (!pipe) continue;
|
||||
while (!feof(pipe.get())) {
|
||||
if (std::fgets(execBuffer, 128, pipe.get()) != 0) output += execBuffer;
|
||||
}
|
||||
|
||||
if (!output.empty()) {
|
||||
llvm::SmallVector<llvm::StringRef, 16> pathSplitVec;
|
||||
// Split output by line, grab first line, and split it into
|
||||
// individual directories
|
||||
llvm::StringRef{output}.split('\n').first.split(pathSplitVec, '/', -1,
|
||||
false);
|
||||
|
||||
// Find each individual item index
|
||||
|
||||
const char* usb1 = "usb1";
|
||||
const char* tty = "tty";
|
||||
|
||||
int findusb = -1;
|
||||
int findtty = -1;
|
||||
int findregex = -1;
|
||||
for (size_t i = 0; i < pathSplitVec.size(); i++) {
|
||||
if (findusb == -1 && pathSplitVec[i].equals(usb1)) {
|
||||
findusb = i;
|
||||
}
|
||||
if (findtty == -1 && pathSplitVec[i].equals(tty)) {
|
||||
findtty = i;
|
||||
}
|
||||
if (findregex == -1 && pathSplitVec[i].equals(matchString)) {
|
||||
findregex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the index for our device
|
||||
int hubIndex = findtty;
|
||||
if (findtty == -1) hubIndex = findregex;
|
||||
|
||||
int devStart = findusb + 1;
|
||||
|
||||
if (hubIndex < devStart) continue;
|
||||
|
||||
// Add our devices to our list
|
||||
m_unsortedHubPath.emplace_back(
|
||||
llvm::StringRef{pathSplitVec[hubIndex - 2]});
|
||||
m_visaResource.emplace_back(desc);
|
||||
m_osResource.emplace_back(
|
||||
llvm::StringRef{osName}.split("(").second.split(")").first);
|
||||
}
|
||||
}
|
||||
|
||||
SortHubPathVector();
|
||||
|
||||
CoiteratedSort(m_visaResource);
|
||||
CoiteratedSort(m_osResource);
|
||||
done:
|
||||
viClose(viList);
|
||||
}
|
||||
|
||||
int32_t SerialHelper::GetIndexForPort(HAL_SerialPort port, int32_t* status) {
|
||||
// Hold lock whenever we're using the names array
|
||||
std::lock_guard<hal::priority_mutex> lock(m_nameMutex);
|
||||
|
||||
std::string portString = m_usbNames[port - 2];
|
||||
|
||||
llvm::SmallVector<int32_t, 4> indices;
|
||||
|
||||
// If port has not been assigned, find the one to assign
|
||||
if (portString.empty()) {
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
// Remove all used ports
|
||||
auto idx = std::find(m_sortedHubPath.begin(), m_sortedHubPath.end(),
|
||||
m_usbNames[i]);
|
||||
if (idx != m_sortedHubPath.end()) {
|
||||
// found
|
||||
m_sortedHubPath.erase(idx);
|
||||
}
|
||||
if (m_usbNames[i] == "") {
|
||||
indices.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t idx = -1;
|
||||
for (size_t i = 0; i < indices.size(); i++) {
|
||||
if (indices[i] == port - 2) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == -1) {
|
||||
*status = HAL_SERIAL_PORT_NOT_FOUND;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (idx >= static_cast<int32_t>(m_sortedHubPath.size())) {
|
||||
*status = HAL_SERIAL_PORT_NOT_FOUND;
|
||||
return -1;
|
||||
}
|
||||
|
||||
portString = m_sortedHubPath[idx].str();
|
||||
m_usbNames[port - 2] = portString;
|
||||
}
|
||||
|
||||
int retIndex = -1;
|
||||
|
||||
for (size_t i = 0; i < m_sortedHubPath.size(); i++) {
|
||||
if (m_sortedHubPath[i].equals(portString)) {
|
||||
retIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retIndex;
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
163
hal/src/main/native/athena/ctre/CtreCanNode.cpp
Normal file
163
hal/src/main/native/athena/ctre/CtreCanNode.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
|
||||
#include "ctre/CtreCanNode.h"
|
||||
#include "FRC_NetworkCommunication/CANSessionMux.h"
|
||||
#include <string.h> // memset
|
||||
|
||||
static const UINT32 kFullMessageIDMask = 0x1fffffff;
|
||||
|
||||
CtreCanNode::CtreCanNode(UINT8 deviceNumber)
|
||||
{
|
||||
_deviceNumber = deviceNumber;
|
||||
}
|
||||
CtreCanNode::~CtreCanNode()
|
||||
{
|
||||
}
|
||||
void CtreCanNode::RegisterRx(uint32_t arbId)
|
||||
{
|
||||
/* no need to do anything, we just use new API to poll last received message */
|
||||
}
|
||||
/**
|
||||
* Schedule a CAN Frame for periodic transmit.
|
||||
* @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
|
||||
* @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
|
||||
* @param dlc Number of bytes to transmit (0 to 8).
|
||||
* @param initialFrame Ptr to the frame data to schedule for transmitting. Passing null will result
|
||||
* in defaulting to zero data value.
|
||||
*/
|
||||
void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs, uint32_t dlc, const uint8_t * initialFrame)
|
||||
{
|
||||
int32_t status = 0;
|
||||
if(dlc > 8)
|
||||
dlc = 8;
|
||||
txJob_t job = {0};
|
||||
job.arbId = arbId;
|
||||
job.periodMs = periodMs;
|
||||
job.dlc = dlc;
|
||||
if(initialFrame){
|
||||
/* caller wants to specify original data */
|
||||
memcpy(job.toSend, initialFrame, dlc);
|
||||
}
|
||||
_txJobs[arbId] = job;
|
||||
FRC_NetworkCommunication_CANSessionMux_sendMessage( job.arbId,
|
||||
job.toSend,
|
||||
job.dlc,
|
||||
job.periodMs,
|
||||
&status);
|
||||
}
|
||||
/**
|
||||
* Schedule a CAN Frame for periodic transmit. Assume eight byte DLC and zero value for initial transmission.
|
||||
* @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
|
||||
* @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
|
||||
*/
|
||||
void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs)
|
||||
{
|
||||
RegisterTx(arbId,periodMs, 8, 0);
|
||||
}
|
||||
/**
|
||||
* Remove a CAN frame Arbid to stop transmission.
|
||||
* @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
|
||||
*/
|
||||
void CtreCanNode::UnregisterTx(uint32_t arbId)
|
||||
{
|
||||
/* set period to zero */
|
||||
ChangeTxPeriod(arbId, 0);
|
||||
/* look and remove */
|
||||
txJobs_t::iterator iter = _txJobs.find(arbId);
|
||||
if(iter != _txJobs.end()) {
|
||||
_txJobs.erase(iter);
|
||||
}
|
||||
}
|
||||
timespec diff(const timespec & start, const timespec & end)
|
||||
{
|
||||
timespec temp;
|
||||
if ((end.tv_nsec-start.tv_nsec)<0) {
|
||||
temp.tv_sec = end.tv_sec-start.tv_sec-1;
|
||||
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
|
||||
} else {
|
||||
temp.tv_sec = end.tv_sec-start.tv_sec;
|
||||
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
CTR_Code CtreCanNode::GetRx(uint32_t arbId,uint8_t * dataBytes, uint32_t timeoutMs)
|
||||
{
|
||||
CTR_Code retval = CTR_OKAY;
|
||||
int32_t status = 0;
|
||||
uint8_t len = 0;
|
||||
uint32_t timeStamp;
|
||||
/* cap timeout at 999ms */
|
||||
if(timeoutMs > 999)
|
||||
timeoutMs = 999;
|
||||
FRC_NetworkCommunication_CANSessionMux_receiveMessage(&arbId,kFullMessageIDMask,dataBytes,&len,&timeStamp,&status);
|
||||
if(status == 0){
|
||||
/* fresh update */
|
||||
rxEvent_t & r = _rxRxEvents[arbId]; /* lookup entry or make a default new one with all zeroes */
|
||||
clock_gettime(2,&r.time); /* fill in time */
|
||||
memcpy(r.bytes, dataBytes, 8); /* fill in databytes */
|
||||
}else{
|
||||
/* did not get the message */
|
||||
rxRxEvents_t::iterator i = _rxRxEvents.find(arbId);
|
||||
if(i == _rxRxEvents.end()){
|
||||
/* we've never gotten this mesage */
|
||||
retval = CTR_RxTimeout;
|
||||
/* fill caller's buffer with zeros */
|
||||
memset(dataBytes,0,8);
|
||||
}else{
|
||||
/* we've gotten this message before but not recently */
|
||||
memcpy(dataBytes,i->second.bytes,8);
|
||||
/* get the time now */
|
||||
struct timespec temp;
|
||||
clock_gettime(2,&temp); /* get now */
|
||||
/* how long has it been? */
|
||||
temp = diff(i->second.time,temp); /* temp = now - last */
|
||||
if(temp.tv_sec > 0){
|
||||
retval = CTR_RxTimeout;
|
||||
}else if(temp.tv_nsec > ((int32_t)timeoutMs*1000*1000)){
|
||||
retval = CTR_RxTimeout;
|
||||
}else {
|
||||
/* our last update was recent enough */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
void CtreCanNode::FlushTx(uint32_t arbId)
|
||||
{
|
||||
int32_t status = 0;
|
||||
txJobs_t::iterator iter = _txJobs.find(arbId);
|
||||
if(iter != _txJobs.end())
|
||||
FRC_NetworkCommunication_CANSessionMux_sendMessage( iter->second.arbId,
|
||||
iter->second.toSend,
|
||||
iter->second.dlc,
|
||||
iter->second.periodMs,
|
||||
&status);
|
||||
}
|
||||
/**
|
||||
* Change the transmit period of an already scheduled CAN frame.
|
||||
* This keeps the frame payload contents the same without caller having to perform
|
||||
* a read-modify-write.
|
||||
* @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
|
||||
* @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
|
||||
* @return true if scheduled job was found and updated, false if there was no preceding job for the specified arbID.
|
||||
*/
|
||||
bool CtreCanNode::ChangeTxPeriod(uint32_t arbId, uint32_t periodMs)
|
||||
{
|
||||
int32_t status = 0;
|
||||
/* lookup the data bytes and period for this message */
|
||||
txJobs_t::iterator iter = _txJobs.find(arbId);
|
||||
if(iter != _txJobs.end()) {
|
||||
/* modify th periodMs */
|
||||
iter->second.periodMs = periodMs;
|
||||
/* reinsert into scheduler with the same data bytes, only the period changed. */
|
||||
FRC_NetworkCommunication_CANSessionMux_sendMessage( iter->second.arbId,
|
||||
iter->second.toSend,
|
||||
iter->second.dlc,
|
||||
iter->second.periodMs,
|
||||
&status);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
572
hal/src/main/native/athena/ctre/PCM.cpp
Normal file
572
hal/src/main/native/athena/ctre/PCM.cpp
Normal file
@@ -0,0 +1,572 @@
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
|
||||
#include "ctre/PCM.h"
|
||||
#include "FRC_NetworkCommunication/CANSessionMux.h"
|
||||
#include <string.h> // memset
|
||||
/* This can be a constant, as long as nobody needs to update solenoids within
|
||||
1/50 of a second. */
|
||||
static const INT32 kCANPeriod = 20;
|
||||
|
||||
#define STATUS_1 0x9041400
|
||||
#define STATUS_SOL_FAULTS 0x9041440
|
||||
#define STATUS_DEBUG 0x9041480
|
||||
|
||||
#define EXPECTED_RESPONSE_TIMEOUT_MS (50)
|
||||
#define GET_PCM_STATUS() CtreCanNode::recMsg<PcmStatus_t> rx = GetRx<PcmStatus_t> (STATUS_1|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
|
||||
#define GET_PCM_SOL_FAULTS() CtreCanNode::recMsg<PcmStatusFault_t> rx = GetRx<PcmStatusFault_t> (STATUS_SOL_FAULTS|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
|
||||
#define GET_PCM_DEBUG() CtreCanNode::recMsg<PcmDebug_t> rx = GetRx<PcmDebug_t> (STATUS_DEBUG|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
|
||||
|
||||
#define CONTROL_1 0x09041C00 /* PCM_Control */
|
||||
#define CONTROL_2 0x09041C40 /* PCM_SupplemControl */
|
||||
#define CONTROL_3 0x09041C80 /* PcmControlSetOneShotDur_t */
|
||||
|
||||
/* encoder/decoders */
|
||||
typedef struct _PcmStatus_t{
|
||||
/* Byte 0 */
|
||||
unsigned SolenoidBits:8;
|
||||
/* Byte 1 */
|
||||
unsigned compressorOn:1;
|
||||
unsigned stickyFaultFuseTripped:1;
|
||||
unsigned stickyFaultCompCurrentTooHigh:1;
|
||||
unsigned faultFuseTripped:1;
|
||||
unsigned faultCompCurrentTooHigh:1;
|
||||
unsigned faultHardwareFailure:1;
|
||||
unsigned isCloseloopEnabled:1;
|
||||
unsigned pressureSwitchEn:1;
|
||||
/* Byte 2*/
|
||||
unsigned battVoltage:8;
|
||||
/* Byte 3 */
|
||||
unsigned solenoidVoltageTop8:8;
|
||||
/* Byte 4 */
|
||||
unsigned compressorCurrentTop6:6;
|
||||
unsigned solenoidVoltageBtm2:2;
|
||||
/* Byte 5 */
|
||||
unsigned StickyFault_dItooHigh :1;
|
||||
unsigned Fault_dItooHigh :1;
|
||||
unsigned moduleEnabled:1;
|
||||
unsigned closedLoopOutput:1;
|
||||
unsigned compressorCurrentBtm4:4;
|
||||
/* Byte 6 */
|
||||
unsigned tokenSeedTop8:8;
|
||||
/* Byte 7 */
|
||||
unsigned tokenSeedBtm8:8;
|
||||
}PcmStatus_t;
|
||||
|
||||
typedef struct _PcmControl_t{
|
||||
/* Byte 0 */
|
||||
unsigned tokenTop8:8;
|
||||
/* Byte 1 */
|
||||
unsigned tokenBtm8:8;
|
||||
/* Byte 2 */
|
||||
unsigned solenoidBits:8;
|
||||
/* Byte 3*/
|
||||
unsigned reserved:4;
|
||||
unsigned closeLoopOutput:1;
|
||||
unsigned compressorOn:1;
|
||||
unsigned closedLoopEnable:1;
|
||||
unsigned clearStickyFaults:1;
|
||||
/* Byte 4 */
|
||||
unsigned OneShotField_h8:8;
|
||||
/* Byte 5 */
|
||||
unsigned OneShotField_l8:8;
|
||||
}PcmControl_t;
|
||||
|
||||
typedef struct _PcmControlSetOneShotDur_t{
|
||||
uint8_t sol10MsPerUnit[8];
|
||||
}PcmControlSetOneShotDur_t;
|
||||
|
||||
typedef struct _PcmStatusFault_t{
|
||||
/* Byte 0 */
|
||||
unsigned SolenoidBlacklist:8;
|
||||
/* Byte 1 */
|
||||
unsigned reserved_bit0 :1;
|
||||
unsigned reserved_bit1 :1;
|
||||
unsigned reserved_bit2 :1;
|
||||
unsigned reserved_bit3 :1;
|
||||
unsigned StickyFault_CompNoCurrent :1;
|
||||
unsigned Fault_CompNoCurrent :1;
|
||||
unsigned StickyFault_SolenoidJumper :1;
|
||||
unsigned Fault_SolenoidJumper :1;
|
||||
}PcmStatusFault_t;
|
||||
|
||||
typedef struct _PcmDebug_t{
|
||||
unsigned tokFailsTop8:8;
|
||||
unsigned tokFailsBtm8:8;
|
||||
unsigned lastFailedTokTop8:8;
|
||||
unsigned lastFailedTokBtm8:8;
|
||||
unsigned tokSuccessTop8:8;
|
||||
unsigned tokSuccessBtm8:8;
|
||||
}PcmDebug_t;
|
||||
|
||||
|
||||
/* PCM Constructor - Clears all vars, establishes default settings, starts PCM background process
|
||||
*
|
||||
* @Return - void
|
||||
*
|
||||
* @Param - deviceNumber - Device ID of PCM to be controlled
|
||||
*/
|
||||
PCM::PCM(UINT8 deviceNumber): CtreCanNode(deviceNumber)
|
||||
{
|
||||
RegisterRx(STATUS_1 | deviceNumber );
|
||||
RegisterRx(STATUS_SOL_FAULTS | deviceNumber );
|
||||
RegisterRx(STATUS_DEBUG | deviceNumber );
|
||||
RegisterTx(CONTROL_1 | deviceNumber, kCANPeriod);
|
||||
/* enable close loop */
|
||||
SetClosedLoopControl(1);
|
||||
}
|
||||
/* PCM D'tor
|
||||
*/
|
||||
PCM::~PCM()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* Set PCM solenoid state
|
||||
*
|
||||
* @Return - CTR_Code - Error code (if any) for setting solenoid
|
||||
*
|
||||
* @Param - idx - ID of solenoid (0-7)
|
||||
* @Param - en - Enable / Disable identified solenoid
|
||||
*/
|
||||
CTR_Code PCM::SetSolenoid(unsigned char idx, bool en)
|
||||
{
|
||||
CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
|
||||
if(toFill.IsEmpty())return CTR_UnexpectedArbId;
|
||||
if (en)
|
||||
toFill->solenoidBits |= (1ul << (idx));
|
||||
else
|
||||
toFill->solenoidBits &= ~(1ul << (idx));
|
||||
FlushTx(toFill);
|
||||
return CTR_OKAY;
|
||||
}
|
||||
|
||||
/* Set all PCM solenoid states
|
||||
*
|
||||
* @Return - CTR_Code - Error code (if any) for setting solenoids
|
||||
* @Param - state Bitfield to set all solenoids to
|
||||
*/
|
||||
CTR_Code PCM::SetAllSolenoids(UINT8 state) {
|
||||
CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
|
||||
if(toFill.IsEmpty())return CTR_UnexpectedArbId;
|
||||
toFill->solenoidBits = state;
|
||||
FlushTx(toFill);
|
||||
return CTR_OKAY;
|
||||
}
|
||||
|
||||
/* Clears PCM sticky faults (indicators of past faults
|
||||
*
|
||||
* @Return - CTR_Code - Error code (if any) for setting solenoid
|
||||
*
|
||||
* @Param - clr - Clear / do not clear faults
|
||||
*/
|
||||
CTR_Code PCM::ClearStickyFaults()
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint8_t pcmSupplemControl[] = { 0, 0, 0, 0x80 }; /* only bit set is ClearStickyFaults */
|
||||
FRC_NetworkCommunication_CANSessionMux_sendMessage(CONTROL_2 | GetDeviceNumber(), pcmSupplemControl, sizeof(pcmSupplemControl), 0, &status);
|
||||
if(status)
|
||||
return CTR_TxFailed;
|
||||
return CTR_OKAY;
|
||||
}
|
||||
|
||||
/* Enables PCM Closed Loop Control of Compressor via pressure switch
|
||||
*
|
||||
* @Return - CTR_Code - Error code (if any) for setting solenoid
|
||||
*
|
||||
* @Param - en - Enable / Disable Closed Loop Control
|
||||
*/
|
||||
CTR_Code PCM::SetClosedLoopControl(bool en)
|
||||
{
|
||||
CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
|
||||
if(toFill.IsEmpty())return CTR_UnexpectedArbId;
|
||||
toFill->closedLoopEnable = en;
|
||||
FlushTx(toFill);
|
||||
return CTR_OKAY;
|
||||
}
|
||||
/* Get solenoid Blacklist status
|
||||
* @Return - CTR_Code - Error code (if any)
|
||||
* @Param - idx - ID of solenoid [0,7] to fire one shot pulse.
|
||||
*/
|
||||
CTR_Code PCM::FireOneShotSolenoid(UINT8 idx)
|
||||
{
|
||||
CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
|
||||
if(toFill.IsEmpty())return CTR_UnexpectedArbId;
|
||||
/* grab field as it is now */
|
||||
uint16_t oneShotField;
|
||||
oneShotField = toFill->OneShotField_h8;
|
||||
oneShotField <<= 8;
|
||||
oneShotField |= toFill->OneShotField_l8;
|
||||
/* get the caller's channel */
|
||||
uint16_t shift = 2*idx;
|
||||
uint16_t mask = 3; /* two bits wide */
|
||||
uint8_t chBits = (oneShotField >> shift) & mask;
|
||||
/* flip it */
|
||||
chBits = (chBits)%3 + 1;
|
||||
/* clear out 2bits for this channel*/
|
||||
oneShotField &= ~(mask << shift);
|
||||
/* put new field in */
|
||||
oneShotField |= chBits << shift;
|
||||
/* apply field as it is now */
|
||||
toFill->OneShotField_h8 = oneShotField >> 8;
|
||||
toFill->OneShotField_l8 = oneShotField;
|
||||
FlushTx(toFill);
|
||||
return CTR_OKAY;
|
||||
}
|
||||
/* Configure the pulse width of a solenoid channel for one-shot pulse.
|
||||
* Preprogrammed pulsewidth is 10ms resolute and can be between 20ms and 5.1s.
|
||||
* @Return - CTR_Code - Error code (if any)
|
||||
* @Param - idx - ID of solenoid [0,7] to configure.
|
||||
* @Param - durMs - pulse width in ms.
|
||||
*/
|
||||
CTR_Code PCM::SetOneShotDurationMs(UINT8 idx,uint32_t durMs)
|
||||
{
|
||||
/* sanity check caller's param */
|
||||
if(idx > 7)
|
||||
return CTR_InvalidParamValue;
|
||||
/* get latest tx frame */
|
||||
CtreCanNode::txTask<PcmControlSetOneShotDur_t> toFill = GetTx<PcmControlSetOneShotDur_t>(CONTROL_3 | GetDeviceNumber());
|
||||
if(toFill.IsEmpty()){
|
||||
/* only send this out if caller wants to do one-shots */
|
||||
RegisterTx(CONTROL_3 | _deviceNumber, kCANPeriod);
|
||||
/* grab it */
|
||||
toFill = GetTx<PcmControlSetOneShotDur_t>(CONTROL_3 | GetDeviceNumber());
|
||||
}
|
||||
toFill->sol10MsPerUnit[idx] = std::min(durMs/10,(uint32_t)0xFF);
|
||||
/* apply the new data bytes */
|
||||
FlushTx(toFill);
|
||||
return CTR_OKAY;
|
||||
}
|
||||
|
||||
/* Get solenoid state
|
||||
*
|
||||
* @Return - True/False - True if solenoid enabled, false otherwise
|
||||
*
|
||||
* @Param - idx - ID of solenoid (0-7) to return status of
|
||||
*/
|
||||
CTR_Code PCM::GetSolenoid(UINT8 idx, bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = (rx->SolenoidBits & (1ul<<(idx)) ) ? 1 : 0;
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get solenoid state for all solenoids on the PCM
|
||||
*
|
||||
* @Return - Bitfield of solenoid states
|
||||
*/
|
||||
CTR_Code PCM::GetAllSolenoids(UINT8 &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->SolenoidBits;
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get pressure switch state
|
||||
*
|
||||
* @Return - True/False - True if pressure adequate, false if low
|
||||
*/
|
||||
CTR_Code PCM::GetPressure(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = (rx->pressureSwitchEn ) ? 1 : 0;
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get compressor state
|
||||
*
|
||||
* @Return - True/False - True if enabled, false if otherwise
|
||||
*/
|
||||
CTR_Code PCM::GetCompressor(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = (rx->compressorOn);
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get closed loop control state
|
||||
*
|
||||
* @Return - True/False - True if closed loop enabled, false if otherwise
|
||||
*/
|
||||
CTR_Code PCM::GetClosedLoopControl(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = (rx->isCloseloopEnabled);
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get compressor current draw
|
||||
*
|
||||
* @Return - Amperes - Compressor current
|
||||
*/
|
||||
CTR_Code PCM::GetCompressorCurrent(float &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
uint32_t temp =(rx->compressorCurrentTop6);
|
||||
temp <<= 4;
|
||||
temp |= rx->compressorCurrentBtm4;
|
||||
status = temp * 0.03125; /* 5.5 fixed pt value in Amps */
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get voltage across solenoid rail
|
||||
*
|
||||
* @Return - Volts - Voltage across solenoid rail
|
||||
*/
|
||||
CTR_Code PCM::GetSolenoidVoltage(float &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
uint32_t raw =(rx->solenoidVoltageTop8);
|
||||
raw <<= 2;
|
||||
raw |= rx->solenoidVoltageBtm2;
|
||||
status = (double) raw * 0.03125; /* 5.5 fixed pt value in Volts */
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get hardware fault value
|
||||
*
|
||||
* @Return - True/False - True if hardware failure detected, false if otherwise
|
||||
*/
|
||||
CTR_Code PCM::GetHardwareFault(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->faultHardwareFailure;
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get compressor fault value
|
||||
*
|
||||
* @Return - True/False - True if shorted compressor detected, false if otherwise
|
||||
*/
|
||||
CTR_Code PCM::GetCompressorCurrentTooHighFault(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->faultCompCurrentTooHigh;
|
||||
return rx.err;
|
||||
}
|
||||
CTR_Code PCM::GetCompressorShortedStickyFault(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->StickyFault_dItooHigh;
|
||||
return rx.err;
|
||||
}
|
||||
CTR_Code PCM::GetCompressorShortedFault(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->Fault_dItooHigh;
|
||||
return rx.err;
|
||||
}
|
||||
CTR_Code PCM::GetCompressorNotConnectedStickyFault(bool &status)
|
||||
{
|
||||
GET_PCM_SOL_FAULTS();
|
||||
status = rx->StickyFault_CompNoCurrent;
|
||||
return rx.err;
|
||||
}
|
||||
CTR_Code PCM::GetCompressorNotConnectedFault(bool &status)
|
||||
{
|
||||
GET_PCM_SOL_FAULTS();
|
||||
status = rx->Fault_CompNoCurrent;
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get solenoid fault value
|
||||
*
|
||||
* @Return - True/False - True if shorted solenoid detected, false if otherwise
|
||||
*/
|
||||
CTR_Code PCM::GetSolenoidFault(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->faultFuseTripped;
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get compressor sticky fault value
|
||||
*
|
||||
* @Return - True/False - True if solenoid had previously been shorted
|
||||
* (and sticky fault was not cleared), false if otherwise
|
||||
*/
|
||||
CTR_Code PCM::GetCompressorCurrentTooHighStickyFault(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->stickyFaultCompCurrentTooHigh;
|
||||
return rx.err;
|
||||
}
|
||||
|
||||
/* Get solenoid sticky fault value
|
||||
*
|
||||
* @Return - True/False - True if compressor had previously been shorted
|
||||
* (and sticky fault was not cleared), false if otherwise
|
||||
*/
|
||||
CTR_Code PCM::GetSolenoidStickyFault(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->stickyFaultFuseTripped;
|
||||
return rx.err;
|
||||
}
|
||||
/* Get battery voltage
|
||||
*
|
||||
* @Return - Volts - Voltage across PCM power ports
|
||||
*/
|
||||
CTR_Code PCM::GetBatteryVoltage(float &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = (float)rx->battVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
|
||||
return rx.err;
|
||||
}
|
||||
/* Return status of module enable/disable
|
||||
*
|
||||
* @Return - bool - Returns TRUE if PCM is enabled, FALSE if disabled
|
||||
*/
|
||||
CTR_Code PCM::isModuleEnabled(bool &status)
|
||||
{
|
||||
GET_PCM_STATUS();
|
||||
status = rx->moduleEnabled;
|
||||
return rx.err;
|
||||
}
|
||||
/* Get number of total failed PCM Control Frame
|
||||
*
|
||||
* @Return - Failed Control Frames - Number of failed control frames (tokenization fails)
|
||||
*
|
||||
* @WARNING - Return only valid if [SeekDebugFrames] is enabled
|
||||
* See function SeekDebugFrames
|
||||
* See function EnableSeekDebugFrames
|
||||
*/
|
||||
CTR_Code PCM::GetNumberOfFailedControlFrames(UINT16 &status)
|
||||
{
|
||||
GET_PCM_DEBUG();
|
||||
status = rx->tokFailsTop8;
|
||||
status <<= 8;
|
||||
status |= rx->tokFailsBtm8;
|
||||
return rx.err;
|
||||
}
|
||||
/* Get raw Solenoid Blacklist
|
||||
*
|
||||
* @Return - BINARY - Raw binary breakdown of Solenoid Blacklist
|
||||
* BIT7 = Solenoid 1, BIT6 = Solenoid 2, etc.
|
||||
*
|
||||
* @WARNING - Return only valid if [SeekStatusFaultFrames] is enabled
|
||||
* See function SeekStatusFaultFrames
|
||||
* See function EnableSeekStatusFaultFrames
|
||||
*/
|
||||
CTR_Code PCM::GetSolenoidBlackList(UINT8 &status)
|
||||
{
|
||||
GET_PCM_SOL_FAULTS();
|
||||
status = rx->SolenoidBlacklist;
|
||||
return rx.err;
|
||||
}
|
||||
/* Get solenoid Blacklist status
|
||||
* - Blacklisted solenoids cannot be enabled until PCM is power cycled
|
||||
*
|
||||
* @Return - True/False - True if Solenoid is blacklisted, false if otherwise
|
||||
*
|
||||
* @Param - idx - ID of solenoid [0,7]
|
||||
*
|
||||
* @WARNING - Return only valid if [SeekStatusFaultFrames] is enabled
|
||||
* See function SeekStatusFaultFrames
|
||||
* See function EnableSeekStatusFaultFrames
|
||||
*/
|
||||
CTR_Code PCM::IsSolenoidBlacklisted(UINT8 idx, bool &status)
|
||||
{
|
||||
GET_PCM_SOL_FAULTS();
|
||||
status = (rx->SolenoidBlacklist & (1ul<<(idx)) )? 1 : 0;
|
||||
return rx.err;
|
||||
}
|
||||
//------------------ C interface --------------------------------------------//
|
||||
extern "C" {
|
||||
void * c_PCM_Init(void) {
|
||||
return new PCM();
|
||||
}
|
||||
CTR_Code c_SetSolenoid(void * handle, unsigned char idx, INT8 param) {
|
||||
return ((PCM*) handle)->SetSolenoid(idx, param);
|
||||
}
|
||||
CTR_Code c_SetAllSolenoids(void * handle, UINT8 state) {
|
||||
return ((PCM*) handle)->SetAllSolenoids(state);
|
||||
}
|
||||
CTR_Code c_SetClosedLoopControl(void * handle, INT8 param) {
|
||||
return ((PCM*) handle)->SetClosedLoopControl(param);
|
||||
}
|
||||
CTR_Code c_ClearStickyFaults(void * handle, INT8 param) {
|
||||
return ((PCM*) handle)->ClearStickyFaults();
|
||||
}
|
||||
CTR_Code c_GetSolenoid(void * handle, UINT8 idx, INT8 * status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetSolenoid(idx, bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetAllSolenoids(void * handle, UINT8 * status) {
|
||||
return ((PCM*) handle)->GetAllSolenoids(*status);
|
||||
}
|
||||
CTR_Code c_GetPressure(void * handle, INT8 * status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetPressure(bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetCompressor(void * handle, INT8 * status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetCompressor(bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetClosedLoopControl(void * handle, INT8 * status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetClosedLoopControl(bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetCompressorCurrent(void * handle, float * status) {
|
||||
CTR_Code retval = ((PCM*) handle)->GetCompressorCurrent(*status);
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetSolenoidVoltage(void * handle, float*status) {
|
||||
return ((PCM*) handle)->GetSolenoidVoltage(*status);
|
||||
}
|
||||
CTR_Code c_GetHardwareFault(void * handle, INT8*status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetHardwareFault(bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetCompressorFault(void * handle, INT8*status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetCompressorCurrentTooHighFault(bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetSolenoidFault(void * handle, INT8*status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetSolenoidFault(bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetCompressorStickyFault(void * handle, INT8*status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetCompressorCurrentTooHighStickyFault(bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetSolenoidStickyFault(void * handle, INT8*status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->GetSolenoidStickyFault(bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
CTR_Code c_GetBatteryVoltage(void * handle, float*status) {
|
||||
CTR_Code retval = ((PCM*) handle)->GetBatteryVoltage(*status);
|
||||
return retval;
|
||||
}
|
||||
void c_SetDeviceNumber_PCM(void * handle, UINT8 deviceNumber) {
|
||||
}
|
||||
CTR_Code c_GetNumberOfFailedControlFrames(void * handle, UINT16*status) {
|
||||
return ((PCM*) handle)->GetNumberOfFailedControlFrames(*status);
|
||||
}
|
||||
CTR_Code c_GetSolenoidBlackList(void * handle, UINT8 *status) {
|
||||
return ((PCM*) handle)->GetSolenoidBlackList(*status);
|
||||
}
|
||||
CTR_Code c_IsSolenoidBlacklisted(void * handle, UINT8 idx, INT8*status) {
|
||||
bool bstatus;
|
||||
CTR_Code retval = ((PCM*) handle)->IsSolenoidBlacklisted(idx, bstatus);
|
||||
*status = bstatus;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
230
hal/src/main/native/athena/ctre/PDP.cpp
Normal file
230
hal/src/main/native/athena/ctre/PDP.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
#include "ctre/PDP.h"
|
||||
#include "FRC_NetworkCommunication/CANSessionMux.h" //CAN Comm
|
||||
#include <string.h> // memset
|
||||
|
||||
#define STATUS_1 0x8041400
|
||||
#define STATUS_2 0x8041440
|
||||
#define STATUS_3 0x8041480
|
||||
#define STATUS_ENERGY 0x8041740
|
||||
|
||||
#define CONTROL_1 0x08041C00 /* PDP_Control_ClearStats */
|
||||
|
||||
#define EXPECTED_RESPONSE_TIMEOUT_MS (50)
|
||||
#define GET_STATUS1() CtreCanNode::recMsg<PdpStatus1_t> rx = GetRx<PdpStatus1_t>(STATUS_1|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
|
||||
#define GET_STATUS2() CtreCanNode::recMsg<PdpStatus2_t> rx = GetRx<PdpStatus2_t>(STATUS_2|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
|
||||
#define GET_STATUS3() CtreCanNode::recMsg<PdpStatus3_t> rx = GetRx<PdpStatus3_t>(STATUS_3|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
|
||||
#define GET_STATUS_ENERGY() CtreCanNode::recMsg<PDP_Status_Energy_t> rx = GetRx<PDP_Status_Energy_t>(STATUS_ENERGY|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
|
||||
|
||||
/* encoder/decoders */
|
||||
typedef struct _PdpStatus1_t{
|
||||
unsigned chan1_h8:8;
|
||||
unsigned chan2_h6:6;
|
||||
unsigned chan1_l2:2;
|
||||
unsigned chan3_h4:4;
|
||||
unsigned chan2_l4:4;
|
||||
unsigned chan4_h2:2;
|
||||
unsigned chan3_l6:6;
|
||||
unsigned chan4_l8:8;
|
||||
unsigned chan5_h8:8;
|
||||
unsigned chan6_h6:6;
|
||||
unsigned chan5_l2:2;
|
||||
unsigned reserved4:4;
|
||||
unsigned chan6_l4:4;
|
||||
}PdpStatus1_t;
|
||||
typedef struct _PdpStatus2_t{
|
||||
unsigned chan7_h8:8;
|
||||
unsigned chan8_h6:6;
|
||||
unsigned chan7_l2:2;
|
||||
unsigned chan9_h4:4;
|
||||
unsigned chan8_l4:4;
|
||||
unsigned chan10_h2:2;
|
||||
unsigned chan9_l6:6;
|
||||
unsigned chan10_l8:8;
|
||||
unsigned chan11_h8:8;
|
||||
unsigned chan12_h6:6;
|
||||
unsigned chan11_l2:2;
|
||||
unsigned reserved4:4;
|
||||
unsigned chan12_l4:4;
|
||||
}PdpStatus2_t;
|
||||
typedef struct _PdpStatus3_t{
|
||||
unsigned chan13_h8:8;
|
||||
unsigned chan14_h6:6;
|
||||
unsigned chan13_l2:2;
|
||||
unsigned chan15_h4:4;
|
||||
unsigned chan14_l4:4;
|
||||
unsigned chan16_h2:2;
|
||||
unsigned chan15_l6:6;
|
||||
unsigned chan16_l8:8;
|
||||
unsigned internalResBattery_mOhms:8;
|
||||
unsigned busVoltage:8;
|
||||
unsigned temp:8;
|
||||
}PdpStatus3_t;
|
||||
typedef struct _PDP_Status_Energy_t {
|
||||
unsigned TmeasMs_likelywillbe20ms_:8;
|
||||
unsigned TotalCurrent_125mAperunit_h8:8;
|
||||
unsigned Power_125mWperunit_h4:4;
|
||||
unsigned TotalCurrent_125mAperunit_l4:4;
|
||||
unsigned Power_125mWperunit_m8:8;
|
||||
unsigned Energy_125mWPerUnitXTmeas_h4:4;
|
||||
unsigned Power_125mWperunit_l4:4;
|
||||
unsigned Energy_125mWPerUnitXTmeas_mh8:8;
|
||||
unsigned Energy_125mWPerUnitXTmeas_ml8:8;
|
||||
unsigned Energy_125mWPerUnitXTmeas_l8:8;
|
||||
} PDP_Status_Energy_t ;
|
||||
|
||||
PDP::PDP(UINT8 deviceNumber): CtreCanNode(deviceNumber)
|
||||
{
|
||||
RegisterRx(STATUS_1 | deviceNumber );
|
||||
RegisterRx(STATUS_2 | deviceNumber );
|
||||
RegisterRx(STATUS_3 | deviceNumber );
|
||||
}
|
||||
/* PDP D'tor
|
||||
*/
|
||||
PDP::~PDP()
|
||||
{
|
||||
}
|
||||
|
||||
CTR_Code PDP::GetChannelCurrent(UINT8 idx, double ¤t)
|
||||
{
|
||||
CTR_Code retval = CTR_InvalidParamValue;
|
||||
uint32_t raw = 0;
|
||||
|
||||
if(idx <= 5){
|
||||
GET_STATUS1();
|
||||
retval = rx.err;
|
||||
switch(idx){
|
||||
case 0: raw = ((uint32_t)rx->chan1_h8 << 2) | rx->chan1_l2; break;
|
||||
case 1: raw = ((uint32_t)rx->chan2_h6 << 4) | rx->chan2_l4; break;
|
||||
case 2: raw = ((uint32_t)rx->chan3_h4 << 6) | rx->chan3_l6; break;
|
||||
case 3: raw = ((uint32_t)rx->chan4_h2 << 8) | rx->chan4_l8; break;
|
||||
case 4: raw = ((uint32_t)rx->chan5_h8 << 2) | rx->chan5_l2; break;
|
||||
case 5: raw = ((uint32_t)rx->chan6_h6 << 4) | rx->chan6_l4; break;
|
||||
default: retval = CTR_InvalidParamValue; break;
|
||||
}
|
||||
}else if(idx <= 11){
|
||||
GET_STATUS2();
|
||||
retval = rx.err;
|
||||
switch(idx){
|
||||
case 6: raw = ((uint32_t)rx->chan7_h8 << 2) | rx->chan7_l2; break;
|
||||
case 7: raw = ((uint32_t)rx->chan8_h6 << 4) | rx->chan8_l4; break;
|
||||
case 8: raw = ((uint32_t)rx->chan9_h4 << 6) | rx->chan9_l6; break;
|
||||
case 9: raw = ((uint32_t)rx->chan10_h2 << 8) | rx->chan10_l8; break;
|
||||
case 10: raw = ((uint32_t)rx->chan11_h8 << 2) | rx->chan11_l2; break;
|
||||
case 11: raw = ((uint32_t)rx->chan12_h6 << 4) | rx->chan12_l4; break;
|
||||
default: retval = CTR_InvalidParamValue; break;
|
||||
}
|
||||
}else if(idx <= 15){
|
||||
GET_STATUS3();
|
||||
retval = rx.err;
|
||||
switch(idx){
|
||||
case 12: raw = ((uint32_t)rx->chan13_h8 << 2) | rx->chan13_l2; break;
|
||||
case 13: raw = ((uint32_t)rx->chan14_h6 << 4) | rx->chan14_l4; break;
|
||||
case 14: raw = ((uint32_t)rx->chan15_h4 << 6) | rx->chan15_l6; break;
|
||||
case 15: raw = ((uint32_t)rx->chan16_h2 << 8) | rx->chan16_l8; break;
|
||||
default: retval = CTR_InvalidParamValue; break;
|
||||
}
|
||||
}
|
||||
/* convert to amps */
|
||||
current = (double)raw * 0.125; /* 7.3 fixed pt value in Amps */
|
||||
/* signal caller with success */
|
||||
return retval;
|
||||
}
|
||||
CTR_Code PDP::GetVoltage(double &voltage)
|
||||
{
|
||||
GET_STATUS3();
|
||||
uint32_t raw = rx->busVoltage;
|
||||
voltage = (double)raw * 0.05 + 4.0; /* 50mV per unit plus 4V. */;
|
||||
return rx.err;
|
||||
}
|
||||
CTR_Code PDP::GetTemperature(double &tempC)
|
||||
{
|
||||
GET_STATUS3();
|
||||
uint32_t raw = rx->temp;
|
||||
tempC = (double)raw * 1.03250836957542 - 67.8564500484966;
|
||||
return rx.err;
|
||||
}
|
||||
CTR_Code PDP::GetTotalCurrent(double ¤tAmps)
|
||||
{
|
||||
GET_STATUS_ENERGY();
|
||||
uint32_t raw;
|
||||
raw = rx->TotalCurrent_125mAperunit_h8;
|
||||
raw <<= 4;
|
||||
raw |= rx->TotalCurrent_125mAperunit_l4;
|
||||
currentAmps = 0.125 * raw;
|
||||
return rx.err;
|
||||
}
|
||||
CTR_Code PDP::GetTotalPower(double &powerWatts)
|
||||
{
|
||||
GET_STATUS_ENERGY();
|
||||
uint32_t raw;
|
||||
raw = rx->Power_125mWperunit_h4;
|
||||
raw <<= 8;
|
||||
raw |= rx->Power_125mWperunit_m8;
|
||||
raw <<= 4;
|
||||
raw |= rx->Power_125mWperunit_l4;
|
||||
powerWatts = 0.125 * raw;
|
||||
return rx.err;
|
||||
}
|
||||
CTR_Code PDP::GetTotalEnergy(double &energyJoules)
|
||||
{
|
||||
GET_STATUS_ENERGY();
|
||||
uint32_t raw;
|
||||
raw = rx->Energy_125mWPerUnitXTmeas_h4;
|
||||
raw <<= 8;
|
||||
raw |= rx->Energy_125mWPerUnitXTmeas_mh8;
|
||||
raw <<= 8;
|
||||
raw |= rx->Energy_125mWPerUnitXTmeas_ml8;
|
||||
raw <<= 8;
|
||||
raw |= rx->Energy_125mWPerUnitXTmeas_l8;
|
||||
energyJoules = 0.125 * raw; /* mW integrated every TmeasMs */
|
||||
energyJoules *= 0.001; /* convert from mW to W */
|
||||
energyJoules *= rx->TmeasMs_likelywillbe20ms_; /* multiplied by TmeasMs = joules */
|
||||
return rx.err;
|
||||
}
|
||||
/* Clear sticky faults.
|
||||
* @Return - CTR_Code - Error code (if any)
|
||||
*/
|
||||
CTR_Code PDP::ClearStickyFaults()
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint8_t pdpControl[] = { 0x80 }; /* only bit set is ClearStickyFaults */
|
||||
FRC_NetworkCommunication_CANSessionMux_sendMessage(CONTROL_1 | GetDeviceNumber(), pdpControl, sizeof(pdpControl), 0, &status);
|
||||
if(status)
|
||||
return CTR_TxFailed;
|
||||
return CTR_OKAY;
|
||||
}
|
||||
|
||||
/* Reset Energy Signals
|
||||
* @Return - CTR_Code - Error code (if any)
|
||||
*/
|
||||
CTR_Code PDP::ResetEnergy()
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint8_t pdpControl[] = { 0x40 }; /* only bit set is ResetEnergy */
|
||||
FRC_NetworkCommunication_CANSessionMux_sendMessage(CONTROL_1 | GetDeviceNumber(), pdpControl, sizeof(pdpControl), 0, &status);
|
||||
if(status)
|
||||
return CTR_TxFailed;
|
||||
return CTR_OKAY;
|
||||
}
|
||||
//------------------ C interface --------------------------------------------//
|
||||
extern "C" {
|
||||
void * c_PDP_Init(void)
|
||||
{
|
||||
return new PDP();
|
||||
}
|
||||
CTR_Code c_GetChannelCurrent(void * handle,UINT8 idx, double *status)
|
||||
{
|
||||
return ((PDP*)handle)-> GetChannelCurrent(idx,*status);
|
||||
}
|
||||
CTR_Code c_GetVoltage(void * handle,double *status)
|
||||
{
|
||||
return ((PDP*)handle)-> GetVoltage(*status);
|
||||
}
|
||||
CTR_Code c_GetTemperature(void * handle,double *status)
|
||||
{
|
||||
return ((PDP*)handle)-> GetTemperature(*status);
|
||||
}
|
||||
void c_SetDeviceNumber_PDP(void * handle,UINT8 deviceNumber)
|
||||
{
|
||||
}
|
||||
}
|
||||
156
hal/src/main/native/athena/frccansae/CANDeviceInterface.h
Normal file
156
hal/src/main/native/athena/frccansae/CANDeviceInterface.h
Normal file
@@ -0,0 +1,156 @@
|
||||
#ifndef __CAN_DEVICE_INTERFACE_H__
|
||||
#define __CAN_DEVICE_INTERFACE_H__
|
||||
|
||||
#define MAX_STRING_LEN 64
|
||||
|
||||
#define SUPPORT_UNIQUE_ID (1) /* depends entirely on old vs new build */
|
||||
#define USE_NTH_ORDER (0) /* zero to user deviceId */
|
||||
#define SUPPORT_MOTOR_CONTROLLER_PROFILE (1)
|
||||
namespace CANDeviceInterface1
|
||||
{
|
||||
|
||||
struct PIDSlot
|
||||
{
|
||||
// Proportional gain
|
||||
float pGain;
|
||||
// Integral gain
|
||||
float iGain;
|
||||
// Differential gain
|
||||
float dGain;
|
||||
// Feed-forward gain
|
||||
float fGain;
|
||||
// Integral zone
|
||||
float iZone;
|
||||
// Closed-loop ramp rate
|
||||
float clRampRate;
|
||||
};
|
||||
|
||||
struct DeviceDescriptor
|
||||
{
|
||||
// The full device ID, including the device number, manufacturer, and device type.
|
||||
// The mask of a message the device supports is 0x1FFF003F.
|
||||
unsigned int deviceID;
|
||||
#if SUPPORT_UNIQUE_ID != 0
|
||||
// This is the ID that uniquely identifies the device node in the UI.
|
||||
// The purpose of this is to be able to track the device across renames or deviceID changes.
|
||||
unsigned int uniqueID;
|
||||
#endif
|
||||
// An dynamically assigned ID that will make setting deviceIDs robust,
|
||||
// Never again will you need to isolate a CAN node just to fix it's ID.
|
||||
unsigned int dynamicID;
|
||||
// User visible name. This can be customized by the user, but should have a
|
||||
// reasonable default.
|
||||
char name[MAX_STRING_LEN];
|
||||
// This is a user visible model name that should match the can_devices.ini section.
|
||||
char model[MAX_STRING_LEN];
|
||||
// This is a version number that represents the version of firmware currently
|
||||
// installed on the device.
|
||||
char currentVersion[MAX_STRING_LEN];
|
||||
// Hardware revision.
|
||||
char hardwareRev[MAX_STRING_LEN];
|
||||
// Bootloader version. Will not change for the life of the product, but additional
|
||||
// field upgrade features could be added in newer hardware.
|
||||
char bootloaderRev[MAX_STRING_LEN];
|
||||
// Manufacture Date. Could be a calender date or just the FRC season year.
|
||||
// Also helps troubleshooting "old ones" vs "new ones".
|
||||
char manufactureDate[MAX_STRING_LEN];
|
||||
// General status of the hardware. For example if the device is in bootloader
|
||||
// due to a bad flash UI could emphasize that.
|
||||
char softwareStatus[MAX_STRING_LEN];
|
||||
// Is the LED currently on?
|
||||
bool led;
|
||||
// Reserved fields for future use by CTRE. Not touched by frccansae
|
||||
unsigned int dynFlags;
|
||||
unsigned int flags; /* bitfield */
|
||||
unsigned int ptrToString;
|
||||
//unsigned int reserved0;
|
||||
//unsigned int reserved1;
|
||||
//unsigned int reserved2;
|
||||
#if SUPPORT_MOTOR_CONTROLLER_PROFILE != 0
|
||||
// Motor controller properties (ignored if SupportsMotorControllerProperties is false or unset for this model)
|
||||
unsigned int brakeMode; // 0=Coast, 1=Brake
|
||||
unsigned int limitSwitchFwdMode; // 0=disabled, 1=Normally Closed, 2=Normally Open
|
||||
unsigned int limitSwitchRevMode; // 0=disabled, 1=Normally Closed, 2=Normally Open
|
||||
// Limit-switch soft limits
|
||||
bool bFwdSoftLimitEnable;
|
||||
bool bRevSoftLimitEnable;
|
||||
float softLimitFwd;
|
||||
float softLimitRev;
|
||||
// PID constants for slot 0
|
||||
struct PIDSlot slot0;
|
||||
// PID constants for slot 1
|
||||
struct PIDSlot slot1;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define kLimitSwitchMode_Disabled (0)
|
||||
#define kLimitSwitchMode_NormallyClosed (1)
|
||||
#define kLimitSwitchMode_NormallyOpen (2)
|
||||
|
||||
// Interface functions that must be implemented by the CAN Firmware Update Library
|
||||
|
||||
// Returns the number of devices that will be returned in a call to
|
||||
// getListOfDevices(). The calling library will use this info to allocate enough
|
||||
// memory to accept all device info.
|
||||
int getNumberOfDevices();
|
||||
|
||||
// Return info about discovered devices. The array of structs should be
|
||||
// populated before returning. The numDescriptors input describes how many
|
||||
// elements were allocated to prevent memory corruption. The number of devices
|
||||
// populated should be returned from this function as well.
|
||||
int getListOfDevices(DeviceDescriptor *devices, int numDescriptors);
|
||||
|
||||
// When the user requests to update the firmware of a device a thread will be
|
||||
// spawned and this function is called from that thread. This function should
|
||||
// complete the firmware update process before returning. The image
|
||||
// contents and size are directly from the file selected by the user. The
|
||||
// error message string can be filled with a NULL-terminated message to show the
|
||||
// user if there was a problem updating firmware. The error message is only
|
||||
// displayed if a non-zero value is returned from this function.
|
||||
int updateFirmware(const DeviceDescriptor *device, const unsigned char *imageContents, unsigned int imageSize, char *errorMessage, int errorMessageMaxSize);
|
||||
|
||||
// This function is called periodically from the UI thread while the firmware
|
||||
// update is in progress. The percentComplete parameter should the filled in
|
||||
// with the current progress of the firmware update process to update a progress
|
||||
// bar in the UI.
|
||||
void checkUpdateProgress(const DeviceDescriptor *device, int *percentComplete);
|
||||
|
||||
// This is called when the user selects a new ID to assign on the bus and
|
||||
// chooses to save. The newDeviceID is really just the device number. The
|
||||
// manufacturer and device type will remain unchanged. If a problem is detected
|
||||
// when assigning a new ID, this function should return a non-zero value.
|
||||
int assignBroadcastDeviceID(unsigned int newDeviceID);
|
||||
// The device descriptor should be updated with the new device ID. The name may
|
||||
// also change in the descriptor and will be updated in the UI immediately.
|
||||
// Be sure to modify the descriptor first since the refresh from the UI is
|
||||
// asynchronous.
|
||||
int assignDeviceID(DeviceDescriptor *device, unsigned int newDeviceID);
|
||||
|
||||
// This entry-point will get called when the user chooses to change the value
|
||||
// of the device's LED. This will allow the user to identify devices which
|
||||
// support dynamic addresses or are otherwise unknown. If this function returns
|
||||
// a non-zero value, the UI will report an error.
|
||||
int saveLightLed(const DeviceDescriptor *device, bool newLEDStatus);
|
||||
|
||||
// This entry-point will get called when the user chooses to change the alias
|
||||
// of the device with the device specified. If this function returns a non-
|
||||
// zero value, the UI will report an error. The device descriptor must be
|
||||
// updated with the new name that was selected. If a different name is saved
|
||||
// to the descriptor than the user specified, this will require a manual
|
||||
// refresh by the user. This is reported as CAR #505139
|
||||
int saveDeviceName(DeviceDescriptor *device, const char *newName);
|
||||
|
||||
// This entry-point will get called when the user changes any of the motor
|
||||
// controller specific properties. If this function returns a non-zero value,
|
||||
// the UI will report an error. The device descriptor may be updated with
|
||||
// coerced values.
|
||||
int saveMotorParameters(DeviceDescriptor *device);
|
||||
|
||||
// Run some sort of self-test functionality on the device. This can be anything
|
||||
// and the results will be displayed to the user. A non-zero return value
|
||||
// indicates an error.
|
||||
int selfTest(const DeviceDescriptor *device, char *detailedResults, int detailedResultsMaxSize);
|
||||
|
||||
} /* CANDeviceInterface */
|
||||
|
||||
#endif /* __CAN_DEVICE_INTERFACE_H__ */
|
||||
1064
hal/src/main/native/athena/visa/visa.h
Normal file
1064
hal/src/main/native/athena/visa/visa.h
Normal file
File diff suppressed because it is too large
Load Diff
201
hal/src/main/native/athena/visa/visatype.h
Normal file
201
hal/src/main/native/athena/visa/visatype.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Distributed by IVI Foundation Inc. */
|
||||
/* */
|
||||
/* Do not modify the contents of this file. */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Title : VISATYPE.H */
|
||||
/* Date : 04-14-2006 */
|
||||
/* Purpose : Fundamental VISA data types and macro definitions */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef __VISATYPE_HEADER__
|
||||
#define __VISATYPE_HEADER__
|
||||
|
||||
#if defined(_WIN64)
|
||||
#define _VI_FAR
|
||||
#define _VI_FUNC __fastcall
|
||||
#define _VI_FUNCC __fastcall
|
||||
#define _VI_FUNCH __fastcall
|
||||
#define _VI_SIGNED signed
|
||||
#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(_NI_mswin16_)
|
||||
#define _VI_FAR
|
||||
#define _VI_FUNC __stdcall
|
||||
#define _VI_FUNCC __cdecl
|
||||
#define _VI_FUNCH __stdcall
|
||||
#define _VI_SIGNED signed
|
||||
#elif defined(_CVI_) && defined(_NI_i386_)
|
||||
#define _VI_FAR
|
||||
#define _VI_FUNC _pascal
|
||||
#define _VI_FUNCC
|
||||
#define _VI_FUNCH _pascal
|
||||
#define _VI_SIGNED signed
|
||||
#elif (defined(_WINDOWS) || defined(_Windows)) && !defined(_NI_mswin16_)
|
||||
#define _VI_FAR _far
|
||||
#define _VI_FUNC _far _pascal _export
|
||||
#define _VI_FUNCC _far _cdecl _export
|
||||
#define _VI_FUNCH _far _pascal
|
||||
#define _VI_SIGNED signed
|
||||
#elif (defined(hpux) || defined(__hpux)) && (defined(__cplusplus) || defined(__cplusplus__))
|
||||
#define _VI_FAR
|
||||
#define _VI_FUNC
|
||||
#define _VI_FUNCC
|
||||
#define _VI_FUNCH
|
||||
#define _VI_SIGNED
|
||||
#else
|
||||
#define _VI_FAR
|
||||
#define _VI_FUNC
|
||||
#define _VI_FUNCC
|
||||
#define _VI_FUNCH
|
||||
#define _VI_SIGNED signed
|
||||
#endif
|
||||
|
||||
#define _VI_ERROR (-2147483647L-1) /* 0x80000000 */
|
||||
#define _VI_PTR _VI_FAR *
|
||||
|
||||
/*- VISA Types --------------------------------------------------------------*/
|
||||
|
||||
#ifndef _VI_INT64_UINT64_DEFINED
|
||||
#if defined(_WIN64) || ((defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(_NI_mswin16_))
|
||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1200)) || (defined(_CVI_) && (_CVI_ >= 700)) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0520))
|
||||
typedef unsigned __int64 ViUInt64;
|
||||
typedef _VI_SIGNED __int64 ViInt64;
|
||||
#define _VI_INT64_UINT64_DEFINED
|
||||
#if defined(_WIN64)
|
||||
#define _VISA_ENV_IS_64_BIT
|
||||
#else
|
||||
/* This is a 32-bit OS, not a 64-bit OS */
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
typedef u_int64_t ViUInt64;
|
||||
typedef int64_t ViInt64;
|
||||
#define _VI_INT64_UINT64_DEFINED
|
||||
#if defined(LONG_MAX) && (LONG_MAX > 0x7FFFFFFFL)
|
||||
#define _VISA_ENV_IS_64_BIT
|
||||
#else
|
||||
/* This is a 32-bit OS, not a 64-bit OS */
|
||||
#endif
|
||||
#else
|
||||
/* This platform does not support 64-bit types */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_VI_INT64_UINT64_DEFINED)
|
||||
typedef ViUInt64 _VI_PTR ViPUInt64;
|
||||
typedef ViUInt64 _VI_PTR ViAUInt64;
|
||||
typedef ViInt64 _VI_PTR ViPInt64;
|
||||
typedef ViInt64 _VI_PTR ViAInt64;
|
||||
#endif
|
||||
|
||||
#if defined(LONG_MAX) && (LONG_MAX > 0x7FFFFFFFL)
|
||||
typedef unsigned int ViUInt32;
|
||||
typedef _VI_SIGNED int ViInt32;
|
||||
#else
|
||||
typedef unsigned long ViUInt32;
|
||||
typedef _VI_SIGNED long ViInt32;
|
||||
#endif
|
||||
|
||||
typedef ViUInt32 _VI_PTR ViPUInt32;
|
||||
typedef ViUInt32 _VI_PTR ViAUInt32;
|
||||
typedef ViInt32 _VI_PTR ViPInt32;
|
||||
typedef ViInt32 _VI_PTR ViAInt32;
|
||||
|
||||
typedef unsigned short ViUInt16;
|
||||
typedef ViUInt16 _VI_PTR ViPUInt16;
|
||||
typedef ViUInt16 _VI_PTR ViAUInt16;
|
||||
|
||||
typedef _VI_SIGNED short ViInt16;
|
||||
typedef ViInt16 _VI_PTR ViPInt16;
|
||||
typedef ViInt16 _VI_PTR ViAInt16;
|
||||
|
||||
typedef unsigned char ViUInt8;
|
||||
typedef ViUInt8 _VI_PTR ViPUInt8;
|
||||
typedef ViUInt8 _VI_PTR ViAUInt8;
|
||||
|
||||
typedef _VI_SIGNED char ViInt8;
|
||||
typedef ViInt8 _VI_PTR ViPInt8;
|
||||
typedef ViInt8 _VI_PTR ViAInt8;
|
||||
|
||||
typedef char ViChar;
|
||||
typedef ViChar _VI_PTR ViPChar;
|
||||
typedef ViChar _VI_PTR ViAChar;
|
||||
|
||||
typedef unsigned char ViByte;
|
||||
typedef ViByte _VI_PTR ViPByte;
|
||||
typedef ViByte _VI_PTR ViAByte;
|
||||
|
||||
typedef void _VI_PTR ViAddr;
|
||||
typedef ViAddr _VI_PTR ViPAddr;
|
||||
typedef ViAddr _VI_PTR ViAAddr;
|
||||
|
||||
typedef float ViReal32;
|
||||
typedef ViReal32 _VI_PTR ViPReal32;
|
||||
typedef ViReal32 _VI_PTR ViAReal32;
|
||||
|
||||
typedef double ViReal64;
|
||||
typedef ViReal64 _VI_PTR ViPReal64;
|
||||
typedef ViReal64 _VI_PTR ViAReal64;
|
||||
|
||||
typedef ViPByte ViBuf;
|
||||
typedef ViPByte ViPBuf;
|
||||
typedef ViPByte _VI_PTR ViABuf;
|
||||
|
||||
typedef ViPChar ViString;
|
||||
typedef ViPChar ViPString;
|
||||
typedef ViPChar _VI_PTR ViAString;
|
||||
|
||||
typedef ViString ViRsrc;
|
||||
typedef ViString ViPRsrc;
|
||||
typedef ViString _VI_PTR ViARsrc;
|
||||
|
||||
typedef ViUInt16 ViBoolean;
|
||||
typedef ViBoolean _VI_PTR ViPBoolean;
|
||||
typedef ViBoolean _VI_PTR ViABoolean;
|
||||
|
||||
typedef ViInt32 ViStatus;
|
||||
typedef ViStatus _VI_PTR ViPStatus;
|
||||
typedef ViStatus _VI_PTR ViAStatus;
|
||||
|
||||
typedef ViUInt32 ViVersion;
|
||||
typedef ViVersion _VI_PTR ViPVersion;
|
||||
typedef ViVersion _VI_PTR ViAVersion;
|
||||
|
||||
typedef ViUInt32 ViObject;
|
||||
typedef ViObject _VI_PTR ViPObject;
|
||||
typedef ViObject _VI_PTR ViAObject;
|
||||
|
||||
typedef ViObject ViSession;
|
||||
typedef ViSession _VI_PTR ViPSession;
|
||||
typedef ViSession _VI_PTR ViASession;
|
||||
|
||||
typedef ViUInt32 ViAttr;
|
||||
|
||||
#ifndef _VI_CONST_STRING_DEFINED
|
||||
typedef const ViChar * ViConstString;
|
||||
#define _VI_CONST_STRING_DEFINED
|
||||
#endif
|
||||
|
||||
/*- Completion and Error Codes ----------------------------------------------*/
|
||||
|
||||
#define VI_SUCCESS (0L)
|
||||
|
||||
/*- Other VISA Definitions --------------------------------------------------*/
|
||||
|
||||
#define VI_NULL (0)
|
||||
|
||||
#define VI_TRUE (1)
|
||||
#define VI_FALSE (0)
|
||||
|
||||
/*- Backward Compatibility Macros -------------------------------------------*/
|
||||
|
||||
#define VISAFN _VI_FUNC
|
||||
#define ViPtr _VI_PTR
|
||||
|
||||
#endif
|
||||
|
||||
/*- The End -----------------------------------------------------------------*/
|
||||
|
||||
28
hal/src/main/native/include/HAL/Accelerometer.h
Normal file
28
hal/src/main/native/include/HAL/Accelerometer.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
enum HAL_AccelerometerRange : int32_t {
|
||||
HAL_AccelerometerRange_k2G = 0,
|
||||
HAL_AccelerometerRange_k4G = 1,
|
||||
HAL_AccelerometerRange_k8G = 2,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void HAL_SetAccelerometerActive(HAL_Bool active);
|
||||
void HAL_SetAccelerometerRange(HAL_AccelerometerRange range);
|
||||
double HAL_GetAccelerometerX(void);
|
||||
double HAL_GetAccelerometerY(void);
|
||||
double HAL_GetAccelerometerZ(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
36
hal/src/main/native/include/HAL/AnalogAccumulator.h
Normal file
36
hal/src/main/native/include/HAL/AnalogAccumulator.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_Bool HAL_IsAccumulatorChannel(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
void HAL_InitAccumulator(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
void HAL_ResetAccumulator(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetAccumulatorCenter(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t center, int32_t* status);
|
||||
void HAL_SetAccumulatorDeadband(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t deadband, int32_t* status);
|
||||
int64_t HAL_GetAccumulatorValue(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
int64_t HAL_GetAccumulatorCount(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
void HAL_GetAccumulatorOutput(HAL_AnalogInputHandle analogPortHandle,
|
||||
int64_t* value, int64_t* count, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
38
hal/src/main/native/include/HAL/AnalogGyro.h
Normal file
38
hal/src/main/native/include/HAL/AnalogGyro.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle handle,
|
||||
int32_t* status);
|
||||
void HAL_SetupAnalogGyro(HAL_GyroHandle handle, int32_t* status);
|
||||
void HAL_FreeAnalogGyro(HAL_GyroHandle handle);
|
||||
void HAL_SetAnalogGyroParameters(HAL_GyroHandle handle,
|
||||
double voltsPerDegreePerSecond, double offset,
|
||||
int32_t center, int32_t* status);
|
||||
void HAL_SetAnalogGyroVoltsPerDegreePerSecond(HAL_GyroHandle handle,
|
||||
double voltsPerDegreePerSecond,
|
||||
int32_t* status);
|
||||
void HAL_ResetAnalogGyro(HAL_GyroHandle handle, int32_t* status);
|
||||
void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status);
|
||||
void HAL_SetAnalogGyroDeadband(HAL_GyroHandle handle, double volts,
|
||||
int32_t* status);
|
||||
double HAL_GetAnalogGyroAngle(HAL_GyroHandle handle, int32_t* status);
|
||||
double HAL_GetAnalogGyroRate(HAL_GyroHandle handle, int32_t* status);
|
||||
double HAL_GetAnalogGyroOffset(HAL_GyroHandle handle, int32_t* status);
|
||||
int32_t HAL_GetAnalogGyroCenter(HAL_GyroHandle handle, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
50
hal/src/main/native/include/HAL/AnalogInput.h
Normal file
50
hal/src/main/native/include/HAL/AnalogInput.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle,
|
||||
int32_t* status);
|
||||
void HAL_FreeAnalogInputPort(HAL_AnalogInputHandle analogPortHandle);
|
||||
HAL_Bool HAL_CheckAnalogModule(int32_t module);
|
||||
HAL_Bool HAL_CheckAnalogInputChannel(int32_t channel);
|
||||
|
||||
void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status);
|
||||
double HAL_GetAnalogSampleRate(int32_t* status);
|
||||
void HAL_SetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t bits, int32_t* status);
|
||||
int32_t HAL_GetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t bits, int32_t* status);
|
||||
int32_t HAL_GetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetAnalogValue(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetAnalogAverageValue(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetAnalogVoltsToValue(HAL_AnalogInputHandle analogPortHandle,
|
||||
double voltage, int32_t* status);
|
||||
double HAL_GetAnalogVoltage(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
double HAL_GetAnalogAverageVoltage(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetAnalogLSBWeight(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetAnalogOffset(HAL_AnalogInputHandle analogPortHandle,
|
||||
int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
28
hal/src/main/native/include/HAL/AnalogOutput.h
Normal file
28
hal/src/main/native/include/HAL/AnalogOutput.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle,
|
||||
int32_t* status);
|
||||
void HAL_FreeAnalogOutputPort(HAL_AnalogOutputHandle analogOutputHandle);
|
||||
void HAL_SetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
|
||||
double voltage, int32_t* status);
|
||||
double HAL_GetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_CheckAnalogOutputChannel(int32_t channel);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
47
hal/src/main/native/include/HAL/AnalogTrigger.h
Normal file
47
hal/src/main/native/include/HAL/AnalogTrigger.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
enum HAL_AnalogTriggerType : int32_t {
|
||||
HAL_Trigger_kInWindow = 0,
|
||||
HAL_Trigger_kState = 1,
|
||||
HAL_Trigger_kRisingPulse = 2,
|
||||
HAL_Trigger_kFallingPulse = 3
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
|
||||
HAL_AnalogInputHandle portHandle, int32_t* index, int32_t* status);
|
||||
void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
int32_t lower, int32_t upper,
|
||||
int32_t* status);
|
||||
void HAL_SetAnalogTriggerLimitsVoltage(
|
||||
HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
|
||||
int32_t* status);
|
||||
void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
HAL_Bool useAveragedValue, int32_t* status);
|
||||
void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
HAL_Bool useFilteredValue, int32_t* status);
|
||||
HAL_Bool HAL_GetAnalogTriggerInWindow(
|
||||
HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status);
|
||||
HAL_Bool HAL_GetAnalogTriggerTriggerState(
|
||||
HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status);
|
||||
HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
|
||||
HAL_AnalogTriggerType type,
|
||||
int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
46
hal/src/main/native/include/HAL/ChipObject.h
Normal file
46
hal/src/main/native/include/HAL/ChipObject.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FRC_FPGA_ChipObject/RoboRIO_FRC_ChipObject_Aliases.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/nInterfaceGlobals.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAI.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAO.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAccel.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAccumulator.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAlarm.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAnalogTrigger.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tBIST.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tCounter.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tDIO.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tDMA.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tEncoder.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tGlobal.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tInterrupt.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tPWM.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tPower.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tRelay.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tSPI.h"
|
||||
#include "FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tSysWatchdog.h"
|
||||
#include "FRC_FPGA_ChipObject/tDMAChannelDescriptor.h"
|
||||
#include "FRC_FPGA_ChipObject/tDMAManager.h"
|
||||
#include "FRC_FPGA_ChipObject/tInterruptManager.h"
|
||||
#include "FRC_FPGA_ChipObject/tSystem.h"
|
||||
#include "FRC_FPGA_ChipObject/tSystemInterface.h"
|
||||
|
||||
namespace hal {
|
||||
using namespace nFPGA;
|
||||
using namespace nRoboRIO_FPGANamespace;
|
||||
} // namespace hal
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
48
hal/src/main/native/include/HAL/Compressor.h
Normal file
48
hal/src/main/native/include/HAL/Compressor.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_CompressorHandle HAL_InitializeCompressor(int32_t module, int32_t* status);
|
||||
HAL_Bool HAL_CheckCompressorModule(int32_t module);
|
||||
|
||||
HAL_Bool HAL_GetCompressor(HAL_CompressorHandle compressorHandle,
|
||||
int32_t* status);
|
||||
|
||||
void HAL_SetCompressorClosedLoopControl(HAL_CompressorHandle compressorHandle,
|
||||
HAL_Bool value, int32_t* status);
|
||||
HAL_Bool HAL_GetCompressorClosedLoopControl(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status);
|
||||
|
||||
HAL_Bool HAL_GetCompressorPressureSwitch(HAL_CompressorHandle compressorHandle,
|
||||
int32_t* status);
|
||||
double HAL_GetCompressorCurrent(HAL_CompressorHandle compressorHandle,
|
||||
int32_t* status);
|
||||
|
||||
HAL_Bool HAL_GetCompressorCurrentTooHighFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status);
|
||||
HAL_Bool HAL_GetCompressorCurrentTooHighStickyFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status);
|
||||
HAL_Bool HAL_GetCompressorShortedStickyFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status);
|
||||
HAL_Bool HAL_GetCompressorShortedFault(HAL_CompressorHandle compressorHandle,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_GetCompressorNotConnectedStickyFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status);
|
||||
HAL_Bool HAL_GetCompressorNotConnectedFault(
|
||||
HAL_CompressorHandle compressorHandle, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
19
hal/src/main/native/include/HAL/Constants.h
Normal file
19
hal/src/main/native/include/HAL/Constants.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int32_t HAL_GetSystemClockTicksPerMicrosecond(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
73
hal/src/main/native/include/HAL/Counter.h
Normal file
73
hal/src/main/native/include/HAL/Counter.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/AnalogTrigger.h"
|
||||
#include "HAL/Types.h"
|
||||
|
||||
enum HAL_Counter_Mode : int32_t {
|
||||
HAL_Counter_kTwoPulse = 0,
|
||||
HAL_Counter_kSemiperiod = 1,
|
||||
HAL_Counter_kPulseLength = 2,
|
||||
HAL_Counter_kExternalDirection = 3
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
HAL_CounterHandle HAL_InitializeCounter(HAL_Counter_Mode mode, int32_t* index,
|
||||
int32_t* status);
|
||||
void HAL_FreeCounter(HAL_CounterHandle counterHandle, int32_t* status);
|
||||
void HAL_SetCounterAverageSize(HAL_CounterHandle counterHandle, int32_t size,
|
||||
int32_t* status);
|
||||
void HAL_SetCounterUpSource(HAL_CounterHandle counterHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
int32_t* status);
|
||||
void HAL_SetCounterUpSourceEdge(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool risingEdge, HAL_Bool fallingEdge,
|
||||
int32_t* status);
|
||||
void HAL_ClearCounterUpSource(HAL_CounterHandle counterHandle, int32_t* status);
|
||||
void HAL_SetCounterDownSource(HAL_CounterHandle counterHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
int32_t* status);
|
||||
void HAL_SetCounterDownSourceEdge(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool risingEdge, HAL_Bool fallingEdge,
|
||||
int32_t* status);
|
||||
void HAL_ClearCounterDownSource(HAL_CounterHandle counterHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetCounterUpDownMode(HAL_CounterHandle counterHandle, int32_t* status);
|
||||
void HAL_SetCounterExternalDirectionMode(HAL_CounterHandle counterHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetCounterSemiPeriodMode(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool highSemiPeriod, int32_t* status);
|
||||
void HAL_SetCounterPulseLengthMode(HAL_CounterHandle counterHandle,
|
||||
double threshold, int32_t* status);
|
||||
int32_t HAL_GetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
|
||||
int32_t samplesToAverage, int32_t* status);
|
||||
void HAL_ResetCounter(HAL_CounterHandle counterHandle, int32_t* status);
|
||||
int32_t HAL_GetCounter(HAL_CounterHandle counterHandle, int32_t* status);
|
||||
double HAL_GetCounterPeriod(HAL_CounterHandle counterHandle, int32_t* status);
|
||||
void HAL_SetCounterMaxPeriod(HAL_CounterHandle counterHandle, double maxPeriod,
|
||||
int32_t* status);
|
||||
void HAL_SetCounterUpdateWhenEmpty(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool enabled, int32_t* status);
|
||||
HAL_Bool HAL_GetCounterStopped(HAL_CounterHandle counterHandle,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_GetCounterDirection(HAL_CounterHandle counterHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetCounterReverseDirection(HAL_CounterHandle counterHandle,
|
||||
HAL_Bool reverseDirection, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
45
hal/src/main/native/include/HAL/DIO.h
Normal file
45
hal/src/main/native/include/HAL/DIO.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
|
||||
HAL_Bool input, int32_t* status);
|
||||
HAL_Bool HAL_CheckDIOChannel(int32_t channel);
|
||||
void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle);
|
||||
HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status);
|
||||
void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status);
|
||||
void HAL_SetDigitalPWMRate(double rate, int32_t* status);
|
||||
void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
|
||||
double dutyCycle, int32_t* status);
|
||||
void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
|
||||
int32_t channel, int32_t* status);
|
||||
void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status);
|
||||
HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status);
|
||||
void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status);
|
||||
HAL_Bool HAL_IsAnyPulsing(int32_t* status);
|
||||
|
||||
void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status);
|
||||
void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status);
|
||||
int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
126
hal/src/main/native/include/HAL/DriverStation.h
Normal file
126
hal/src/main/native/include/HAL/DriverStation.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2013-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#define HAL_IO_CONFIG_DATA_SIZE 32
|
||||
#define HAL_SYS_STATUS_DATA_SIZE 44
|
||||
#define HAL_USER_STATUS_DATA_SIZE \
|
||||
(984 - HAL_IO_CONFIG_DATA_SIZE - HAL_SYS_STATUS_DATA_SIZE)
|
||||
|
||||
#define HALFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Input 17
|
||||
#define HALFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Output 18
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Header 19
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Extra1 20
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Vertices1 21
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Extra2 22
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Vertices2 23
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Joystick 24
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Custom 25
|
||||
|
||||
struct HAL_ControlWord {
|
||||
uint32_t enabled : 1;
|
||||
uint32_t autonomous : 1;
|
||||
uint32_t test : 1;
|
||||
uint32_t eStop : 1;
|
||||
uint32_t fmsAttached : 1;
|
||||
uint32_t dsAttached : 1;
|
||||
uint32_t control_reserved : 26;
|
||||
};
|
||||
|
||||
enum HAL_AllianceStationID : int32_t {
|
||||
HAL_AllianceStationID_kRed1,
|
||||
HAL_AllianceStationID_kRed2,
|
||||
HAL_AllianceStationID_kRed3,
|
||||
HAL_AllianceStationID_kBlue1,
|
||||
HAL_AllianceStationID_kBlue2,
|
||||
HAL_AllianceStationID_kBlue3,
|
||||
};
|
||||
|
||||
/* The maximum number of axes that will be stored in a single HALJoystickAxes
|
||||
* struct. This is used for allocating buffers, not bounds checking, since
|
||||
* there are usually less axes in practice.
|
||||
*/
|
||||
#define HAL_kMaxJoystickAxes 12
|
||||
#define HAL_kMaxJoystickPOVs 12
|
||||
|
||||
struct HAL_JoystickAxes {
|
||||
int16_t count;
|
||||
float axes[HAL_kMaxJoystickAxes];
|
||||
};
|
||||
|
||||
struct HAL_JoystickPOVs {
|
||||
int16_t count;
|
||||
int16_t povs[HAL_kMaxJoystickPOVs];
|
||||
};
|
||||
|
||||
struct HAL_JoystickButtons {
|
||||
uint32_t buttons;
|
||||
uint8_t count;
|
||||
};
|
||||
|
||||
struct HAL_JoystickDescriptor {
|
||||
uint8_t isXbox;
|
||||
uint8_t type;
|
||||
char name[256];
|
||||
uint8_t axisCount;
|
||||
uint8_t axisTypes[HAL_kMaxJoystickAxes];
|
||||
uint8_t buttonCount;
|
||||
uint8_t povCount;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int32_t HAL_SetErrorData(const char* errors, int32_t errorsLength,
|
||||
int32_t waitMs);
|
||||
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);
|
||||
|
||||
int32_t HAL_GetControlWord(HAL_ControlWord* controlWord);
|
||||
HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status);
|
||||
int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes);
|
||||
int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs);
|
||||
int32_t HAL_GetJoystickButtons(int32_t joystickNum,
|
||||
HAL_JoystickButtons* buttons);
|
||||
int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
|
||||
HAL_JoystickDescriptor* desc);
|
||||
HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum);
|
||||
int32_t HAL_GetJoystickType(int32_t joystickNum);
|
||||
char* HAL_GetJoystickName(int32_t joystickNum);
|
||||
void HAL_FreeJoystickName(char* name);
|
||||
int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis);
|
||||
int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
|
||||
int32_t leftRumble, int32_t rightRumble);
|
||||
double HAL_GetMatchTime(int32_t* status);
|
||||
|
||||
#ifndef HAL_USE_LABVIEW
|
||||
|
||||
void HAL_ReleaseDSMutex(void);
|
||||
bool HAL_IsNewControlData(void);
|
||||
void HAL_WaitForDSData(void);
|
||||
HAL_Bool HAL_WaitForDSDataTimeout(double timeout);
|
||||
void HAL_InitializeDriverStation(void);
|
||||
|
||||
void HAL_ObserveUserProgramStarting(void);
|
||||
void HAL_ObserveUserProgramDisabled(void);
|
||||
void HAL_ObserveUserProgramAutonomous(void);
|
||||
void HAL_ObserveUserProgramTeleop(void);
|
||||
void HAL_ObserveUserProgramTest(void);
|
||||
|
||||
#endif // HAL_USE_LABVIEW
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
79
hal/src/main/native/include/HAL/Encoder.h
Normal file
79
hal/src/main/native/include/HAL/Encoder.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/AnalogTrigger.h"
|
||||
#include "HAL/Types.h"
|
||||
|
||||
enum HAL_EncoderIndexingType : int32_t {
|
||||
HAL_kResetWhileHigh,
|
||||
HAL_kResetWhileLow,
|
||||
HAL_kResetOnFallingEdge,
|
||||
HAL_kResetOnRisingEdge
|
||||
};
|
||||
enum HAL_EncoderEncodingType : int32_t {
|
||||
HAL_Encoder_k1X,
|
||||
HAL_Encoder_k2X,
|
||||
HAL_Encoder_k4X
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
HAL_EncoderHandle HAL_InitializeEncoder(
|
||||
HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
|
||||
HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
|
||||
HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
|
||||
int32_t* status);
|
||||
void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
|
||||
int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
|
||||
int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status);
|
||||
int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status);
|
||||
void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
|
||||
double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status);
|
||||
void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status);
|
||||
double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle, int32_t* status);
|
||||
double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status);
|
||||
void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
|
||||
int32_t* status);
|
||||
void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
|
||||
double distancePerPulse, int32_t* status);
|
||||
void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
|
||||
HAL_Bool reverseDirection, int32_t* status);
|
||||
void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
|
||||
int32_t samplesToAverage, int32_t* status);
|
||||
int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status);
|
||||
|
||||
void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
HAL_EncoderIndexingType type, int32_t* status);
|
||||
|
||||
int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status);
|
||||
|
||||
double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status);
|
||||
|
||||
double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
|
||||
int32_t* status);
|
||||
|
||||
HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
|
||||
HAL_EncoderHandle encoderHandle, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
117
hal/src/main/native/include/HAL/Errors.h
Normal file
117
hal/src/main/native/include/HAL/Errors.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CTR_RxTimeout_MESSAGE "CTRE CAN Receive Timeout"
|
||||
#define CTR_TxTimeout_MESSAGE "CTRE CAN Transmit Timeout"
|
||||
#define CTR_InvalidParamValue_MESSAGE "CTRE CAN Invalid Parameter"
|
||||
#define CTR_UnexpectedArbId_MESSAGE \
|
||||
"CTRE Unexpected Arbitration ID (CAN Node ID)"
|
||||
#define CTR_TxFailed_MESSAGE "CTRE CAN Transmit Error"
|
||||
#define CTR_SigNotUpdated_MESSAGE "CTRE CAN Signal Not Updated"
|
||||
|
||||
#define NiFpga_Status_FifoTimeout_MESSAGE "NIFPGA: FIFO timeout error"
|
||||
#define NiFpga_Status_TransferAborted_MESSAGE "NIFPGA: Transfer aborted error"
|
||||
#define NiFpga_Status_MemoryFull_MESSAGE \
|
||||
"NIFPGA: Memory Allocation failed, memory full"
|
||||
#define NiFpga_Status_SoftwareFault_MESSAGE "NIFPGA: Unexpected software error"
|
||||
#define NiFpga_Status_InvalidParameter_MESSAGE "NIFPGA: Invalid Parameter"
|
||||
#define NiFpga_Status_ResourceNotFound_MESSAGE "NIFPGA: Resource not found"
|
||||
#define NiFpga_Status_ResourceNotInitialized_MESSAGE \
|
||||
"NIFPGA: Resource not initialized"
|
||||
#define NiFpga_Status_HardwareFault_MESSAGE "NIFPGA: Hardware Fault"
|
||||
#define NiFpga_Status_IrqTimeout_MESSAGE "NIFPGA: Interrupt timeout"
|
||||
|
||||
#define ERR_CANSessionMux_InvalidBuffer_MESSAGE "CAN: Invalid Buffer"
|
||||
#define ERR_CANSessionMux_MessageNotFound_MESSAGE "CAN: Message not found"
|
||||
#define WARN_CANSessionMux_NoToken_MESSAGE "CAN: No token"
|
||||
#define ERR_CANSessionMux_NotAllowed_MESSAGE "CAN: Not allowed"
|
||||
#define ERR_CANSessionMux_NotInitialized_MESSAGE "CAN: Not initialized"
|
||||
|
||||
#define SAMPLE_RATE_TOO_HIGH 1001
|
||||
#define SAMPLE_RATE_TOO_HIGH_MESSAGE \
|
||||
"HAL: Analog module sample rate is too high"
|
||||
#define VOLTAGE_OUT_OF_RANGE 1002
|
||||
#define VOLTAGE_OUT_OF_RANGE_MESSAGE \
|
||||
"HAL: Voltage to convert to raw value is out of range [0; 5]"
|
||||
#define LOOP_TIMING_ERROR 1004
|
||||
#define LOOP_TIMING_ERROR_MESSAGE \
|
||||
"HAL: Digital module loop timing is not the expected value"
|
||||
#define SPI_WRITE_NO_MOSI 1012
|
||||
#define SPI_WRITE_NO_MOSI_MESSAGE \
|
||||
"HAL: Cannot write to SPI port with no MOSI output"
|
||||
#define SPI_READ_NO_MISO 1013
|
||||
#define SPI_READ_NO_MISO_MESSAGE \
|
||||
"HAL: Cannot read from SPI port with no MISO input"
|
||||
#define SPI_READ_NO_DATA 1014
|
||||
#define SPI_READ_NO_DATA_MESSAGE "HAL: No data available to read from SPI"
|
||||
#define INCOMPATIBLE_STATE 1015
|
||||
#define INCOMPATIBLE_STATE_MESSAGE \
|
||||
"HAL: Incompatible State: The operation cannot be completed"
|
||||
#define NO_AVAILABLE_RESOURCES -1004
|
||||
#define NO_AVAILABLE_RESOURCES_MESSAGE "HAL: No available resources to allocate"
|
||||
#define NULL_PARAMETER -1005
|
||||
#define NULL_PARAMETER_MESSAGE "HAL: A pointer parameter to a method is NULL"
|
||||
#define ANALOG_TRIGGER_LIMIT_ORDER_ERROR -1010
|
||||
#define ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE \
|
||||
"HAL: AnalogTrigger limits error. Lower limit > Upper Limit"
|
||||
#define ANALOG_TRIGGER_PULSE_OUTPUT_ERROR -1011
|
||||
#define ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE \
|
||||
"HAL: Attempted to read AnalogTrigger pulse output."
|
||||
#define PARAMETER_OUT_OF_RANGE -1028
|
||||
#define PARAMETER_OUT_OF_RANGE_MESSAGE "HAL: A parameter is out of range."
|
||||
#define RESOURCE_IS_ALLOCATED -1029
|
||||
#define RESOURCE_IS_ALLOCATED_MESSAGE "HAL: Resource already allocated"
|
||||
#define RESOURCE_OUT_OF_RANGE -1030
|
||||
#define RESOURCE_OUT_OF_RANGE_MESSAGE \
|
||||
"HAL: The requested resource is out of range."
|
||||
#define HAL_INVALID_ACCUMULATOR_CHANNEL -1035
|
||||
#define HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE \
|
||||
"HAL: The requested input is not an accumulator channel"
|
||||
#define HAL_COUNTER_NOT_SUPPORTED -1058
|
||||
#define HAL_COUNTER_NOT_SUPPORTED_MESSAGE \
|
||||
"HAL: Counter mode not supported for encoder method"
|
||||
#define HAL_PWM_SCALE_ERROR -1072
|
||||
#define HAL_PWM_SCALE_ERROR_MESSAGE \
|
||||
"HAL: The PWM Scale Factors are out of range"
|
||||
#define HAL_HANDLE_ERROR -1098
|
||||
#define HAL_HANDLE_ERROR_MESSAGE \
|
||||
"HAL: A handle parameter was passed incorrectly"
|
||||
|
||||
#define HAL_SERIAL_PORT_NOT_FOUND -1123
|
||||
#define HAL_SERIAL_PORT_NOT_FOUND_MESSAGE \
|
||||
"HAL: The specified serial port device was not found"
|
||||
|
||||
#define HAL_SERIAL_PORT_OPEN_ERROR -1124
|
||||
#define HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE \
|
||||
"HAL: The serial port could not be opened"
|
||||
|
||||
#define HAL_SERIAL_PORT_ERROR -1125
|
||||
#define HAL_SERIAL_PORT_ERROR_MESSAGE \
|
||||
"HAL: There was an error on the serial port"
|
||||
|
||||
#define HAL_THREAD_PRIORITY_ERROR -1152
|
||||
#define HAL_THREAD_PRIORITY_ERROR_MESSAGE \
|
||||
"HAL: Getting or setting the priority of a thread has failed";
|
||||
|
||||
#define HAL_THREAD_PRIORITY_RANGE_ERROR -1153
|
||||
#define HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE \
|
||||
"HAL: The priority requested to be set is invalid"
|
||||
|
||||
#define VI_ERROR_SYSTEM_ERROR_MESSAGE "HAL - VISA: System Error";
|
||||
#define VI_ERROR_INV_OBJECT_MESSAGE "HAL - VISA: Invalid Object"
|
||||
#define VI_ERROR_RSRC_LOCKED_MESSAGE "HAL - VISA: Resource Locked"
|
||||
#define VI_ERROR_RSRC_NFOUND_MESSAGE "HAL - VISA: Resource Not Found"
|
||||
#define VI_ERROR_INV_RSRC_NAME_MESSAGE "HAL - VISA: Invalid Resource Name"
|
||||
#define VI_ERROR_QUEUE_OVERFLOW_MESSAGE "HAL - VISA: Queue Overflow"
|
||||
#define VI_ERROR_IO_MESSAGE "HAL - VISA: General IO Error"
|
||||
#define VI_ERROR_ASRL_PARITY_MESSAGE "HAL - VISA: Parity Error"
|
||||
#define VI_ERROR_ASRL_FRAMING_MESSAGE "HAL - VISA: Framing Error"
|
||||
#define VI_ERROR_ASRL_OVERRUN_MESSAGE "HAL - VISA: Buffer Overrun Error"
|
||||
#define VI_ERROR_RSRC_BUSY_MESSAGE "HAL - VISA: Resource Busy"
|
||||
#define VI_ERROR_INV_PARAMETER_MESSAGE "HAL - VISA: Invalid Parameter"
|
||||
85
hal/src/main/native/include/HAL/HAL.h
Normal file
85
hal/src/main/native/include/HAL/HAL.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2013-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef HAL_USE_LABVIEW
|
||||
|
||||
#include "HAL/Accelerometer.h"
|
||||
#include "HAL/AnalogAccumulator.h"
|
||||
#include "HAL/AnalogGyro.h"
|
||||
#include "HAL/AnalogInput.h"
|
||||
#include "HAL/AnalogOutput.h"
|
||||
#include "HAL/AnalogTrigger.h"
|
||||
#include "HAL/Compressor.h"
|
||||
#include "HAL/Constants.h"
|
||||
#include "HAL/Counter.h"
|
||||
#include "HAL/DIO.h"
|
||||
#include "HAL/DriverStation.h"
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/I2C.h"
|
||||
#include "HAL/Interrupts.h"
|
||||
#include "HAL/Notifier.h"
|
||||
#include "HAL/PDP.h"
|
||||
#include "HAL/PWM.h"
|
||||
#include "HAL/Ports.h"
|
||||
#include "HAL/Power.h"
|
||||
#include "HAL/Relay.h"
|
||||
#include "HAL/SPI.h"
|
||||
#include "HAL/SerialPort.h"
|
||||
#include "HAL/Solenoid.h"
|
||||
|
||||
#endif // HAL_USE_LABVIEW
|
||||
|
||||
#include "HAL/Types.h"
|
||||
#include "UsageReporting.h"
|
||||
|
||||
namespace HALUsageReporting = nUsageReporting;
|
||||
|
||||
enum HAL_RuntimeType : int32_t { HAL_Athena, HAL_Mock };
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const char* HAL_GetErrorMessage(int32_t code);
|
||||
|
||||
int32_t HAL_GetFPGAVersion(int32_t* status);
|
||||
int64_t HAL_GetFPGARevision(int32_t* status);
|
||||
|
||||
HAL_RuntimeType HAL_GetRuntimeType();
|
||||
HAL_Bool HAL_GetFPGAButton(int32_t* status);
|
||||
|
||||
HAL_Bool HAL_GetSystemActive(int32_t* status);
|
||||
HAL_Bool HAL_GetBrownedOut(int32_t* status);
|
||||
|
||||
void HAL_BaseInitialize(int32_t* status);
|
||||
|
||||
#ifndef HAL_USE_LABVIEW
|
||||
|
||||
HAL_PortHandle HAL_GetPort(int32_t channel);
|
||||
HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel);
|
||||
|
||||
uint64_t HAL_GetFPGATime(int32_t* status);
|
||||
|
||||
HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode);
|
||||
|
||||
// ifdef's definition is to allow for default parameters in C++.
|
||||
#ifdef __cplusplus
|
||||
int64_t HAL_Report(int32_t resource, int32_t instanceNumber,
|
||||
int32_t context = 0, const char* feature = nullptr);
|
||||
#else
|
||||
int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
|
||||
const char* feature);
|
||||
#endif
|
||||
|
||||
#endif // HAL_USE_LABVIEW
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
29
hal/src/main/native/include/HAL/I2C.h
Normal file
29
hal/src/main/native/include/HAL/I2C.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum HAL_I2CPort : int32_t { HAL_I2C_kOnboard = 0, HAL_I2C_kMXP };
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status);
|
||||
int32_t HAL_TransactionI2C(HAL_I2CPort port, int32_t deviceAddress,
|
||||
uint8_t* dataToSend, int32_t sendSize,
|
||||
uint8_t* dataReceived, int32_t receiveSize);
|
||||
int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress,
|
||||
uint8_t* dataToSend, int32_t sendSize);
|
||||
int32_t HAL_ReadI2C(HAL_I2CPort port, int32_t deviceAddress, uint8_t* buffer,
|
||||
int32_t count);
|
||||
void HAL_CloseI2C(HAL_I2CPort port);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
50
hal/src/main/native/include/HAL/Interrupts.h
Normal file
50
hal/src/main/native/include/HAL/Interrupts.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/AnalogTrigger.h"
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*HAL_InterruptHandlerFunction)(uint32_t interruptAssertedMask,
|
||||
void* param);
|
||||
|
||||
HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher, int32_t* status);
|
||||
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
|
||||
|
||||
int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
|
||||
double timeout, HAL_Bool ignorePrevious,
|
||||
int32_t* status);
|
||||
void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
|
||||
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status);
|
||||
double HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status);
|
||||
double HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status);
|
||||
void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
HAL_Handle digitalSourceHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
int32_t* status);
|
||||
void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status);
|
||||
void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status);
|
||||
void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
|
||||
HAL_Bool risingEdge, HAL_Bool fallingEdge,
|
||||
int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
14
hal/src/main/native/include/HAL/LabVIEW/HAL.h
Normal file
14
hal/src/main/native/include/HAL/LabVIEW/HAL.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define HAL_USE_LABVIEW
|
||||
|
||||
#include "HAL/DriverStation.h"
|
||||
#include "HAL/HAL.h"
|
||||
#include "HAL/Types.h"
|
||||
30
hal/src/main/native/include/HAL/Notifier.h
Normal file
30
hal/src/main/native/include/HAL/Notifier.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*HAL_NotifierProcessFunction)(uint64_t currentTime,
|
||||
HAL_NotifierHandle handle);
|
||||
|
||||
HAL_NotifierHandle HAL_InitializeNotifier(HAL_NotifierProcessFunction process,
|
||||
void* param, int32_t* status);
|
||||
void HAL_CleanNotifier(HAL_NotifierHandle notifierHandle, int32_t* status);
|
||||
void* HAL_GetNotifierParam(HAL_NotifierHandle notifierHandle, int32_t* status);
|
||||
void HAL_UpdateNotifierAlarm(HAL_NotifierHandle notifierHandle,
|
||||
uint64_t triggerTime, int32_t* status);
|
||||
void HAL_StopNotifierAlarm(HAL_NotifierHandle notifierHandle, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
50
hal/src/main/native/include/HAL/OSSerialPort.h
Normal file
50
hal/src/main/native/include/HAL/OSSerialPort.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "SerialPort.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HAL_InitializeOSSerialPort(HAL_SerialPort port, int32_t* status);
|
||||
void HAL_SetOSSerialBaudRate(HAL_SerialPort port, int32_t baud,
|
||||
int32_t* status);
|
||||
void HAL_SetOSSerialDataBits(HAL_SerialPort port, int32_t bits,
|
||||
int32_t* status);
|
||||
void HAL_SetOSSerialParity(HAL_SerialPort port, int32_t parity,
|
||||
int32_t* status);
|
||||
void HAL_SetOSSerialStopBits(HAL_SerialPort port, int32_t stopBits,
|
||||
int32_t* status);
|
||||
void HAL_SetOSSerialWriteMode(HAL_SerialPort port, int32_t mode,
|
||||
int32_t* status);
|
||||
void HAL_SetOSSerialFlowControl(HAL_SerialPort port, int32_t flow,
|
||||
int32_t* status);
|
||||
void HAL_SetOSSerialTimeout(HAL_SerialPort port, double timeout,
|
||||
int32_t* status);
|
||||
void HAL_EnableOSSerialTermination(HAL_SerialPort port, char terminator,
|
||||
int32_t* status);
|
||||
void HAL_DisableOSSerialTermination(HAL_SerialPort port, int32_t* status);
|
||||
void HAL_SetOSSerialReadBufferSize(HAL_SerialPort port, int32_t size,
|
||||
int32_t* status);
|
||||
void HAL_SetOSSerialWriteBufferSize(HAL_SerialPort port, int32_t size,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetOSSerialBytesReceived(HAL_SerialPort port, int32_t* status);
|
||||
int32_t HAL_ReadOSSerial(HAL_SerialPort port, char* buffer, int32_t count,
|
||||
int32_t* status);
|
||||
int32_t HAL_WriteOSSerial(HAL_SerialPort port, const char* buffer,
|
||||
int32_t count, int32_t* status);
|
||||
void HAL_FlushOSSerial(HAL_SerialPort port, int32_t* status);
|
||||
void HAL_ClearOSSerial(HAL_SerialPort port, int32_t* status);
|
||||
void HAL_CloseOSSerial(HAL_SerialPort port, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
32
hal/src/main/native/include/HAL/PDP.h
Normal file
32
hal/src/main/native/include/HAL/PDP.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HAL_InitializePDP(int32_t module, int32_t* status);
|
||||
HAL_Bool HAL_CheckPDPChannel(int32_t channel);
|
||||
HAL_Bool HAL_CheckPDPModule(int32_t module);
|
||||
double HAL_GetPDPTemperature(int32_t module, int32_t* status);
|
||||
double HAL_GetPDPVoltage(int32_t module, int32_t* status);
|
||||
double HAL_GetPDPChannelCurrent(int32_t module, int32_t channel,
|
||||
int32_t* status);
|
||||
double HAL_GetPDPTotalCurrent(int32_t module, int32_t* status);
|
||||
double HAL_GetPDPTotalPower(int32_t module, int32_t* status);
|
||||
double HAL_GetPDPTotalEnergy(int32_t module, int32_t* status);
|
||||
void HAL_ResetPDPTotalEnergy(int32_t module, int32_t* status);
|
||||
void HAL_ClearPDPStickyFaults(int32_t module, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
55
hal/src/main/native/include/HAL/PWM.h
Normal file
55
hal/src/main/native/include/HAL/PWM.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
|
||||
int32_t* status);
|
||||
void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status);
|
||||
|
||||
HAL_Bool HAL_CheckPWMChannel(int32_t channel);
|
||||
|
||||
void HAL_SetPWMConfig(HAL_DigitalHandle pwmPortHandle, double maxPwm,
|
||||
double deadbandMaxPwm, double centerPwm,
|
||||
double deadbandMinPwm, double minPwm, int32_t* status);
|
||||
void HAL_SetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t maxPwm,
|
||||
int32_t deadbandMaxPwm, int32_t centerPwm,
|
||||
int32_t deadbandMinPwm, int32_t minPwm,
|
||||
int32_t* status);
|
||||
void HAL_GetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t* maxPwm,
|
||||
int32_t* deadbandMaxPwm, int32_t* centerPwm,
|
||||
int32_t* deadbandMinPwm, int32_t* minPwm,
|
||||
int32_t* status);
|
||||
void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
|
||||
HAL_Bool eliminateDeadband, int32_t* status);
|
||||
HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
|
||||
int32_t* status);
|
||||
void HAL_SetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t value,
|
||||
int32_t* status);
|
||||
void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
|
||||
int32_t* status);
|
||||
void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double position,
|
||||
int32_t* status);
|
||||
void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status);
|
||||
int32_t HAL_GetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t* status);
|
||||
double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status);
|
||||
double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status);
|
||||
void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status);
|
||||
void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetLoopTiming(int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
36
hal/src/main/native/include/HAL/Ports.h
Normal file
36
hal/src/main/native/include/HAL/Ports.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int32_t HAL_GetNumAccumulators(void);
|
||||
int32_t HAL_GetNumAnalogTriggers(void);
|
||||
int32_t HAL_GetNumAnalogInputs(void);
|
||||
int32_t HAL_GetNumAnalogOutputs(void);
|
||||
int32_t HAL_GetNumCounters(void);
|
||||
int32_t HAL_GetNumDigitalHeaders(void);
|
||||
int32_t HAL_GetNumPWMHeaders(void);
|
||||
int32_t HAL_GetNumDigitalChannels(void);
|
||||
int32_t HAL_GetNumPWMChannels(void);
|
||||
int32_t HAL_GetNumDigitalPWMOutputs(void);
|
||||
int32_t HAL_GetNumEncoders(void);
|
||||
int32_t HAL_GetNumInterrupts(void);
|
||||
int32_t HAL_GetNumRelayChannels(void);
|
||||
int32_t HAL_GetNumRelayHeaders(void);
|
||||
int32_t HAL_GetNumPCMModules(void);
|
||||
int32_t HAL_GetNumSolenoidChannels(void);
|
||||
int32_t HAL_GetNumPDPModules(void);
|
||||
int32_t HAL_GetNumPDPChannels(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
34
hal/src/main/native/include/HAL/Power.h
Normal file
34
hal/src/main/native/include/HAL/Power.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
double HAL_GetVinVoltage(int32_t* status);
|
||||
double HAL_GetVinCurrent(int32_t* status);
|
||||
double HAL_GetUserVoltage6V(int32_t* status);
|
||||
double HAL_GetUserCurrent6V(int32_t* status);
|
||||
HAL_Bool HAL_GetUserActive6V(int32_t* status);
|
||||
int32_t HAL_GetUserCurrentFaults6V(int32_t* status);
|
||||
double HAL_GetUserVoltage5V(int32_t* status);
|
||||
double HAL_GetUserCurrent5V(int32_t* status);
|
||||
HAL_Bool HAL_GetUserActive5V(int32_t* status);
|
||||
int32_t HAL_GetUserCurrentFaults5V(int32_t* status);
|
||||
double HAL_GetUserVoltage3V3(int32_t* status);
|
||||
double HAL_GetUserCurrent3V3(int32_t* status);
|
||||
HAL_Bool HAL_GetUserActive3V3(int32_t* status);
|
||||
int32_t HAL_GetUserCurrentFaults3V3(int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
29
hal/src/main/native/include/HAL/Relay.h
Normal file
29
hal/src/main/native/include/HAL/Relay.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
|
||||
int32_t* status);
|
||||
void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle);
|
||||
|
||||
HAL_Bool HAL_CheckRelayChannel(int32_t channel);
|
||||
|
||||
void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
|
||||
int32_t* status);
|
||||
HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
59
hal/src/main/native/include/HAL/SPI.h
Normal file
59
hal/src/main/native/include/HAL/SPI.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
enum HAL_SPIPort : int32_t {
|
||||
HAL_SPI_kOnboardCS0 = 0,
|
||||
HAL_SPI_kOnboardCS1,
|
||||
HAL_SPI_kOnboardCS2,
|
||||
HAL_SPI_kOnboardCS3,
|
||||
HAL_SPI_kMXP
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status);
|
||||
int32_t HAL_TransactionSPI(HAL_SPIPort port, uint8_t* dataToSend,
|
||||
uint8_t* dataReceived, int32_t size);
|
||||
int32_t HAL_WriteSPI(HAL_SPIPort port, uint8_t* dataToSend, int32_t sendSize);
|
||||
int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count);
|
||||
void HAL_CloseSPI(HAL_SPIPort port);
|
||||
void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed);
|
||||
void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst,
|
||||
HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh);
|
||||
void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status);
|
||||
void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status);
|
||||
int32_t HAL_GetSPIHandle(HAL_SPIPort port);
|
||||
void HAL_SetSPIHandle(HAL_SPIPort port, int32_t handle);
|
||||
|
||||
void HAL_InitSPIAccumulator(HAL_SPIPort port, int32_t period, int32_t cmd,
|
||||
int32_t xferSize, int32_t validMask,
|
||||
int32_t validValue, int32_t dataShift,
|
||||
int32_t dataSize, HAL_Bool isSigned,
|
||||
HAL_Bool bigEndian, int32_t* status);
|
||||
void HAL_FreeSPIAccumulator(HAL_SPIPort port, int32_t* status);
|
||||
void HAL_ResetSPIAccumulator(HAL_SPIPort port, int32_t* status);
|
||||
void HAL_SetSPIAccumulatorCenter(HAL_SPIPort port, int32_t center,
|
||||
int32_t* status);
|
||||
void HAL_SetSPIAccumulatorDeadband(HAL_SPIPort port, int32_t deadband,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetSPIAccumulatorLastValue(HAL_SPIPort port, int32_t* status);
|
||||
int64_t HAL_GetSPIAccumulatorValue(HAL_SPIPort port, int32_t* status);
|
||||
int64_t HAL_GetSPIAccumulatorCount(HAL_SPIPort port, int32_t* status);
|
||||
double HAL_GetSPIAccumulatorAverage(HAL_SPIPort port, int32_t* status);
|
||||
void HAL_GetSPIAccumulatorOutput(HAL_SPIPort port, int64_t* value,
|
||||
int64_t* count, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
50
hal/src/main/native/include/HAL/SerialPort.h
Normal file
50
hal/src/main/native/include/HAL/SerialPort.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum HAL_SerialPort : int32_t {
|
||||
HAL_SerialPort_Onboard = 0,
|
||||
HAL_SerialPort_MXP = 1,
|
||||
HAL_SerialPort_USB1 = 2,
|
||||
HAL_SerialPort_USB2 = 3
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HAL_InitializeSerialPort(HAL_SerialPort port, int32_t* status);
|
||||
void HAL_SetSerialBaudRate(HAL_SerialPort port, int32_t baud, int32_t* status);
|
||||
void HAL_SetSerialDataBits(HAL_SerialPort port, int32_t bits, int32_t* status);
|
||||
void HAL_SetSerialParity(HAL_SerialPort port, int32_t parity, int32_t* status);
|
||||
void HAL_SetSerialStopBits(HAL_SerialPort port, int32_t stopBits,
|
||||
int32_t* status);
|
||||
void HAL_SetSerialWriteMode(HAL_SerialPort port, int32_t mode, int32_t* status);
|
||||
void HAL_SetSerialFlowControl(HAL_SerialPort port, int32_t flow,
|
||||
int32_t* status);
|
||||
void HAL_SetSerialTimeout(HAL_SerialPort port, double timeout, int32_t* status);
|
||||
void HAL_EnableSerialTermination(HAL_SerialPort port, char terminator,
|
||||
int32_t* status);
|
||||
void HAL_DisableSerialTermination(HAL_SerialPort port, int32_t* status);
|
||||
void HAL_SetSerialReadBufferSize(HAL_SerialPort port, int32_t size,
|
||||
int32_t* status);
|
||||
void HAL_SetSerialWriteBufferSize(HAL_SerialPort port, int32_t size,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetSerialBytesReceived(HAL_SerialPort port, int32_t* status);
|
||||
int32_t HAL_ReadSerial(HAL_SerialPort port, char* buffer, int32_t count,
|
||||
int32_t* status);
|
||||
int32_t HAL_WriteSerial(HAL_SerialPort port, const char* buffer, int32_t count,
|
||||
int32_t* status);
|
||||
void HAL_FlushSerial(HAL_SerialPort port, int32_t* status);
|
||||
void HAL_ClearSerial(HAL_SerialPort port, int32_t* status);
|
||||
void HAL_CloseSerial(HAL_SerialPort port, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
35
hal/src/main/native/include/HAL/Solenoid.h
Normal file
35
hal/src/main/native/include/HAL/Solenoid.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle,
|
||||
int32_t* status);
|
||||
void HAL_FreeSolenoidPort(HAL_SolenoidHandle solenoidPortHandle);
|
||||
HAL_Bool HAL_CheckSolenoidModule(int32_t module);
|
||||
HAL_Bool HAL_CheckSolenoidChannel(int32_t channel);
|
||||
HAL_Bool HAL_GetSolenoid(HAL_SolenoidHandle solenoidPortHandle,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetAllSolenoids(int32_t module, int32_t* status);
|
||||
void HAL_SetSolenoid(HAL_SolenoidHandle solenoidPortHandle, HAL_Bool value,
|
||||
int32_t* status);
|
||||
void HAL_SetAllSolenoids(int32_t module, int32_t state, int32_t* status);
|
||||
int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status);
|
||||
HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status);
|
||||
HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status);
|
||||
void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
28
hal/src/main/native/include/HAL/Threads.h
Normal file
28
hal/src/main/native/include/HAL/Threads.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#define NativeThreadHandle const HANDLE*
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#define NativeThreadHandle const pthread_t*
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
int32_t HAL_GetThreadPriority(NativeThreadHandle handle, HAL_Bool* isRealTime,
|
||||
int32_t* status);
|
||||
int32_t HAL_GetCurrentThreadPriority(HAL_Bool* isRealTime, int32_t* status);
|
||||
HAL_Bool HAL_SetThreadPriority(NativeThreadHandle handle, HAL_Bool realTime,
|
||||
int32_t priority, int32_t* status);
|
||||
HAL_Bool HAL_SetCurrentThreadPriority(HAL_Bool realTime, int32_t priority,
|
||||
int32_t* status);
|
||||
}
|
||||
46
hal/src/main/native/include/HAL/Types.h
Normal file
46
hal/src/main/native/include/HAL/Types.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define HAL_kInvalidHandle 0
|
||||
|
||||
typedef int32_t HAL_Handle;
|
||||
|
||||
typedef HAL_Handle HAL_PortHandle;
|
||||
|
||||
typedef HAL_Handle HAL_AnalogInputHandle;
|
||||
|
||||
typedef HAL_Handle HAL_AnalogOutputHandle;
|
||||
|
||||
typedef HAL_Handle HAL_AnalogTriggerHandle;
|
||||
|
||||
typedef HAL_Handle HAL_CompressorHandle;
|
||||
|
||||
typedef HAL_Handle HAL_CounterHandle;
|
||||
|
||||
typedef HAL_Handle HAL_DigitalHandle;
|
||||
|
||||
typedef HAL_Handle HAL_DigitalPWMHandle;
|
||||
|
||||
typedef HAL_Handle HAL_EncoderHandle;
|
||||
|
||||
typedef HAL_Handle HAL_FPGAEncoderHandle;
|
||||
|
||||
typedef HAL_Handle HAL_GyroHandle;
|
||||
|
||||
typedef HAL_Handle HAL_InterruptHandle;
|
||||
|
||||
typedef HAL_Handle HAL_NotifierHandle;
|
||||
|
||||
typedef HAL_Handle HAL_RelayHandle;
|
||||
|
||||
typedef HAL_Handle HAL_SolenoidHandle;
|
||||
|
||||
typedef int32_t HAL_Bool;
|
||||
154
hal/src/main/native/include/HAL/UsageReporting.h
Normal file
154
hal/src/main/native/include/HAL/UsageReporting.h
Normal file
@@ -0,0 +1,154 @@
|
||||
|
||||
#ifndef __UsageReporting_h__
|
||||
#define __UsageReporting_h__
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <stdint.h>
|
||||
#define EXPORT_FUNC __declspec(dllexport) __cdecl
|
||||
#elif defined (__vxworks)
|
||||
#include <vxWorks.h>
|
||||
#define EXPORT_FUNC
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#define EXPORT_FUNC
|
||||
#endif
|
||||
|
||||
#define kUsageReporting_version 1
|
||||
|
||||
namespace nUsageReporting
|
||||
{
|
||||
typedef enum
|
||||
{
|
||||
kResourceType_Controller,
|
||||
kResourceType_Module,
|
||||
kResourceType_Language,
|
||||
kResourceType_CANPlugin,
|
||||
kResourceType_Accelerometer,
|
||||
kResourceType_ADXL345,
|
||||
kResourceType_AnalogChannel,
|
||||
kResourceType_AnalogTrigger,
|
||||
kResourceType_AnalogTriggerOutput,
|
||||
kResourceType_CANJaguar,
|
||||
kResourceType_Compressor, // 10
|
||||
kResourceType_Counter,
|
||||
kResourceType_Dashboard,
|
||||
kResourceType_DigitalInput,
|
||||
kResourceType_DigitalOutput,
|
||||
kResourceType_DriverStationCIO,
|
||||
kResourceType_DriverStationEIO,
|
||||
kResourceType_DriverStationLCD,
|
||||
kResourceType_Encoder,
|
||||
kResourceType_GearTooth,
|
||||
kResourceType_Gyro, // 20
|
||||
kResourceType_I2C,
|
||||
kResourceType_Framework,
|
||||
kResourceType_Jaguar,
|
||||
kResourceType_Joystick,
|
||||
kResourceType_Kinect,
|
||||
kResourceType_KinectStick,
|
||||
kResourceType_PIDController,
|
||||
kResourceType_Preferences,
|
||||
kResourceType_PWM,
|
||||
kResourceType_Relay, // 30
|
||||
kResourceType_RobotDrive,
|
||||
kResourceType_SerialPort,
|
||||
kResourceType_Servo,
|
||||
kResourceType_Solenoid,
|
||||
kResourceType_SPI,
|
||||
kResourceType_Task,
|
||||
kResourceType_Ultrasonic,
|
||||
kResourceType_Victor,
|
||||
kResourceType_Button,
|
||||
kResourceType_Command, // 40
|
||||
kResourceType_AxisCamera,
|
||||
kResourceType_PCVideoServer,
|
||||
kResourceType_SmartDashboard,
|
||||
kResourceType_Talon,
|
||||
kResourceType_HiTechnicColorSensor,
|
||||
kResourceType_HiTechnicAccel,
|
||||
kResourceType_HiTechnicCompass,
|
||||
kResourceType_SRF08,
|
||||
kResourceType_AnalogOutput,
|
||||
kResourceType_VictorSP, // 50
|
||||
kResourceType_TalonSRX,
|
||||
kResourceType_CANTalonSRX,
|
||||
kResourceType_ADXL362,
|
||||
kResourceType_ADXRS450,
|
||||
kResourceType_RevSPARK,
|
||||
kResourceType_MindsensorsSD540,
|
||||
kResourceType_DigitalFilter,
|
||||
kResourceType_ADIS16448,
|
||||
kResourceType_PDP,
|
||||
kResourceType_PCM, // 60
|
||||
kResourceType_PigeonIMU,
|
||||
} tResourceType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kLanguage_LabVIEW = 1,
|
||||
kLanguage_CPlusPlus = 2,
|
||||
kLanguage_Java = 3,
|
||||
kLanguage_Python = 4,
|
||||
kLanguage_DotNet = 5,
|
||||
|
||||
kCANPlugin_BlackJagBridge = 1,
|
||||
kCANPlugin_2CAN = 2,
|
||||
|
||||
kFramework_Iterative = 1,
|
||||
kFramework_Simple = 2,
|
||||
kFramework_CommandControl = 3,
|
||||
|
||||
kRobotDrive_ArcadeStandard = 1,
|
||||
kRobotDrive_ArcadeButtonSpin = 2,
|
||||
kRobotDrive_ArcadeRatioCurve = 3,
|
||||
kRobotDrive_Tank = 4,
|
||||
kRobotDrive_MecanumPolar = 5,
|
||||
kRobotDrive_MecanumCartesian = 6,
|
||||
|
||||
kDriverStationCIO_Analog = 1,
|
||||
kDriverStationCIO_DigitalIn = 2,
|
||||
kDriverStationCIO_DigitalOut = 3,
|
||||
|
||||
kDriverStationEIO_Acceleration = 1,
|
||||
kDriverStationEIO_AnalogIn = 2,
|
||||
kDriverStationEIO_AnalogOut = 3,
|
||||
kDriverStationEIO_Button = 4,
|
||||
kDriverStationEIO_LED = 5,
|
||||
kDriverStationEIO_DigitalIn = 6,
|
||||
kDriverStationEIO_DigitalOut = 7,
|
||||
kDriverStationEIO_FixedDigitalOut = 8,
|
||||
kDriverStationEIO_PWM = 9,
|
||||
kDriverStationEIO_Encoder = 10,
|
||||
kDriverStationEIO_TouchSlider = 11,
|
||||
|
||||
kADXL345_SPI = 1,
|
||||
kADXL345_I2C = 2,
|
||||
|
||||
kCommand_Scheduler = 1,
|
||||
|
||||
kSmartDashboard_Instance = 1,
|
||||
} tInstances;
|
||||
|
||||
/**
|
||||
* Report the usage of a resource of interest.
|
||||
*
|
||||
* @param resource one of the values in the tResourceType above (max value 51).
|
||||
* @param instanceNumber an index that identifies the resource instance.
|
||||
* @param context an optional additional context number for some cases (such as module number). Set to 0 to omit.
|
||||
* @param feature a string to be included describing features in use on a specific resource. Setting the same resource more than once allows you to change the feature string.
|
||||
*/
|
||||
uint32_t EXPORT_FUNC report(tResourceType resource, uint8_t instanceNumber, uint8_t context = 0, const char *feature = NULL);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint32_t EXPORT_FUNC FRC_NetworkCommunication_nUsageReporting_report(uint8_t resource, uint8_t instanceNumber, uint8_t context, const char *feature);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __UsageReporting_h__
|
||||
126
hal/src/main/native/include/HAL/cpp/Log.h
Normal file
126
hal/src/main/native/include/HAL/cpp/Log.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
#include "llvm/SmallString.h"
|
||||
#include "llvm/raw_ostream.h"
|
||||
|
||||
inline std::string NowTime();
|
||||
|
||||
enum TLogLevel {
|
||||
logNONE,
|
||||
logERROR,
|
||||
logWARNING,
|
||||
logINFO,
|
||||
logDEBUG,
|
||||
logDEBUG1,
|
||||
logDEBUG2,
|
||||
logDEBUG3,
|
||||
logDEBUG4
|
||||
};
|
||||
|
||||
class Log {
|
||||
public:
|
||||
Log();
|
||||
virtual ~Log();
|
||||
llvm::raw_ostream& Get(TLogLevel level = logINFO);
|
||||
|
||||
public:
|
||||
static TLogLevel& ReportingLevel();
|
||||
static std::string ToString(TLogLevel level);
|
||||
static TLogLevel FromString(const std::string& level);
|
||||
|
||||
protected:
|
||||
llvm::SmallString<128> buf;
|
||||
llvm::raw_svector_ostream oss{buf};
|
||||
|
||||
private:
|
||||
Log(const Log&);
|
||||
Log& operator=(const Log&);
|
||||
};
|
||||
|
||||
inline Log::Log() {}
|
||||
|
||||
inline llvm::raw_ostream& Log::Get(TLogLevel level) {
|
||||
oss << "- " << NowTime();
|
||||
oss << " " << ToString(level) << ": ";
|
||||
oss << std::string(level > logDEBUG ? level - logDEBUG : 0, '\t');
|
||||
return oss;
|
||||
}
|
||||
|
||||
inline Log::~Log() {
|
||||
oss << "\n";
|
||||
llvm::errs() << oss.str();
|
||||
}
|
||||
|
||||
inline TLogLevel& Log::ReportingLevel() {
|
||||
static TLogLevel reportingLevel = logDEBUG4;
|
||||
return reportingLevel;
|
||||
}
|
||||
|
||||
inline std::string Log::ToString(TLogLevel level) {
|
||||
static const char* const buffer[] = {"NONE", "ERROR", "WARNING",
|
||||
"INFO", "DEBUG", "DEBUG1",
|
||||
"DEBUG2", "DEBUG3", "DEBUG4"};
|
||||
return buffer[level];
|
||||
}
|
||||
|
||||
inline TLogLevel Log::FromString(const std::string& level) {
|
||||
if (level == "DEBUG4") return logDEBUG4;
|
||||
if (level == "DEBUG3") return logDEBUG3;
|
||||
if (level == "DEBUG2") return logDEBUG2;
|
||||
if (level == "DEBUG1") return logDEBUG1;
|
||||
if (level == "DEBUG") return logDEBUG;
|
||||
if (level == "INFO") return logINFO;
|
||||
if (level == "WARNING") return logWARNING;
|
||||
if (level == "ERROR") return logERROR;
|
||||
if (level == "NONE") return logNONE;
|
||||
Log().Get(logWARNING) << "Unknown logging level '" << level
|
||||
<< "'. Using INFO level as default.";
|
||||
return logINFO;
|
||||
}
|
||||
|
||||
typedef Log FILELog;
|
||||
|
||||
#define FILE_LOG(level) \
|
||||
if (level > FILELog::ReportingLevel()) \
|
||||
; \
|
||||
else \
|
||||
Log().Get(level)
|
||||
|
||||
inline std::string NowTime() {
|
||||
llvm::SmallString<128> buf;
|
||||
llvm::raw_svector_ostream oss(buf);
|
||||
|
||||
using std::chrono::duration_cast;
|
||||
|
||||
auto now = std::chrono::system_clock::now().time_since_epoch();
|
||||
|
||||
// Hours
|
||||
auto count = duration_cast<std::chrono::hours>(now).count() % 24;
|
||||
if (count < 10) oss << "0";
|
||||
oss << count << ":";
|
||||
|
||||
// Minutes
|
||||
count = duration_cast<std::chrono::minutes>(now).count() % 60;
|
||||
if (count < 10) oss << "0";
|
||||
oss << count << ":";
|
||||
|
||||
// Seconds
|
||||
count = duration_cast<std::chrono::seconds>(now).count() % 60;
|
||||
if (count < 10) oss << "0";
|
||||
oss << count << ".";
|
||||
|
||||
// Milliseconds
|
||||
oss << duration_cast<std::chrono::milliseconds>(now).count() % 1000;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
15
hal/src/main/native/include/HAL/cpp/NotifierInternal.h
Normal file
15
hal/src/main/native/include/HAL/cpp/NotifierInternal.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
extern "C" {
|
||||
HAL_NotifierHandle HAL_InitializeNotifierNonThreadedUnsafe(
|
||||
HAL_NotifierProcessFunction process, void* param, int32_t* status);
|
||||
}
|
||||
51
hal/src/main/native/include/HAL/cpp/SerialHelper.h
Normal file
51
hal/src/main/native/include/HAL/cpp/SerialHelper.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "HAL/SerialPort.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "llvm/SmallString.h"
|
||||
#include "llvm/SmallVector.h"
|
||||
|
||||
namespace hal {
|
||||
class SerialHelper {
|
||||
public:
|
||||
SerialHelper();
|
||||
|
||||
std::string GetVISASerialPortName(HAL_SerialPort port, int32_t* status);
|
||||
std::string GetOSSerialPortName(HAL_SerialPort port, int32_t* status);
|
||||
|
||||
std::vector<std::string> GetVISASerialPortList(int32_t* status);
|
||||
std::vector<std::string> GetOSSerialPortList(int32_t* status);
|
||||
|
||||
private:
|
||||
void SortHubPathVector();
|
||||
void CoiteratedSort(llvm::SmallVectorImpl<llvm::SmallString<16>>& vec);
|
||||
void QueryHubPaths(int32_t* status);
|
||||
|
||||
int32_t GetIndexForPort(HAL_SerialPort port, int32_t* status);
|
||||
|
||||
// Vectors to hold data before sorting.
|
||||
// Note we will most likely have at max 2 instances, and the longest string
|
||||
// is around 12, so these should never touch the heap;
|
||||
llvm::SmallVector<llvm::SmallString<16>, 4> m_visaResource;
|
||||
llvm::SmallVector<llvm::SmallString<16>, 4> m_osResource;
|
||||
llvm::SmallVector<llvm::SmallString<16>, 4> m_unsortedHubPath;
|
||||
llvm::SmallVector<llvm::SmallString<16>, 4> m_sortedHubPath;
|
||||
|
||||
int32_t m_resourceHandle;
|
||||
|
||||
static hal::priority_mutex m_nameMutex;
|
||||
static std::string m_usbNames[2];
|
||||
};
|
||||
} // namespace hal
|
||||
32
hal/src/main/native/include/HAL/cpp/fpga_clock.h
Normal file
32
hal/src/main/native/include/HAL/cpp/fpga_clock.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
|
||||
namespace hal {
|
||||
|
||||
class fpga_clock {
|
||||
public:
|
||||
typedef std::chrono::microseconds::rep rep;
|
||||
typedef std::chrono::microseconds::period period;
|
||||
typedef std::chrono::microseconds duration;
|
||||
typedef std::chrono::time_point<fpga_clock> time_point;
|
||||
|
||||
static fpga_clock::time_point now() noexcept;
|
||||
static constexpr bool is_steady = true;
|
||||
|
||||
static constexpr fpga_clock::time_point epoch() { return time_point(zero()); }
|
||||
|
||||
static constexpr fpga_clock::duration zero() { return duration(0); }
|
||||
|
||||
static constexpr time_point min_time{
|
||||
time_point(duration(std::numeric_limits<duration::rep>::min()))};
|
||||
};
|
||||
} // namespace hal
|
||||
47
hal/src/main/native/include/HAL/cpp/make_unique.h
Normal file
47
hal/src/main/native/include/HAL/cpp/make_unique.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Define make_unique for C++11-only compilers
|
||||
#if __cplusplus == 201103L
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace std {
|
||||
template <class T>
|
||||
struct _Unique_if {
|
||||
typedef unique_ptr<T> _Single_object;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct _Unique_if<T[]> {
|
||||
typedef unique_ptr<T[]> _Unknown_bound;
|
||||
};
|
||||
|
||||
template <class T, size_t N>
|
||||
struct _Unique_if<T[N]> {
|
||||
typedef void _Known_bound;
|
||||
};
|
||||
|
||||
template <class T, class... Args>
|
||||
typename _Unique_if<T>::_Single_object make_unique(Args&&... args) {
|
||||
return unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename _Unique_if<T>::_Unknown_bound make_unique(size_t n) {
|
||||
typedef typename remove_extent<T>::type U;
|
||||
return unique_ptr<T>(new U[n]());
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
typename _Unique_if<T>::_Known_bound make_unique(Args&&...) = delete;
|
||||
} // namespace std
|
||||
#endif
|
||||
@@ -0,0 +1,141 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* std::condition_variable provides the native_handle() method to return its
|
||||
* underlying pthread_cond_t*. WPILib uses this to interface with the FRC
|
||||
* network communication library. Since WPILib uses a custom mutex class and
|
||||
* not std::mutex, std::condition_variable_any must be used instead.
|
||||
* std::condition_variable_any doesn't expose its internal handle, so this
|
||||
* class provides the same interface and implementation in addition to a
|
||||
* native_handle() method.
|
||||
*/
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "priority_mutex.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
class priority_condition_variable {
|
||||
typedef std::chrono::system_clock clock;
|
||||
|
||||
public:
|
||||
typedef std::condition_variable::native_handle_type native_handle_type;
|
||||
|
||||
priority_condition_variable() : m_mutex(std::make_shared<std::mutex>()) {}
|
||||
~priority_condition_variable() = default;
|
||||
|
||||
priority_condition_variable(const priority_condition_variable&) = delete;
|
||||
priority_condition_variable& operator=(const priority_condition_variable&) =
|
||||
delete;
|
||||
|
||||
void notify_one() noexcept {
|
||||
std::lock_guard<std::mutex> lock(*m_mutex);
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
void notify_all() noexcept {
|
||||
std::lock_guard<std::mutex> lock(*m_mutex);
|
||||
m_cond.notify_all();
|
||||
}
|
||||
|
||||
template <typename Lock>
|
||||
void wait(Lock& _lock) {
|
||||
std::shared_ptr<std::mutex> _mutex = m_mutex;
|
||||
std::unique_lock<std::mutex> my_lock(*_mutex);
|
||||
Unlock<Lock> unlock(_lock);
|
||||
|
||||
// *mutex must be unlocked before re-locking _lock so move
|
||||
// ownership of *_mutex lock to an object with shorter lifetime.
|
||||
std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
|
||||
m_cond.wait(my_lock2);
|
||||
}
|
||||
|
||||
template <typename Lock, typename Predicate>
|
||||
void wait(Lock& lock, Predicate p) {
|
||||
while (!p()) {
|
||||
wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Lock, typename Clock, typename Duration>
|
||||
std::cv_status wait_until(
|
||||
Lock& _lock, const std::chrono::time_point<Clock, Duration>& atime) {
|
||||
std::shared_ptr<std::mutex> _mutex = m_mutex;
|
||||
std::unique_lock<std::mutex> my_lock(*_mutex);
|
||||
Unlock<Lock> unlock(_lock);
|
||||
|
||||
// *_mutex must be unlocked before re-locking _lock so move
|
||||
// ownership of *_mutex lock to an object with shorter lifetime.
|
||||
std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
|
||||
return m_cond.wait_until(my_lock2, atime);
|
||||
}
|
||||
|
||||
template <typename Lock, typename Clock, typename Duration,
|
||||
typename Predicate>
|
||||
bool wait_until(Lock& lock,
|
||||
const std::chrono::time_point<Clock, Duration>& atime,
|
||||
Predicate p) {
|
||||
while (!p()) {
|
||||
if (wait_until(lock, atime) == std::cv_status::timeout) {
|
||||
return p();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Lock, typename Rep, typename Period>
|
||||
std::cv_status wait_for(Lock& lock,
|
||||
const std::chrono::duration<Rep, Period>& rtime) {
|
||||
return wait_until(lock, clock::now() + rtime);
|
||||
}
|
||||
|
||||
template <typename Lock, typename Rep, typename Period, typename Predicate>
|
||||
bool wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& rtime,
|
||||
Predicate p) {
|
||||
return wait_until(lock, clock::now() + rtime, std::move(p));
|
||||
}
|
||||
|
||||
native_handle_type native_handle() { return m_cond.native_handle(); }
|
||||
|
||||
private:
|
||||
std::condition_variable m_cond;
|
||||
std::shared_ptr<std::mutex> m_mutex;
|
||||
|
||||
// scoped unlock - unlocks in ctor, re-locks in dtor
|
||||
template <typename Lock>
|
||||
struct Unlock {
|
||||
explicit Unlock(Lock& lk) : m_lock(lk) { lk.unlock(); }
|
||||
|
||||
~Unlock() /*noexcept(false)*/ {
|
||||
if (std::uncaught_exception()) {
|
||||
try {
|
||||
m_lock.lock();
|
||||
} catch (...) {
|
||||
}
|
||||
} else {
|
||||
m_lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
Unlock(const Unlock&) = delete;
|
||||
Unlock& operator=(const Unlock&) = delete;
|
||||
|
||||
Lock& m_lock;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
|
||||
// For backwards compatibility
|
||||
#ifndef NAMESPACED_PRIORITY
|
||||
using hal::priority_condition_variable; // NOLINT
|
||||
#endif
|
||||
92
hal/src/main/native/include/HAL/cpp/priority_mutex.h
Normal file
92
hal/src/main/native/include/HAL/cpp/priority_mutex.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Allows usage with std::lock_guard without including <mutex> separately
|
||||
#include <mutex>
|
||||
|
||||
#if defined(_WIN32)
|
||||
namespace hal {
|
||||
// We do not want to use pthreads if in the simulator; however, in the
|
||||
// simulator, we do not care about priority inversion.
|
||||
typedef std::mutex priority_mutex;
|
||||
typedef std::recursive_mutex priority_recursive_mutex;
|
||||
} // namespace hal
|
||||
#else // Covers rest of file.
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace hal {
|
||||
|
||||
class priority_recursive_mutex {
|
||||
public:
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
|
||||
constexpr priority_recursive_mutex() noexcept = default;
|
||||
priority_recursive_mutex(const priority_recursive_mutex&) = delete;
|
||||
priority_recursive_mutex& operator=(const priority_recursive_mutex&) = delete;
|
||||
|
||||
// Lock the mutex, blocking until it's available.
|
||||
void lock();
|
||||
|
||||
// Unlock the mutex.
|
||||
void unlock();
|
||||
|
||||
// Tries to lock the mutex.
|
||||
bool try_lock() noexcept;
|
||||
|
||||
pthread_mutex_t* native_handle();
|
||||
|
||||
private:
|
||||
// Do the equivalent of setting PTHREAD_PRIO_INHERIT and
|
||||
// PTHREAD_MUTEX_RECURSIVE_NP.
|
||||
#if __WORDSIZE == 64
|
||||
pthread_mutex_t m_mutex = {
|
||||
{0, 0, 0, 0, 0x20 | PTHREAD_MUTEX_RECURSIVE_NP, 0, 0, {0, 0}}};
|
||||
#else
|
||||
pthread_mutex_t m_mutex = {
|
||||
{0, 0, 0, 0x20 | PTHREAD_MUTEX_RECURSIVE_NP, 0, {0}}};
|
||||
#endif
|
||||
};
|
||||
|
||||
class priority_mutex {
|
||||
public:
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
|
||||
constexpr priority_mutex() noexcept = default;
|
||||
priority_mutex(const priority_mutex&) = delete;
|
||||
priority_mutex& operator=(const priority_mutex&) = delete;
|
||||
|
||||
// Lock the mutex, blocking until it's available.
|
||||
void lock();
|
||||
|
||||
// Unlock the mutex.
|
||||
void unlock();
|
||||
|
||||
// Tries to lock the mutex.
|
||||
bool try_lock() noexcept;
|
||||
|
||||
pthread_mutex_t* native_handle();
|
||||
|
||||
private:
|
||||
// Do the equivalent of setting PTHREAD_PRIO_INHERIT.
|
||||
#if __WORDSIZE == 64
|
||||
pthread_mutex_t m_mutex = {{0, 0, 0, 0, 0x20, 0, 0, {0, 0}}};
|
||||
#else
|
||||
pthread_mutex_t m_mutex = {{0, 0, 0, 0x20, 0, {0}}};
|
||||
#endif
|
||||
};
|
||||
} // namespace hal
|
||||
|
||||
#endif // FRC_SIMULATOR
|
||||
|
||||
// For backwards compatibility
|
||||
#ifndef NAMESPACED_PRIORITY
|
||||
using hal::priority_mutex; // NOLINT
|
||||
using hal::priority_recursive_mutex; // NOLINT
|
||||
#endif
|
||||
105
hal/src/main/native/include/HAL/handles/DigitalHandleResource.h
Normal file
105
hal/src/main/native/include/HAL/handles/DigitalHandleResource.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The DigitalHandleResource class is a way to track handles. This version
|
||||
* allows a limited number of handles that are allocated by index.
|
||||
* The enum value is seperate, as 2 enum values are allowed per handle
|
||||
* Because they are allocated by index, each individual index holds its own
|
||||
* mutex, which reduces contention heavily.]
|
||||
*
|
||||
* @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
|
||||
* @tparam TStruct The struct type held by this resource
|
||||
* @tparam size The number of resources allowed to be allocated
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, int16_t size>
|
||||
class DigitalHandleResource : public HandleBase {
|
||||
friend class DigitalHandleResourceTest;
|
||||
|
||||
public:
|
||||
DigitalHandleResource() = default;
|
||||
DigitalHandleResource(const DigitalHandleResource&) = delete;
|
||||
DigitalHandleResource& operator=(const DigitalHandleResource&) = delete;
|
||||
|
||||
THandle Allocate(int16_t index, HAL_HandleEnum enumValue, int32_t* status);
|
||||
std::shared_ptr<TStruct> Get(THandle handle, HAL_HandleEnum enumValue);
|
||||
void Free(THandle handle, HAL_HandleEnum enumValue);
|
||||
void ResetHandles() override;
|
||||
|
||||
private:
|
||||
std::array<std::shared_ptr<TStruct>, size> m_structures;
|
||||
std::array<hal::priority_mutex, size> m_handleMutexes;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size>
|
||||
THandle DigitalHandleResource<THandle, TStruct, size>::Allocate(
|
||||
int16_t index, HAL_HandleEnum enumValue, int32_t* status) {
|
||||
// don't aquire the lock if we can fail early.
|
||||
if (index < 0 || index >= size) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
// check for allocation, otherwise allocate and return a valid handle
|
||||
if (m_structures[index] != nullptr) {
|
||||
*status = RESOURCE_IS_ALLOCATED;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
m_structures[index] = std::make_shared<TStruct>();
|
||||
return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size>
|
||||
std::shared_ptr<TStruct> DigitalHandleResource<THandle, TStruct, size>::Get(
|
||||
THandle handle, HAL_HandleEnum enumValue) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
// return structure. Null will propogate correctly, so no need to manually
|
||||
// check.
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size>
|
||||
void DigitalHandleResource<THandle, TStruct, size>::Free(
|
||||
THandle handle, HAL_HandleEnum enumValue) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size>
|
||||
void DigitalHandleResource<THandle, TStruct, size>::ResetHandles() {
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i].reset();
|
||||
}
|
||||
HandleBase::ResetHandles();
|
||||
}
|
||||
} // namespace hal
|
||||
119
hal/src/main/native/include/HAL/handles/HandlesInternal.h
Normal file
119
hal/src/main/native/include/HAL/handles/HandlesInternal.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
/* General Handle Data Layout
|
||||
* Bits 0-15: Handle Index
|
||||
* Bits 16-23: 8 bit rolling reset detection
|
||||
* Bits 24-30: Handle Type
|
||||
* Bit 31: 1 if handle error, 0 if no error
|
||||
*
|
||||
* Other specialized handles will use different formats, however Bits 24-31 are
|
||||
* always reserved for type and error handling.
|
||||
*/
|
||||
|
||||
namespace hal {
|
||||
|
||||
class HandleBase {
|
||||
public:
|
||||
HandleBase();
|
||||
~HandleBase();
|
||||
HandleBase(const HandleBase&) = delete;
|
||||
HandleBase& operator=(const HandleBase&) = delete;
|
||||
virtual void ResetHandles();
|
||||
static void ResetGlobalHandles();
|
||||
|
||||
protected:
|
||||
int16_t m_version;
|
||||
};
|
||||
|
||||
constexpr int16_t InvalidHandleIndex = -1;
|
||||
|
||||
enum class HAL_HandleEnum {
|
||||
Undefined = 0,
|
||||
DIO = 1,
|
||||
Port = 2,
|
||||
Notifier = 3,
|
||||
Interrupt = 4,
|
||||
AnalogOutput = 5,
|
||||
AnalogInput = 6,
|
||||
AnalogTrigger = 7,
|
||||
Relay = 8,
|
||||
PWM = 9,
|
||||
DigitalPWM = 10,
|
||||
Counter = 11,
|
||||
FPGAEncoder = 12,
|
||||
Encoder = 13,
|
||||
Compressor = 14,
|
||||
Solenoid = 15,
|
||||
AnalogGyro = 16,
|
||||
Vendor = 17
|
||||
};
|
||||
|
||||
static inline int16_t getHandleIndex(HAL_Handle handle) {
|
||||
// mask and return last 16 bits
|
||||
return static_cast<int16_t>(handle & 0xffff);
|
||||
}
|
||||
static inline HAL_HandleEnum getHandleType(HAL_Handle handle) {
|
||||
// mask first 8 bits and cast to enum
|
||||
return static_cast<HAL_HandleEnum>((handle >> 24) & 0xff);
|
||||
}
|
||||
static inline bool isHandleType(HAL_Handle handle, HAL_HandleEnum handleType) {
|
||||
return handleType == getHandleType(handle);
|
||||
}
|
||||
static inline bool isHandleCorrectVersion(HAL_Handle handle, int16_t version) {
|
||||
return (((handle & 0xFF0000) >> 16) & version) == version;
|
||||
}
|
||||
static inline int16_t getHandleTypedIndex(HAL_Handle handle,
|
||||
HAL_HandleEnum enumType,
|
||||
int16_t version) {
|
||||
if (!isHandleType(handle, enumType)) return InvalidHandleIndex;
|
||||
#if !defined(CONFIG_ATHENA)
|
||||
if (!isHandleCorrectVersion(handle, version)) return InvalidHandleIndex;
|
||||
#endif
|
||||
return getHandleIndex(handle);
|
||||
}
|
||||
|
||||
/* specialized functions for Port handle
|
||||
* Port Handle Data Layout
|
||||
* Bits 0-7: Channel Number
|
||||
* Bits 8-15: Module Number
|
||||
* Bits 16-23: Unused
|
||||
* Bits 24-30: Handle Type
|
||||
* Bit 31: 1 if handle error, 0 if no error
|
||||
*/
|
||||
|
||||
// using a 16 bit value so we can store 0-255 and still report error
|
||||
static inline int16_t getPortHandleChannel(HAL_PortHandle handle) {
|
||||
if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
|
||||
return static_cast<uint8_t>(handle & 0xff);
|
||||
}
|
||||
|
||||
// using a 16 bit value so we can store 0-255 and still report error
|
||||
static inline int16_t getPortHandleModule(HAL_PortHandle handle) {
|
||||
if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
|
||||
return static_cast<uint8_t>((handle >> 8) & 0xff);
|
||||
}
|
||||
|
||||
// using a 16 bit value so we can store 0-255 and still report error
|
||||
static inline int16_t getPortHandleSPIEnable(HAL_PortHandle handle) {
|
||||
if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
|
||||
return static_cast<uint8_t>((handle >> 16) & 0xff);
|
||||
}
|
||||
|
||||
HAL_PortHandle createPortHandle(uint8_t channel, uint8_t module);
|
||||
|
||||
HAL_PortHandle createPortHandleForSPI(uint8_t channel);
|
||||
|
||||
HAL_Handle createHandle(int16_t index, HAL_HandleEnum handleType,
|
||||
int16_t version);
|
||||
} // namespace hal
|
||||
@@ -0,0 +1,122 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The IndexedClassedHandleResource class is a way to track handles. This
|
||||
* version
|
||||
* allows a limited number of handles that are allocated by index.
|
||||
* Because they are allocated by index, each individual index holds its own
|
||||
* mutex, which reduces contention heavily.]
|
||||
*
|
||||
* @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
|
||||
* @tparam TStruct The struct type held by this resource
|
||||
* @tparam size The number of resources allowed to be allocated
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
class IndexedClassedHandleResource : public HandleBase {
|
||||
friend class IndexedClassedHandleResourceTest;
|
||||
|
||||
public:
|
||||
IndexedClassedHandleResource();
|
||||
IndexedClassedHandleResource(const IndexedClassedHandleResource&) = delete;
|
||||
IndexedClassedHandleResource& operator=(const IndexedClassedHandleResource&) =
|
||||
delete;
|
||||
|
||||
THandle Allocate(int16_t index, std::shared_ptr<TStruct> toSet,
|
||||
int32_t* status);
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
|
||||
private:
|
||||
std::array<std::shared_ptr<TStruct>[], size> m_structures;
|
||||
std::array<hal::priority_mutex[], size> m_handleMutexes;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
IndexedClassedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::IndexedClassedHandleResource() {
|
||||
m_structures = std::make_unique<std::shared_ptr<TStruct>[]>(size);
|
||||
m_handleMutexes = std::make_unique<hal::priority_mutex[]>(size);
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
THandle
|
||||
IndexedClassedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
|
||||
int16_t index, std::shared_ptr<TStruct> toSet, int32_t* status) {
|
||||
// don't aquire the lock if we can fail early.
|
||||
if (index < 0 || index >= size) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
// check for allocation, otherwise allocate and return a valid handle
|
||||
if (m_structures[index] != nullptr) {
|
||||
*status = RESOURCE_IS_ALLOCATED;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
m_structures[index] = toSet;
|
||||
return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct> IndexedClassedHandleResource<
|
||||
THandle, TStruct, size, enumValue>::Get(THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
// return structure. Null will propogate correctly, so no need to manually
|
||||
// check.
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
void IndexedClassedHandleResource<THandle, TStruct, size, enumValue>::Free(
|
||||
THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
void IndexedClassedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::ResetHandles() {
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i].reset();
|
||||
}
|
||||
HandleBase::ResetHandles();
|
||||
}
|
||||
} // namespace hal
|
||||
110
hal/src/main/native/include/HAL/handles/IndexedHandleResource.h
Normal file
110
hal/src/main/native/include/HAL/handles/IndexedHandleResource.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The IndexedHandleResource class is a way to track handles. This version
|
||||
* allows a limited number of handles that are allocated by index.
|
||||
* Because they are allocated by index, each individual index holds its own
|
||||
* mutex, which reduces contention heavily.]
|
||||
*
|
||||
* @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
|
||||
* @tparam TStruct The struct type held by this resource
|
||||
* @tparam size The number of resources allowed to be allocated
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
class IndexedHandleResource : public HandleBase {
|
||||
friend class IndexedHandleResourceTest;
|
||||
|
||||
public:
|
||||
IndexedHandleResource() = default;
|
||||
IndexedHandleResource(const IndexedHandleResource&) = delete;
|
||||
IndexedHandleResource& operator=(const IndexedHandleResource&) = delete;
|
||||
|
||||
THandle Allocate(int16_t index, int32_t* status);
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
void ResetHandles() override;
|
||||
|
||||
private:
|
||||
std::array<std::shared_ptr<TStruct>, size> m_structures;
|
||||
std::array<hal::priority_mutex, size> m_handleMutexes;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
THandle IndexedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
|
||||
int16_t index, int32_t* status) {
|
||||
// don't aquire the lock if we can fail early.
|
||||
if (index < 0 || index >= size) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
// check for allocation, otherwise allocate and return a valid handle
|
||||
if (m_structures[index] != nullptr) {
|
||||
*status = RESOURCE_IS_ALLOCATED;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
m_structures[index] = std::make_shared<TStruct>();
|
||||
return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct>
|
||||
IndexedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
// return structure. Null will propogate correctly, so no need to manually
|
||||
// check.
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
void IndexedHandleResource<THandle, TStruct, size, enumValue>::Free(
|
||||
THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
void IndexedHandleResource<THandle, TStruct, size, enumValue>::ResetHandles() {
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i].reset();
|
||||
}
|
||||
HandleBase::ResetHandles();
|
||||
}
|
||||
} // namespace hal
|
||||
@@ -0,0 +1,115 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The LimitedClassedHandleResource class is a way to track handles. This
|
||||
* version
|
||||
* allows a limited number of handles that are allocated sequentially.
|
||||
*
|
||||
* @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
|
||||
* @tparam TStruct The struct type held by this resource
|
||||
* @tparam size The number of resources allowed to be allocated
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
class LimitedClassedHandleResource : public HandleBase {
|
||||
friend class LimitedClassedHandleResourceTest;
|
||||
|
||||
public:
|
||||
LimitedClassedHandleResource() = default;
|
||||
LimitedClassedHandleResource(const LimitedClassedHandleResource&) = delete;
|
||||
LimitedClassedHandleResource& operator=(const LimitedClassedHandleResource&) =
|
||||
delete;
|
||||
|
||||
THandle Allocate(std::shared_ptr<TStruct> toSet);
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
void ResetHandles() override;
|
||||
|
||||
private:
|
||||
std::array<std::shared_ptr<TStruct>, size> m_structures;
|
||||
std::array<hal::priority_mutex, size> m_handleMutexes;
|
||||
hal::priority_mutex m_allocateMutex;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
THandle
|
||||
LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
|
||||
std::shared_ptr<TStruct> toSet) {
|
||||
// globally lock to loop through indices
|
||||
std::lock_guard<hal::priority_mutex> sync(m_allocateMutex);
|
||||
for (int16_t i = 0; i < size; i++) {
|
||||
if (m_structures[i] == nullptr) {
|
||||
// if a false index is found, grab its specific mutex
|
||||
// and allocate it.
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i] = toSet;
|
||||
return static_cast<THandle>(createHandle(i, enumValue, m_version));
|
||||
}
|
||||
}
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct> LimitedClassedHandleResource<
|
||||
THandle, TStruct, size, enumValue>::Get(THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
// return structure. Null will propogate correctly, so no need to manually
|
||||
// check.
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
void LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Free(
|
||||
THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<hal::priority_mutex> sync(m_allocateMutex);
|
||||
std::lock_guard<hal::priority_mutex> lock(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
void LimitedClassedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::ResetHandles() {
|
||||
{
|
||||
std::lock_guard<hal::priority_mutex> lock(m_allocateMutex);
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i].reset();
|
||||
}
|
||||
}
|
||||
HandleBase::ResetHandles();
|
||||
}
|
||||
} // namespace hal
|
||||
110
hal/src/main/native/include/HAL/handles/LimitedHandleResource.h
Normal file
110
hal/src/main/native/include/HAL/handles/LimitedHandleResource.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/make_unique.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The LimitedHandleResource class is a way to track handles. This version
|
||||
* allows a limited number of handles that are allocated sequentially.
|
||||
*
|
||||
* @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
|
||||
* @tparam TStruct The struct type held by this resource
|
||||
* @tparam size The number of resources allowed to be allocated
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
class LimitedHandleResource : public HandleBase {
|
||||
friend class LimitedHandleResourceTest;
|
||||
|
||||
public:
|
||||
LimitedHandleResource() = default;
|
||||
LimitedHandleResource(const LimitedHandleResource&) = delete;
|
||||
LimitedHandleResource& operator=(const LimitedHandleResource&) = delete;
|
||||
|
||||
THandle Allocate();
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
void ResetHandles() override;
|
||||
|
||||
private:
|
||||
std::array<std::shared_ptr<TStruct>, size> m_structures;
|
||||
std::array<hal::priority_mutex, size> m_handleMutexes;
|
||||
hal::priority_mutex m_allocateMutex;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
THandle LimitedHandleResource<THandle, TStruct, size, enumValue>::Allocate() {
|
||||
// globally lock to loop through indices
|
||||
std::lock_guard<hal::priority_mutex> sync(m_allocateMutex);
|
||||
for (int16_t i = 0; i < size; i++) {
|
||||
if (m_structures[i] == nullptr) {
|
||||
// if a false index is found, grab its specific mutex
|
||||
// and allocate it.
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i] = std::make_shared<TStruct>();
|
||||
return static_cast<THandle>(createHandle(i, enumValue, m_version));
|
||||
}
|
||||
}
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct>
|
||||
LimitedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[index]);
|
||||
// return structure. Null will propogate correctly, so no need to manually
|
||||
// check.
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
void LimitedHandleResource<THandle, TStruct, size, enumValue>::Free(
|
||||
THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<hal::priority_mutex> sync(m_allocateMutex);
|
||||
std::lock_guard<hal::priority_mutex> lock(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
void LimitedHandleResource<THandle, TStruct, size, enumValue>::ResetHandles() {
|
||||
{
|
||||
std::lock_guard<hal::priority_mutex> lock(m_allocateMutex);
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i].reset();
|
||||
}
|
||||
}
|
||||
HandleBase::ResetHandles();
|
||||
}
|
||||
} // namespace hal
|
||||
@@ -0,0 +1,101 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The UnlimitedHandleResource class is a way to track handles. This version
|
||||
* allows an unlimted number of handles that are allocated sequentially. When
|
||||
* possible, indices are reused to save memory usage and keep the array length
|
||||
* down.
|
||||
* However, automatic array management has not been implemented, but might be in
|
||||
* the future.
|
||||
* Because we have to loop through the allocator, we must use a global mutex.
|
||||
|
||||
* @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
|
||||
* @tparam TStruct The struct type held by this resource
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
class UnlimitedHandleResource : public HandleBase {
|
||||
friend class UnlimitedHandleResourceTest;
|
||||
|
||||
public:
|
||||
UnlimitedHandleResource() = default;
|
||||
UnlimitedHandleResource(const UnlimitedHandleResource&) = delete;
|
||||
UnlimitedHandleResource& operator=(const UnlimitedHandleResource&) = delete;
|
||||
|
||||
THandle Allocate(std::shared_ptr<TStruct> structure);
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
void ResetHandles() override;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<TStruct>> m_structures;
|
||||
hal::priority_mutex m_handleMutex;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
THandle UnlimitedHandleResource<THandle, TStruct, enumValue>::Allocate(
|
||||
std::shared_ptr<TStruct> structure) {
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutex);
|
||||
size_t i;
|
||||
for (i = 0; i < m_structures.size(); i++) {
|
||||
if (m_structures[i] == nullptr) {
|
||||
m_structures[i] = structure;
|
||||
return static_cast<THandle>(createHandle(i, enumValue, m_version));
|
||||
}
|
||||
}
|
||||
if (i >= INT16_MAX) return HAL_kInvalidHandle;
|
||||
|
||||
m_structures.push_back(structure);
|
||||
return static_cast<THandle>(
|
||||
createHandle(static_cast<int16_t>(i), enumValue, m_version));
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct>
|
||||
UnlimitedHandleResource<THandle, TStruct, enumValue>::Get(THandle handle) {
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutex);
|
||||
if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
|
||||
return nullptr;
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
void UnlimitedHandleResource<THandle, TStruct, enumValue>::Free(
|
||||
THandle handle) {
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
||||
std::lock_guard<hal::priority_mutex> sync(m_handleMutex);
|
||||
if (index < 0 || index >= static_cast<int16_t>(m_structures.size())) return;
|
||||
m_structures[index].reset();
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
void UnlimitedHandleResource<THandle, TStruct, enumValue>::ResetHandles() {
|
||||
{
|
||||
std::lock_guard<hal::priority_mutex> lock(m_handleMutex);
|
||||
for (size_t i = 0; i < m_structures.size(); i++) {
|
||||
m_structures[i].reset();
|
||||
}
|
||||
}
|
||||
HandleBase::ResetHandles();
|
||||
}
|
||||
} // namespace hal
|
||||
60
hal/src/main/native/include/MockData/AccelerometerData.h
Normal file
60
hal/src/main/native/include/MockData/AccelerometerData.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetAccelerometerData(int32_t index);
|
||||
int32_t HALSIM_RegisterAccelerometerActiveCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAccelerometerActiveCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetAccelerometerActive(int32_t index);
|
||||
void HALSIM_SetAccelerometerActive(int32_t index, HAL_Bool active);
|
||||
|
||||
int32_t HALSIM_RegisterAccelerometerRangeCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAccelerometerRangeCallback(int32_t index, int32_t uid);
|
||||
HAL_AccelerometerRange HALSIM_GetAccelerometerRange(int32_t index);
|
||||
void HALSIM_SetAccelerometerRange(int32_t index, HAL_AccelerometerRange range);
|
||||
|
||||
int32_t HALSIM_RegisterAccelerometerXCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAccelerometerXCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetAccelerometerX(int32_t index);
|
||||
void HALSIM_SetAccelerometerX(int32_t index, double x);
|
||||
|
||||
int32_t HALSIM_RegisterAccelerometerYCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAccelerometerYCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetAccelerometerY(int32_t index);
|
||||
void HALSIM_SetAccelerometerY(int32_t index, double y);
|
||||
|
||||
int32_t HALSIM_RegisterAccelerometerZCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAccelerometerZCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetAccelerometerZ(int32_t index);
|
||||
void HALSIM_SetAccelerometerZ(int32_t index, double z);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
43
hal/src/main/native/include/MockData/AnalogGyroData.h
Normal file
43
hal/src/main/native/include/MockData/AnalogGyroData.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetAnalogGyroData(int32_t index);
|
||||
int32_t HALSIM_RegisterAnalogGyroAngleCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogGyroAngleCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetAnalogGyroAngle(int32_t index);
|
||||
void HALSIM_SetAnalogGyroAngle(int32_t index, double angle);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogGyroRateCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogGyroRateCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetAnalogGyroRate(int32_t index);
|
||||
void HALSIM_SetAnalogGyroRate(int32_t index, double rate);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogGyroInitializedCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogGyroInitializedCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetAnalogGyroInitialized(int32_t index);
|
||||
void HALSIM_SetAnalogGyroInitialized(int32_t index, HAL_Bool initialized);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
93
hal/src/main/native/include/MockData/AnalogInData.h
Normal file
93
hal/src/main/native/include/MockData/AnalogInData.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetAnalogInData(int32_t index);
|
||||
int32_t HALSIM_RegisterAnalogInInitializedCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInInitializedCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetAnalogInInitialized(int32_t index);
|
||||
void HALSIM_SetAnalogInInitialized(int32_t index, HAL_Bool initialized);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogInAverageBitsCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInAverageBitsCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetAnalogInAverageBits(int32_t index);
|
||||
void HALSIM_SetAnalogInAverageBits(int32_t index, int32_t averageBits);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogInOversampleBitsCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInOversampleBitsCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetAnalogInOversampleBits(int32_t index);
|
||||
void HALSIM_SetAnalogInOversampleBits(int32_t index, int32_t oversampleBits);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogInVoltageCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInVoltageCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetAnalogInVoltage(int32_t index);
|
||||
void HALSIM_SetAnalogInVoltage(int32_t index, double voltage);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogInAccumulatorInitializedCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInAccumulatorInitializedCallback(int32_t index,
|
||||
int32_t uid);
|
||||
HAL_Bool HALSIM_GetAnalogInAccumulatorInitialized(int32_t index);
|
||||
void HALSIM_SetAnalogInAccumulatorInitialized(int32_t index,
|
||||
HAL_Bool accumulatorInitialized);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogInAccumulatorValueCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInAccumulatorValueCallback(int32_t index, int32_t uid);
|
||||
int64_t HALSIM_GetAnalogInAccumulatorValue(int32_t index);
|
||||
void HALSIM_SetAnalogInAccumulatorValue(int32_t index,
|
||||
int64_t accumulatorValue);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogInAccumulatorCountCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInAccumulatorCountCallback(int32_t index, int32_t uid);
|
||||
int64_t HALSIM_GetAnalogInAccumulatorCount(int32_t index);
|
||||
void HALSIM_SetAnalogInAccumulatorCount(int32_t index,
|
||||
int64_t accumulatorCount);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogInAccumulatorCenterCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInAccumulatorCenterCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetAnalogInAccumulatorCenter(int32_t index);
|
||||
void HALSIM_SetAnalogInAccumulatorCenter(int32_t index,
|
||||
int32_t accumulatorCenter);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogInAccumulatorDeadbandCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogInAccumulatorDeadbandCallback(int32_t index,
|
||||
int32_t uid);
|
||||
int32_t HALSIM_GetAnalogInAccumulatorDeadband(int32_t index);
|
||||
void HALSIM_SetAnalogInAccumulatorDeadband(int32_t index,
|
||||
int32_t accumulatorDeadband);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
36
hal/src/main/native/include/MockData/AnalogOutData.h
Normal file
36
hal/src/main/native/include/MockData/AnalogOutData.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetAnalogOutData(int32_t index);
|
||||
int32_t HALSIM_RegisterAnalogOutVoltageCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogOutVoltageCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetAnalogOutVoltage(int32_t index);
|
||||
void HALSIM_SetAnalogOutVoltage(int32_t index, double voltage);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogOutInitializedCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogOutInitializedCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetAnalogOutInitialized(int32_t index);
|
||||
void HALSIM_SetAnalogOutInitialized(int32_t index, HAL_Bool initialized);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
59
hal/src/main/native/include/MockData/AnalogTriggerData.h
Normal file
59
hal/src/main/native/include/MockData/AnalogTriggerData.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
enum HALSIM_AnalogTriggerMode : int32_t {
|
||||
HALSIM_AnalogTriggerUnassigned,
|
||||
HALSIM_AnalogTriggerFiltered,
|
||||
HALSIM_AnalogTriggerAveraged
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetAnalogTriggerData(int32_t index);
|
||||
int32_t HALSIM_RegisterAnalogTriggerInitializedCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogTriggerInitializedCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetAnalogTriggerInitialized(int32_t index);
|
||||
void HALSIM_SetAnalogTriggerInitialized(int32_t index, HAL_Bool initialized);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogTriggerTriggerLowerBoundCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogTriggerTriggerLowerBoundCallback(int32_t index,
|
||||
int32_t uid);
|
||||
double HALSIM_GetAnalogTriggerTriggerLowerBound(int32_t index);
|
||||
void HALSIM_SetAnalogTriggerTriggerLowerBound(int32_t index,
|
||||
double triggerLowerBound);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogTriggerTriggerUpperBoundCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogTriggerTriggerUpperBoundCallback(int32_t index,
|
||||
int32_t uid);
|
||||
double HALSIM_GetAnalogTriggerTriggerUpperBound(int32_t index);
|
||||
void HALSIM_SetAnalogTriggerTriggerUpperBound(int32_t index,
|
||||
double triggerUpperBound);
|
||||
|
||||
int32_t HALSIM_RegisterAnalogTriggerTriggerModeCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAnalogTriggerTriggerModeCallback(int32_t index, int32_t uid);
|
||||
HALSIM_AnalogTriggerMode HALSIM_GetAnalogTriggerTriggerMode(int32_t index);
|
||||
void HALSIM_SetAnalogTriggerTriggerMode(int32_t index,
|
||||
HALSIM_AnalogTriggerMode triggerMode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
58
hal/src/main/native/include/MockData/DIOData.h
Normal file
58
hal/src/main/native/include/MockData/DIOData.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetDIOData(int32_t index);
|
||||
int32_t HALSIM_RegisterDIOInitializedCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDIOInitializedCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetDIOInitialized(int32_t index);
|
||||
void HALSIM_SetDIOInitialized(int32_t index, HAL_Bool initialized);
|
||||
|
||||
int32_t HALSIM_RegisterDIOValueCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param, HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDIOValueCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetDIOValue(int32_t index);
|
||||
void HALSIM_SetDIOValue(int32_t index, HAL_Bool value);
|
||||
|
||||
int32_t HALSIM_RegisterDIOPulseLengthCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDIOPulseLengthCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetDIOPulseLength(int32_t index);
|
||||
void HALSIM_SetDIOPulseLength(int32_t index, double pulseLength);
|
||||
|
||||
int32_t HALSIM_RegisterDIOIsInputCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param, HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDIOIsInputCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetDIOIsInput(int32_t index);
|
||||
void HALSIM_SetDIOIsInput(int32_t index, HAL_Bool isInput);
|
||||
|
||||
int32_t HALSIM_RegisterDIOFilterIndexCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDIOFilterIndexCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetDIOFilterIndex(int32_t index);
|
||||
void HALSIM_SetDIOFilterIndex(int32_t index, int32_t filterIndex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
43
hal/src/main/native/include/MockData/DigitalPWMData.h
Normal file
43
hal/src/main/native/include/MockData/DigitalPWMData.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetDigitalPWMData(int32_t index);
|
||||
int32_t HALSIM_RegisterDigitalPWMInitializedCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDigitalPWMInitializedCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetDigitalPWMInitialized(int32_t index);
|
||||
void HALSIM_SetDigitalPWMInitialized(int32_t index, HAL_Bool initialized);
|
||||
|
||||
int32_t HALSIM_RegisterDigitalPWMDutyCycleCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDigitalPWMDutyCycleCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetDigitalPWMDutyCycle(int32_t index);
|
||||
void HALSIM_SetDigitalPWMDutyCycle(int32_t index, double dutyCycle);
|
||||
|
||||
int32_t HALSIM_RegisterDigitalPWMPinCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDigitalPWMPinCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetDigitalPWMPin(int32_t index);
|
||||
void HALSIM_SetDigitalPWMPin(int32_t index, int32_t pin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
74
hal/src/main/native/include/MockData/DriverStationData.h
Normal file
74
hal/src/main/native/include/MockData/DriverStationData.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetDriverStationData(void);
|
||||
int32_t HALSIM_RegisterDriverStationEnabledCallback(HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDriverStationEnabledCallback(int32_t uid);
|
||||
HAL_Bool HALSIM_GetDriverStationEnabled();
|
||||
void HALSIM_SetDriverStationEnabled(HAL_Bool enabled);
|
||||
|
||||
int32_t HALSIM_RegisterDriverStationAutonomousCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDriverStationAutonomousCallback(int32_t uid);
|
||||
HAL_Bool HALSIM_GetDriverStationAutonomous();
|
||||
void HALSIM_SetDriverStationAutonomous(HAL_Bool autonomous);
|
||||
|
||||
int32_t HALSIM_RegisterDriverStationTestCallback(HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDriverStationTestCallback(int32_t uid);
|
||||
HAL_Bool HALSIM_GetDriverStationTest();
|
||||
void HALSIM_SetDriverStationTest(HAL_Bool test);
|
||||
|
||||
int32_t HALSIM_RegisterDriverStationEStopCallback(HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDriverStationEStopCallback(int32_t uid);
|
||||
HAL_Bool HALSIM_GetDriverStationEStop();
|
||||
void HALSIM_SetDriverStationEStop(HAL_Bool eStop);
|
||||
|
||||
int32_t HALSIM_RegisterDriverStationFmsAttachedCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDriverStationFmsAttachedCallback(int32_t uid);
|
||||
HAL_Bool HALSIM_GetDriverStationFmsAttached();
|
||||
void HALSIM_SetDriverStationFmsAttached(HAL_Bool fmsAttached);
|
||||
|
||||
int32_t HALSIM_RegisterDriverStationDsAttachedCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDriverStationDsAttachedCallback(int32_t uid);
|
||||
HAL_Bool HALSIM_GetDriverStationDsAttached();
|
||||
void HALSIM_SetDriverStationDsAttached(HAL_Bool dsAttached);
|
||||
|
||||
int32_t HALSIM_RegisterDriverStationAllianceStationIdCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDriverStationAllianceStationIdCallback(int32_t uid);
|
||||
HAL_AllianceStationID HALSIM_GetDriverStationAllianceStationId();
|
||||
void HALSIM_SetDriverStationAllianceStationId(
|
||||
HAL_AllianceStationID allianceStationId);
|
||||
|
||||
int32_t HALSIM_RegisterDriverStationMatchTimeCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
|
||||
void HALSIM_CancelDriverStationMatchTimeCallback(int32_t uid);
|
||||
double HALSIM_GetDriverStationMatchTime();
|
||||
void HALSIM_SetDriverStationMatchTime(double matchTime);
|
||||
|
||||
void HALSIM_NotifyDriverStationNewData(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
83
hal/src/main/native/include/MockData/EncoderData.h
Normal file
83
hal/src/main/native/include/MockData/EncoderData.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/HAL.h"
|
||||
#include "NotifyListener.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void HALSIM_ResetEncoderData(int32_t index);
|
||||
int32_t HALSIM_RegisterEncoderInitializedCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelEncoderInitializedCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetEncoderInitialized(int32_t index);
|
||||
void HALSIM_SetEncoderInitialized(int32_t index, HAL_Bool initialized);
|
||||
|
||||
int32_t HALSIM_RegisterEncoderCountCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelEncoderCountCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetEncoderCount(int32_t index);
|
||||
void HALSIM_SetEncoderCount(int32_t index, int32_t count);
|
||||
|
||||
int32_t HALSIM_RegisterEncoderPeriodCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelEncoderPeriodCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetEncoderPeriod(int32_t index);
|
||||
void HALSIM_SetEncoderPeriod(int32_t index, double period);
|
||||
|
||||
int32_t HALSIM_RegisterEncoderResetCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelEncoderResetCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetEncoderReset(int32_t index);
|
||||
void HALSIM_SetEncoderReset(int32_t index, HAL_Bool reset);
|
||||
|
||||
int32_t HALSIM_RegisterEncoderMaxPeriodCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelEncoderMaxPeriodCallback(int32_t index, int32_t uid);
|
||||
double HALSIM_GetEncoderMaxPeriod(int32_t index);
|
||||
void HALSIM_SetEncoderMaxPeriod(int32_t index, double maxPeriod);
|
||||
|
||||
int32_t HALSIM_RegisterEncoderDirectionCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelEncoderDirectionCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetEncoderDirection(int32_t index);
|
||||
void HALSIM_SetEncoderDirection(int32_t index, HAL_Bool direction);
|
||||
|
||||
int32_t HALSIM_RegisterEncoderReverseDirectionCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelEncoderReverseDirectionCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetEncoderReverseDirection(int32_t index);
|
||||
void HALSIM_SetEncoderReverseDirection(int32_t index,
|
||||
HAL_Bool reverseDirection);
|
||||
|
||||
int32_t HALSIM_RegisterEncoderSamplesToAverageCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelEncoderSamplesToAverageCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetEncoderSamplesToAverage(int32_t index);
|
||||
void HALSIM_SetEncoderSamplesToAverage(int32_t index, int32_t samplesToAverage);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
67
hal/src/main/native/include/MockData/HAL_Value.h
Normal file
67
hal/src/main/native/include/MockData/HAL_Value.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HAL/Types.h"
|
||||
|
||||
/** HAL data types. */
|
||||
enum HAL_Type {
|
||||
HAL_UNASSIGNED = 0,
|
||||
HAL_BOOLEAN = 0x01,
|
||||
HAL_DOUBLE = 0x02,
|
||||
HAL_ENUM = 0x16,
|
||||
HAL_INT = 0x32,
|
||||
HAL_LONG = 0x64,
|
||||
};
|
||||
|
||||
/** HAL Entry Value. Note this is a typed union. */
|
||||
struct HAL_Value {
|
||||
union {
|
||||
HAL_Bool v_boolean;
|
||||
int32_t v_enum;
|
||||
int32_t v_int;
|
||||
int64_t v_long;
|
||||
double v_double;
|
||||
} data;
|
||||
enum HAL_Type type;
|
||||
};
|
||||
|
||||
inline HAL_Value MakeBoolean(HAL_Bool v) {
|
||||
HAL_Value value;
|
||||
value.type = HAL_BOOLEAN;
|
||||
value.data.v_boolean = v;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline HAL_Value MakeEnum(int v) {
|
||||
HAL_Value value;
|
||||
value.type = HAL_ENUM;
|
||||
value.data.v_enum = v;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline HAL_Value MakeInt(int v) {
|
||||
HAL_Value value;
|
||||
value.type = HAL_INT;
|
||||
value.data.v_int = v;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline HAL_Value MakeLong(int64_t v) {
|
||||
HAL_Value value;
|
||||
value.type = HAL_LONG;
|
||||
value.data.v_long = v;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline HAL_Value MakeDouble(double v) {
|
||||
HAL_Value value;
|
||||
value.type = HAL_DOUBLE;
|
||||
value.data.v_double = v;
|
||||
return value;
|
||||
}
|
||||
14
hal/src/main/native/include/MockData/MockHooks.h
Normal file
14
hal/src/main/native/include/MockData/MockHooks.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
void HALSIM_WaitForProgramStart(void);
|
||||
void HALSIM_SetProgramStarted(void);
|
||||
void HALSIM_RestartTiming(void);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user