mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-05 03:21:42 +00:00
Change hal sim to use spinlocks (#1291)
This makes callback registration completely thread safe. This patch also uses templates and macros to dramatically reduce the amount of manual boilerplate.
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include <mockdata/NotifyCallbackHelpers.h>
|
||||
#include <mockdata/SPIData.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -62,10 +61,9 @@ bool ADXRS450_SpiGyroWrapper::GetInitialized() const {
|
||||
}
|
||||
|
||||
void ADXRS450_SpiGyroWrapper::ResetData() {
|
||||
std::lock_guard<wpi::mutex> lock(m_dataMutex);
|
||||
m_angle = 0;
|
||||
std::lock_guard<wpi::recursive_spinlock> lock(m_angle.GetMutex());
|
||||
m_angle.Reset(0.0);
|
||||
m_angleDiff = 0;
|
||||
m_angleCallbacks = nullptr;
|
||||
}
|
||||
|
||||
void ADXRS450_SpiGyroWrapper::HandleRead(uint8_t* buffer, uint32_t count) {
|
||||
@@ -76,7 +74,7 @@ void ADXRS450_SpiGyroWrapper::HandleRead(uint8_t* buffer, uint32_t count) {
|
||||
void ADXRS450_SpiGyroWrapper::HandleAutoReceiveData(uint8_t* buffer,
|
||||
int32_t numToRead,
|
||||
int32_t& outputCount) {
|
||||
std::lock_guard<wpi::mutex> lock(m_dataMutex);
|
||||
std::lock_guard<wpi::recursive_spinlock> lock(m_angle.GetMutex());
|
||||
int32_t messagesToSend = std::abs(
|
||||
m_angleDiff > 0 ? std::ceil(m_angleDiff / kMaxAngleDeltaPerMessage)
|
||||
: std::floor(m_angleDiff / kMaxAngleDeltaPerMessage));
|
||||
@@ -110,42 +108,9 @@ void ADXRS450_SpiGyroWrapper::HandleAutoReceiveData(uint8_t* buffer,
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ADXRS450_SpiGyroWrapper::RegisterAngleCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {
|
||||
// Must return -1 on a null callback for error handling
|
||||
if (callback == nullptr) return -1;
|
||||
int32_t newUid = 0;
|
||||
{
|
||||
std::lock_guard<wpi::mutex> lock(m_registerMutex);
|
||||
m_angleCallbacks =
|
||||
RegisterCallback(m_angleCallbacks, "Angle", callback, param, &newUid);
|
||||
}
|
||||
if (initialNotify) {
|
||||
// We know that the callback is not null because of earlier null check
|
||||
HAL_Value value = MakeDouble(GetAngle());
|
||||
callback("Angle", param, &value);
|
||||
}
|
||||
return newUid;
|
||||
}
|
||||
|
||||
void ADXRS450_SpiGyroWrapper::CancelAngleCallback(int32_t uid) {
|
||||
m_angleCallbacks = CancelCallback(m_angleCallbacks, uid);
|
||||
}
|
||||
|
||||
void ADXRS450_SpiGyroWrapper::InvokeAngleCallback(HAL_Value value) {
|
||||
InvokeCallback(m_angleCallbacks, "Angle", &value);
|
||||
}
|
||||
|
||||
double ADXRS450_SpiGyroWrapper::GetAngle() {
|
||||
std::lock_guard<wpi::mutex> lock(m_dataMutex);
|
||||
return m_angle;
|
||||
}
|
||||
|
||||
void ADXRS450_SpiGyroWrapper::SetAngle(double angle) {
|
||||
std::lock_guard<wpi::mutex> lock(m_dataMutex);
|
||||
std::lock_guard<wpi::recursive_spinlock> lock(m_angle.GetMutex());
|
||||
if (m_angle != angle) {
|
||||
InvokeAngleCallback(MakeDouble(angle));
|
||||
|
||||
m_angleDiff += angle - m_angle;
|
||||
m_angle = angle;
|
||||
}
|
||||
|
||||
@@ -7,123 +7,13 @@
|
||||
|
||||
#include "ThreeAxisAccelerometerData.h"
|
||||
|
||||
#include <mockdata/NotifyCallbackHelpers.h>
|
||||
|
||||
using namespace hal;
|
||||
|
||||
ThreeAxisAccelerometerData::ThreeAxisAccelerometerData() {}
|
||||
|
||||
ThreeAxisAccelerometerData::~ThreeAxisAccelerometerData() {}
|
||||
void ThreeAxisAccelerometerData::ResetData() {
|
||||
m_x = 0.0;
|
||||
m_xCallbacks = nullptr;
|
||||
m_y = 0.0;
|
||||
m_yCallbacks = nullptr;
|
||||
m_z = 0.0;
|
||||
m_zCallbacks = nullptr;
|
||||
}
|
||||
|
||||
int32_t ThreeAxisAccelerometerData::RegisterXCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {
|
||||
// Must return -1 on a null callback for error handling
|
||||
if (callback == nullptr) return -1;
|
||||
int32_t newUid = 0;
|
||||
{
|
||||
std::lock_guard<wpi::mutex> lock(m_registerMutex);
|
||||
m_xCallbacks =
|
||||
RegisterCallback(m_xCallbacks, "X", callback, param, &newUid);
|
||||
}
|
||||
if (initialNotify) {
|
||||
// We know that the callback is not null because of earlier null check
|
||||
HAL_Value value = MakeDouble(GetX());
|
||||
callback("X", param, &value);
|
||||
}
|
||||
return newUid;
|
||||
}
|
||||
|
||||
void ThreeAxisAccelerometerData::CancelXCallback(int32_t uid) {
|
||||
m_xCallbacks = CancelCallback(m_xCallbacks, uid);
|
||||
}
|
||||
|
||||
void ThreeAxisAccelerometerData::InvokeXCallback(HAL_Value value) {
|
||||
InvokeCallback(m_xCallbacks, "X", &value);
|
||||
}
|
||||
|
||||
double ThreeAxisAccelerometerData::GetX() { return m_x; }
|
||||
|
||||
void ThreeAxisAccelerometerData::SetX(double x) {
|
||||
double oldValue = m_x.exchange(x);
|
||||
if (oldValue != x) {
|
||||
InvokeXCallback(MakeDouble(x));
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ThreeAxisAccelerometerData::RegisterYCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {
|
||||
// Must return -1 on a null callback for error handling
|
||||
if (callback == nullptr) return -1;
|
||||
int32_t newUid = 0;
|
||||
{
|
||||
std::lock_guard<wpi::mutex> lock(m_registerMutex);
|
||||
m_yCallbacks =
|
||||
RegisterCallback(m_yCallbacks, "Y", callback, param, &newUid);
|
||||
}
|
||||
if (initialNotify) {
|
||||
// We know that the callback is not null because of earlier null check
|
||||
HAL_Value value = MakeDouble(GetY());
|
||||
callback("Y", param, &value);
|
||||
}
|
||||
return newUid;
|
||||
}
|
||||
|
||||
void ThreeAxisAccelerometerData::CancelYCallback(int32_t uid) {
|
||||
m_yCallbacks = CancelCallback(m_yCallbacks, uid);
|
||||
}
|
||||
|
||||
void ThreeAxisAccelerometerData::InvokeYCallback(HAL_Value value) {
|
||||
InvokeCallback(m_yCallbacks, "Y", &value);
|
||||
}
|
||||
|
||||
double ThreeAxisAccelerometerData::GetY() { return m_y; }
|
||||
|
||||
void ThreeAxisAccelerometerData::SetY(double y) {
|
||||
double oldValue = m_y.exchange(y);
|
||||
if (oldValue != y) {
|
||||
InvokeYCallback(MakeDouble(y));
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ThreeAxisAccelerometerData::RegisterZCallback(
|
||||
HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {
|
||||
// Must return -1 on a null callback for error handling
|
||||
if (callback == nullptr) return -1;
|
||||
int32_t newUid = 0;
|
||||
{
|
||||
std::lock_guard<wpi::mutex> lock(m_registerMutex);
|
||||
m_zCallbacks =
|
||||
RegisterCallback(m_zCallbacks, "Z", callback, param, &newUid);
|
||||
}
|
||||
if (initialNotify) {
|
||||
// We know that the callback is not null because of earlier null check
|
||||
HAL_Value value = MakeDouble(GetZ());
|
||||
callback("Z", param, &value);
|
||||
}
|
||||
return newUid;
|
||||
}
|
||||
|
||||
void ThreeAxisAccelerometerData::CancelZCallback(int32_t uid) {
|
||||
m_zCallbacks = CancelCallback(m_zCallbacks, uid);
|
||||
}
|
||||
|
||||
void ThreeAxisAccelerometerData::InvokeZCallback(HAL_Value value) {
|
||||
InvokeCallback(m_zCallbacks, "Z", &value);
|
||||
}
|
||||
|
||||
double ThreeAxisAccelerometerData::GetZ() { return m_z; }
|
||||
|
||||
void ThreeAxisAccelerometerData::SetZ(double z) {
|
||||
double oldValue = m_z.exchange(z);
|
||||
if (oldValue != z) {
|
||||
InvokeZCallback(MakeDouble(z));
|
||||
}
|
||||
x.Reset(0.0);
|
||||
y.Reset(0.0);
|
||||
z.Reset(0.0);
|
||||
}
|
||||
|
||||
@@ -7,11 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include <mockdata/NotifyListenerVector.h>
|
||||
#include <wpi/mutex.h>
|
||||
#include <mockdata/SimDataValue.h>
|
||||
|
||||
namespace hal {
|
||||
class ADXRS450_SpiGyroWrapper {
|
||||
@@ -25,25 +21,25 @@ class ADXRS450_SpiGyroWrapper {
|
||||
void HandleAutoReceiveData(uint8_t* buffer, int32_t numToRead,
|
||||
int32_t& outputCount);
|
||||
|
||||
virtual void ResetData();
|
||||
|
||||
int32_t RegisterAngleCallback(HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void CancelAngleCallback(int32_t uid);
|
||||
void InvokeAngleCallback(HAL_Value value);
|
||||
double GetAngle();
|
||||
HAL_Bool initialNotify) {
|
||||
return m_angle.RegisterCallback(callback, param, initialNotify);
|
||||
}
|
||||
void CancelAngleCallback(int32_t uid) { m_angle.CancelCallback(uid); }
|
||||
double GetAngle() { return m_angle; }
|
||||
void SetAngle(double angle);
|
||||
|
||||
virtual void ResetData();
|
||||
|
||||
private:
|
||||
int m_port;
|
||||
int m_readCallbackId;
|
||||
int m_autoReceiveReadCallbackId;
|
||||
|
||||
wpi::mutex m_registerMutex;
|
||||
wpi::mutex m_dataMutex;
|
||||
double m_angle = 0.0;
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Angle)
|
||||
|
||||
SimDataValue<double, MakeDouble, GetAngleName> m_angle{0.0};
|
||||
double m_angleDiff = 0.0;
|
||||
std::shared_ptr<NotifyListenerVector> m_angleCallbacks = nullptr;
|
||||
|
||||
static const double kAngleLsb;
|
||||
// The maximum difference that can fit inside of the shifted and masked data
|
||||
|
||||
@@ -7,50 +7,33 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include <mockdata/NotifyListenerVector.h>
|
||||
#include <wpi/mutex.h>
|
||||
#include <mockdata/SimDataValue.h>
|
||||
|
||||
namespace hal {
|
||||
class ThreeAxisAccelerometerData {
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(X);
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Y);
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Z);
|
||||
|
||||
public:
|
||||
ThreeAxisAccelerometerData();
|
||||
virtual ~ThreeAxisAccelerometerData();
|
||||
|
||||
virtual bool GetInitialized() const = 0;
|
||||
|
||||
int32_t RegisterXCallback(HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void CancelXCallback(int32_t uid);
|
||||
void InvokeXCallback(HAL_Value value);
|
||||
double GetX();
|
||||
void SetX(double x);
|
||||
double GetX() { return x; }
|
||||
void SetX(double x_) { x = x_; }
|
||||
|
||||
int32_t RegisterYCallback(HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void CancelYCallback(int32_t uid);
|
||||
void InvokeYCallback(HAL_Value value);
|
||||
double GetY();
|
||||
void SetY(double y);
|
||||
double GetY() { return y; }
|
||||
void SetY(double y_) { y = y_; }
|
||||
|
||||
int32_t RegisterZCallback(HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void CancelZCallback(int32_t uid);
|
||||
void InvokeZCallback(HAL_Value value);
|
||||
double GetZ();
|
||||
void SetZ(double z);
|
||||
double GetZ() { return z; }
|
||||
void SetZ(double z_) { z = z_; }
|
||||
|
||||
SimDataValue<double, MakeDouble, GetXName> x{0.0};
|
||||
SimDataValue<double, MakeDouble, GetYName> y{0.0};
|
||||
SimDataValue<double, MakeDouble, GetZName> z{0.0};
|
||||
|
||||
virtual void ResetData();
|
||||
|
||||
protected:
|
||||
wpi::mutex m_registerMutex;
|
||||
std::atomic<double> m_x{0.0};
|
||||
std::shared_ptr<NotifyListenerVector> m_xCallbacks = nullptr;
|
||||
std::atomic<double> m_y{0.0};
|
||||
std::shared_ptr<NotifyListenerVector> m_yCallbacks = nullptr;
|
||||
std::atomic<double> m_z{0.0};
|
||||
std::shared_ptr<NotifyListenerVector> m_zCallbacks = nullptr;
|
||||
};
|
||||
} // namespace hal
|
||||
|
||||
Reference in New Issue
Block a user