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:
Thad House
2017-08-18 21:35:53 -07:00
committed by Peter Johnson
parent 50ed55e8e2
commit e1195e8b9d
1024 changed files with 64481 additions and 61340 deletions

View 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"

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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

View 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

View 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;
}
}

View 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;
}
}

View 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"

View 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;
}
}

View 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;
}

View 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);
}
}
}

View 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;
}
}

View 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

View 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

View 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();
}
}

View 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

View 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);
}
}

View 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);
}

View 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"

View 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"

View 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;
}
}

View 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"

View 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"

View 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]);
}
}

View 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

View 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

View 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"

View 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);
}
}

View 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; }
}

View 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

View 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"

View 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;
}
}

View 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;
}
}

View 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"

View 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"

View 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);
}
}

View 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

View 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;
}

View 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;
}
}

View 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 &current)
{
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 &currentAmps)
{
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)
{
}
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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 -----------------------------------------------------------------*/

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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"

View 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

View 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

View 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

View 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"

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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);
}

View 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;

View 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__

View 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();
}

View 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);
}

View 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

View 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

View 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

View File

@@ -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

View 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

View 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

View 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

View 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. */
/*----------------------------------------------------------------------------*/
#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

View 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

View File

@@ -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

View 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

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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;
}

View 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