2016-05-26 12:56:39 -07:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
/* Copyright (c) FIRST 2016. 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"
|
|
|
|
|
|
2016-06-05 07:33:37 -07:00
|
|
|
#include <cmath>
|
2016-05-26 12:56:39 -07:00
|
|
|
|
|
|
|
|
#include "DigitalInternal.h"
|
2016-07-02 23:19:14 -07:00
|
|
|
#include "PortsInternal.h"
|
2016-06-05 15:23:58 -07:00
|
|
|
#include "handles/HandlesInternal.h"
|
2016-06-30 23:43:00 -07:00
|
|
|
#include "handles/LimitedHandleResource.h"
|
2016-05-26 12:56:39 -07:00
|
|
|
|
|
|
|
|
using namespace hal;
|
|
|
|
|
|
|
|
|
|
// Create a mutex to protect changes to the digital output values
|
|
|
|
|
static priority_recursive_mutex digitalDIOMutex;
|
|
|
|
|
|
2016-07-09 00:24:26 -07:00
|
|
|
static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
|
|
|
|
|
kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>
|
2016-06-30 23:43:00 -07:00
|
|
|
digitalPWMHandles;
|
|
|
|
|
|
2016-05-26 12:56:39 -07:00
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a new instance of a digital port.
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle port_handle,
|
|
|
|
|
uint8_t input, int32_t* status) {
|
2016-05-26 12:56:39 -07:00
|
|
|
initializeDigital(status);
|
2016-06-05 15:23:58 -07:00
|
|
|
|
2016-07-09 00:24:26 -07:00
|
|
|
if (*status != 0) return HAL_kInvalidHandle;
|
2016-06-05 15:23:58 -07:00
|
|
|
|
|
|
|
|
int16_t pin = getPortHandlePin(port_handle);
|
2016-06-17 20:21:25 -07:00
|
|
|
if (pin == InvalidHandleIndex) {
|
2016-06-05 15:23:58 -07:00
|
|
|
*status = PARAMETER_OUT_OF_RANGE;
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle;
|
2016-06-05 15:23:58 -07:00
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
|
2016-07-09 00:24:26 -07:00
|
|
|
auto handle = digitalPinHandles.Allocate(pin, HAL_HandleEnum::DIO, status);
|
2016-05-26 12:56:39 -07:00
|
|
|
|
2016-06-30 21:39:09 -07:00
|
|
|
if (*status != 0)
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2016-07-09 00:24:26 -07:00
|
|
|
auto port = digitalPinHandles.Get(handle, HAL_HandleEnum::DIO);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) { // would only occur on thread issue.
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle;
|
2016-06-30 21:39:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
port->pin = static_cast<uint8_t>(pin);
|
|
|
|
|
|
|
|
|
|
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
|
|
|
|
|
|
|
|
|
tDIO::tOutputEnable outputEnable = digitalSystem->readOutputEnable(status);
|
|
|
|
|
|
2016-07-02 23:19:14 -07:00
|
|
|
if (port->pin < kNumDigitalHeaders) {
|
2016-06-30 21:39:09 -07:00
|
|
|
uint32_t bitToSet = 1 << port->pin;
|
|
|
|
|
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 = 1 << remapMXPChannel(port->pin);
|
|
|
|
|
|
|
|
|
|
// Disable special functions on this pin
|
|
|
|
|
short 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;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_FreeDIOPort(HAL_DigitalHandle dio_port_handle) {
|
2016-06-30 21:39:09 -07:00
|
|
|
// no status, so no need to check for a proper free.
|
2016-07-09 00:24:26 -07:00
|
|
|
digitalPinHandles.Free(dio_port_handle, HAL_HandleEnum::DIO);
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Allocate a DO PWM Generator.
|
|
|
|
|
* Allocate PWM generators so that they are not accidentally reused.
|
|
|
|
|
*
|
2016-06-30 23:43:00 -07:00
|
|
|
* @return PWM Generator handle
|
2016-05-26 12:56:39 -07:00
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
|
2016-06-30 23:43:00 -07:00
|
|
|
auto handle = digitalPWMHandles.Allocate();
|
2016-07-09 00:24:26 -07:00
|
|
|
if (handle == HAL_kInvalidHandle) {
|
2016-06-30 23:43:00 -07:00
|
|
|
*status = NO_AVAILABLE_RESOURCES;
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle;
|
2016-06-30 23:43:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto id = digitalPWMHandles.Get(handle);
|
|
|
|
|
if (id == nullptr) { // would only occur on thread issue.
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle;
|
2016-06-30 23:43:00 -07:00
|
|
|
}
|
|
|
|
|
*id = static_cast<uint8_t>(getHandleIndex(handle));
|
|
|
|
|
|
|
|
|
|
return handle;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Free the resource associated with a DO PWM generator.
|
|
|
|
|
*
|
|
|
|
|
* @param pwmGenerator The pwmGen to free that was allocated with
|
2016-06-30 23:43:00 -07:00
|
|
|
* allocateDigitalPWM()
|
2016-05-26 12:56:39 -07:00
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status) {
|
2016-06-30 23:43:00 -07:00
|
|
|
digitalPWMHandles.Free(pwmGenerator);
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_SetDigitalPWMRate(double rate, int32_t* status) {
|
2016-05-26 12:56:39 -07:00
|
|
|
// Currently rounding in the log rate domain... heavy weight toward picking a
|
|
|
|
|
// higher freq.
|
|
|
|
|
// TODO: Round in the linear rate domain.
|
|
|
|
|
uint8_t pwmPeriodPower = (uint8_t)(
|
|
|
|
|
log(1.0 / (pwmSystem->readLoopTiming(status) * 0.25E-6 * rate)) /
|
|
|
|
|
log(2.0) +
|
|
|
|
|
0.5);
|
|
|
|
|
digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure the duty-cycle of the PWM generator
|
|
|
|
|
*
|
2016-06-30 23:43:00 -07:00
|
|
|
* @param pwmGenerator The generator index reserved by allocateDigitalPWM()
|
2016-05-26 12:56:39 -07:00
|
|
|
* @param dutyCycle The percent duty cycle to output [0..1].
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
|
|
|
|
|
double dutyCycle, int32_t* status) {
|
2016-06-30 23:43:00 -07:00
|
|
|
auto port = digitalPWMHandles.Get(pwmGenerator);
|
|
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 23:43:00 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint32_t id = *port;
|
2016-05-26 12:56:39 -07:00
|
|
|
if (dutyCycle > 1.0) dutyCycle = 1.0;
|
|
|
|
|
if (dutyCycle < 0.0) dutyCycle = 0.0;
|
|
|
|
|
float rawDutyCycle = 256.0 * dutyCycle;
|
|
|
|
|
if (rawDutyCycle > 255.5) rawDutyCycle = 255.5;
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<priority_recursive_mutex> sync(digitalPwmMutex);
|
|
|
|
|
uint8_t pwmPeriodPower = digitalSystem->readPWMPeriodPower(status);
|
|
|
|
|
if (pwmPeriodPower < 4) {
|
|
|
|
|
// The resolution of the duty cycle drops close to the highest
|
|
|
|
|
// frequencies.
|
2016-06-05 07:33:37 -07:00
|
|
|
rawDutyCycle = rawDutyCycle / std::pow(2.0, 4 - pwmPeriodPower);
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
if (id < 4)
|
|
|
|
|
digitalSystem->writePWMDutyCycleA(id, (uint8_t)rawDutyCycle, status);
|
|
|
|
|
else
|
|
|
|
|
digitalSystem->writePWMDutyCycleB(id - 4, (uint8_t)rawDutyCycle, status);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure which DO channel the PWM signal is output on
|
|
|
|
|
*
|
2016-06-30 23:43:00 -07:00
|
|
|
* @param pwmGenerator The generator index reserved by allocateDigitalPWM()
|
2016-05-26 12:56:39 -07:00
|
|
|
* @param channel The Digital Output channel to output on
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
|
|
|
|
|
uint32_t pin, int32_t* status) {
|
2016-06-30 23:43:00 -07:00
|
|
|
auto port = digitalPWMHandles.Get(pwmGenerator);
|
|
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 23:43:00 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint32_t id = *port;
|
2016-07-02 23:19:14 -07:00
|
|
|
if (pin >= kNumDigitalHeaders) { // if it is on the MXP
|
2016-06-24 22:46:43 -04:00
|
|
|
pin += kMXPDigitalPWMOffset; // then to write as a digital PWM pin requires
|
|
|
|
|
// an offset to write on the correct pin
|
|
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
digitalSystem->writePWMOutputSelect(id, pin, 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)
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_SetDIO(HAL_DigitalHandle dio_port_handle, short value,
|
|
|
|
|
int32_t* status) {
|
|
|
|
|
auto port = digitalPinHandles.Get(dio_port_handle, HAL_HandleEnum::DIO);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 21:39:09 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
if (value != 0 && value != 1) {
|
|
|
|
|
if (value != 0) value = 1;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
|
|
|
|
tDIO::tDO currentDIO = digitalSystem->readDO(status);
|
|
|
|
|
|
2016-07-02 23:19:14 -07:00
|
|
|
if (port->pin < kNumDigitalHeaders) {
|
2016-05-26 12:56:39 -07:00
|
|
|
if (value == 0) {
|
2016-06-05 15:23:58 -07:00
|
|
|
currentDIO.Headers = currentDIO.Headers & ~(1 << port->pin);
|
2016-05-26 12:56:39 -07:00
|
|
|
} else if (value == 1) {
|
2016-06-05 15:23:58 -07:00
|
|
|
currentDIO.Headers = currentDIO.Headers | (1 << port->pin);
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (value == 0) {
|
2016-06-05 15:23:58 -07:00
|
|
|
currentDIO.MXP = currentDIO.MXP & ~(1 << remapMXPChannel(port->pin));
|
2016-05-26 12:56:39 -07:00
|
|
|
} else if (value == 1) {
|
2016-06-05 15:23:58 -07:00
|
|
|
currentDIO.MXP = currentDIO.MXP | (1 << remapMXPChannel(port->pin));
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
2016-06-05 15:23:58 -07:00
|
|
|
uint32_t bitToSet = 1 << remapMXPChannel(port->pin);
|
2016-05-26 12:56:39 -07:00
|
|
|
short specialFunctions =
|
|
|
|
|
digitalSystem->readEnableMXPSpecialFunction(status);
|
|
|
|
|
digitalSystem->writeEnableMXPSpecialFunction(specialFunctions & ~bitToSet,
|
|
|
|
|
status);
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
bool HAL_GetDIO(HAL_DigitalHandle dio_port_handle, int32_t* status) {
|
|
|
|
|
auto port = digitalPinHandles.Get(dio_port_handle, HAL_HandleEnum::DIO);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 21:39:09 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
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
|
|
|
|
|
|
2016-07-02 23:19:14 -07:00
|
|
|
if (port->pin < kNumDigitalHeaders) {
|
2016-06-05 15:23:58 -07:00
|
|
|
return ((currentDIO.Headers >> port->pin) & 1) != 0;
|
2016-05-26 12:56:39 -07:00
|
|
|
} else {
|
|
|
|
|
// Disable special functions
|
2016-06-05 15:23:58 -07:00
|
|
|
uint32_t bitToSet = 1 << remapMXPChannel(port->pin);
|
2016-05-26 12:56:39 -07:00
|
|
|
short specialFunctions =
|
|
|
|
|
digitalSystem->readEnableMXPSpecialFunction(status);
|
|
|
|
|
digitalSystem->writeEnableMXPSpecialFunction(specialFunctions & ~bitToSet,
|
|
|
|
|
status);
|
|
|
|
|
|
2016-06-05 15:23:58 -07:00
|
|
|
return ((currentDIO.MXP >> remapMXPChannel(port->pin)) & 1) != 0;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
bool HAL_GetDIODirection(HAL_DigitalHandle dio_port_handle, int32_t* status) {
|
|
|
|
|
auto port = digitalPinHandles.Get(dio_port_handle, HAL_HandleEnum::DIO);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 21:39:09 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
tDIO::tOutputEnable currentOutputEnable =
|
|
|
|
|
digitalSystem->readOutputEnable(status);
|
2016-06-05 15:23:58 -07:00
|
|
|
// Shift 00000001 over port->pin-1 places.
|
2016-05-26 12:56:39 -07:00
|
|
|
// AND it against the currentOutputEnable
|
|
|
|
|
// if it == 0, then return false
|
|
|
|
|
// else return true
|
|
|
|
|
|
2016-07-02 23:19:14 -07:00
|
|
|
if (port->pin < kNumDigitalHeaders) {
|
2016-06-05 15:23:58 -07:00
|
|
|
return ((currentOutputEnable.Headers >> port->pin) & 1) != 0;
|
2016-05-26 12:56:39 -07:00
|
|
|
} else {
|
2016-06-05 15:23:58 -07:00
|
|
|
return ((currentOutputEnable.MXP >> remapMXPChannel(port->pin)) & 1) != 0;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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)
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_Pulse(HAL_DigitalHandle dio_port_handle, double pulseLength,
|
|
|
|
|
int32_t* status) {
|
|
|
|
|
auto port = digitalPinHandles.Get(dio_port_handle, HAL_HandleEnum::DIO);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 21:39:09 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
tDIO::tPulse pulse;
|
|
|
|
|
|
2016-07-02 23:19:14 -07:00
|
|
|
if (port->pin < kNumDigitalHeaders) {
|
2016-06-05 15:23:58 -07:00
|
|
|
pulse.Headers = 1 << port->pin;
|
2016-05-26 12:56:39 -07:00
|
|
|
} else {
|
2016-06-05 15:23:58 -07:00
|
|
|
pulse.MXP = 1 << remapMXPChannel(port->pin);
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
digitalSystem->writePulseLength(
|
|
|
|
|
(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
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
bool HAL_IsPulsing(HAL_DigitalHandle dio_port_handle, int32_t* status) {
|
|
|
|
|
auto port = digitalPinHandles.Get(dio_port_handle, HAL_HandleEnum::DIO);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 21:39:09 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
|
|
|
|
|
|
2016-07-02 23:19:14 -07:00
|
|
|
if (port->pin < kNumDigitalHeaders) {
|
2016-06-05 15:23:58 -07:00
|
|
|
return (pulseRegister.Headers & (1 << port->pin)) != 0;
|
2016-05-26 12:56:39 -07:00
|
|
|
} else {
|
2016-06-05 15:23:58 -07:00
|
|
|
return (pulseRegister.MXP & (1 << remapMXPChannel(port->pin))) != 0;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if any DIO line is currently generating a pulse.
|
|
|
|
|
*
|
|
|
|
|
* @return A pulse on some line is in progress
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
bool HAL_IsAnyPulsing(int32_t* status) {
|
2016-05-26 12:56:39 -07:00
|
|
|
tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
|
|
|
|
|
return pulseRegister.Headers != 0 && pulseRegister.MXP != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write the filter index from the FPGA.
|
|
|
|
|
* Set the filter index used to filter out short pulses.
|
|
|
|
|
*
|
|
|
|
|
* @param digital_port_pointer The digital I/O channel
|
|
|
|
|
* @param filter_index The filter index. Must be in the range 0 - 3,
|
|
|
|
|
* where 0 means "none" and 1 - 3 means filter # filter_index - 1.
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_SetFilterSelect(HAL_DigitalHandle dio_port_handle, int filter_index,
|
|
|
|
|
int32_t* status) {
|
|
|
|
|
auto port = digitalPinHandles.Get(dio_port_handle, HAL_HandleEnum::DIO);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 21:39:09 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
|
|
|
|
|
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
2016-07-02 23:19:14 -07:00
|
|
|
if (port->pin < kNumDigitalHeaders) {
|
2016-06-05 15:23:58 -07:00
|
|
|
digitalSystem->writeFilterSelectHdr(port->pin, filter_index, status);
|
2016-05-26 12:56:39 -07:00
|
|
|
} else {
|
2016-06-05 15:23:58 -07:00
|
|
|
digitalSystem->writeFilterSelectMXP(remapMXPChannel(port->pin),
|
2016-05-26 12:56:39 -07:00
|
|
|
filter_index, status);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read the filter index from the FPGA.
|
|
|
|
|
* Get the filter index used to filter out short pulses.
|
|
|
|
|
*
|
|
|
|
|
* @param digital_port_pointer The digital I/O channel
|
|
|
|
|
* @return filter_index The filter index. Must be in the range 0 - 3,
|
|
|
|
|
* where 0 means "none" and 1 - 3 means filter # filter_index - 1.
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
int HAL_GetFilterSelect(HAL_DigitalHandle dio_port_handle, int32_t* status) {
|
|
|
|
|
auto port = digitalPinHandles.Get(dio_port_handle, HAL_HandleEnum::DIO);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 21:39:09 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2016-05-26 12:56:39 -07:00
|
|
|
|
|
|
|
|
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
2016-07-02 23:19:14 -07:00
|
|
|
if (port->pin < kNumDigitalHeaders) {
|
2016-06-05 15:23:58 -07:00
|
|
|
return digitalSystem->readFilterSelectHdr(port->pin, status);
|
2016-05-26 12:56:39 -07:00
|
|
|
} else {
|
2016-06-05 15:23:58 -07:00
|
|
|
return digitalSystem->readFilterSelectMXP(remapMXPChannel(port->pin),
|
2016-05-26 12:56:39 -07:00
|
|
|
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 filter_index The filter index, 0 - 2.
|
|
|
|
|
* @param value The number of cycles that the signal must not transition to be
|
|
|
|
|
* counted as a transition.
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
void HAL_SetFilterPeriod(int filter_index, uint32_t value, int32_t* status) {
|
2016-05-26 12:56:39 -07:00
|
|
|
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
|
|
|
|
digitalSystem->writeFilterPeriodHdr(filter_index, value, status);
|
|
|
|
|
if (*status == 0) {
|
|
|
|
|
digitalSystem->writeFilterPeriodMXP(filter_index, 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 filter_index The filter index, 0 - 2.
|
|
|
|
|
* @param value The number of cycles that the signal must not transition to be
|
|
|
|
|
* counted as a transition.
|
|
|
|
|
*/
|
2016-07-09 00:24:26 -07:00
|
|
|
uint32_t HAL_GetFilterPeriod(int filter_index, int32_t* status) {
|
2016-05-26 12:56:39 -07:00
|
|
|
uint32_t hdr_period = 0;
|
|
|
|
|
uint32_t mxp_period = 0;
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
|
|
|
|
hdr_period = digitalSystem->readFilterPeriodHdr(filter_index, status);
|
|
|
|
|
if (*status == 0) {
|
|
|
|
|
mxp_period = digitalSystem->readFilterPeriodMXP(filter_index, status);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (hdr_period != mxp_period) {
|
|
|
|
|
*status = NiFpga_Status_SoftwareFault;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return hdr_period;
|
|
|
|
|
}
|
|
|
|
|
}
|