Checks for system initialization in functions that can be called before creating handle based objects (#285)

This commit is contained in:
Thad House
2016-10-23 10:00:34 -07:00
committed by Peter Johnson
parent c46c490376
commit df4a2c07f0
7 changed files with 67 additions and 31 deletions

View File

@@ -19,8 +19,6 @@
using namespace hal;
static bool analogSampleRateSet = false;
extern "C" {
/**
* Initialize the analog input port using the given port object.
@@ -103,28 +101,9 @@ void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status) {
// TODO: This will change when variable size scan lists are implemented.
// TODO: Need float 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);
initializeAnalog(status);
if (*status != 0) return;
setAnalogSampleRate(samplesPerSecond, status);
}
/**
@@ -136,6 +115,8 @@ void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status) {
* @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);

View File

@@ -7,6 +7,8 @@
#include "AnalogInternal.h"
#include <atomic>
#include "ChipObject.h"
#include "HAL/AnalogInput.h"
#include "HAL/cpp/priority_mutex.h"
@@ -23,18 +25,21 @@ IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort, kNumAnalogInputs,
static int32_t analogNumChannelsToActivate = 0;
bool analogSystemInitialized = false;
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);
HAL_SetAnalogSampleRate(kDefaultSampleRate, status);
setAnalogSampleRate(kDefaultSampleRate, status);
analogSystemInitialized = true;
}
@@ -66,6 +71,41 @@ int32_t getAnalogNumChannelsToActivate(int32_t* 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 float 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.
*

View File

@@ -27,6 +27,7 @@ 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;
@@ -40,7 +41,6 @@ extern IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort,
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);
extern bool analogSystemInitialized;
} // namespace hal

View File

@@ -142,6 +142,8 @@ 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) +
@@ -371,6 +373,8 @@ HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
* @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;
}
@@ -436,6 +440,8 @@ int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
* 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) {
@@ -456,6 +462,8 @@ void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
* 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;
{

View File

@@ -7,6 +7,7 @@
#include "DigitalInternal.h"
#include <atomic>
#include <mutex>
#include <thread>
@@ -27,7 +28,8 @@ std::unique_ptr<tDIO> digitalSystem;
std::unique_ptr<tRelay> relaySystem;
std::unique_ptr<tPWM> pwmSystem;
bool digitalSystemsInitialized = false;
static std::atomic<bool> digitalSystemsInitialized{false};
static priority_mutex initializeMutex;
DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
kNumDigitalChannels + kNumPWMHeaders>
@@ -37,6 +39,11 @@ DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
* 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<priority_mutex> lock(initializeMutex);
// Second check in case another thread was waiting
if (digitalSystemsInitialized) return;
digitalSystem.reset(tDIO::create(status));

View File

@@ -63,8 +63,6 @@ extern std::unique_ptr<tDIO> digitalSystem;
extern std::unique_ptr<tRelay> relaySystem;
extern std::unique_ptr<tPWM> pwmSystem;
extern bool digitalSystemsInitialized;
struct DigitalPort {
uint8_t channel;
bool configSet = false;

View File

@@ -441,6 +441,8 @@ void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
* @return The loop time
*/
int32_t HAL_GetLoopTiming(int32_t* status) {
initializeDigital(status);
if (*status != 0) return 0;
return pwmSystem->readLoopTiming(status);
}
}