mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
[sim] Various WebSockets fixes and enhancements (#2952)
This is a breaking change to the WebSockets layer to align it with recent specification documentation work. To support this, HAL SimValue changed readonly to a direction enum. This allows specifying bidirectional in addition to input and output. The SimValue change is specifically designed to avoid API and ABI breakage. This is completely transparent in C++; in Java a new callback class was added, and the old readonly functions have been marked deprecated. A new SimValue creation function for enums allows specifying double values for each enum value, not just strings. This allows mapping enum values to doubles in the WebSockets layer. A ":" in the SimDevice name now maps it to different WebSocket types (e.g. "Accel:Name" becomes type "Accel", device "Name"). The type is hidden in the GUI. Other WebSockets changes: * Implemented match_time and game_data * Added joystick rumble data * Added builtin accelerometer support * SimValue enums are mapped to string and double value on WS interface * Added WebSockets protocol specification * Added READMEs
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2019-2020 FIRST. 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. */
|
||||
@@ -14,19 +14,26 @@ HAL_SimDeviceHandle HAL_CreateSimDevice(const char* name) { return 0; }
|
||||
void HAL_FreeSimDevice(HAL_SimDeviceHandle handle) {}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
const char* name, int32_t direction,
|
||||
const struct HAL_Value* initialValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
const char* name, int32_t direction,
|
||||
int32_t numOptions,
|
||||
const char** options,
|
||||
int32_t initialValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValueEnumDouble(
|
||||
HAL_SimDeviceHandle device, const char* name, int32_t direction,
|
||||
int32_t numOptions, const char** options, const double* optionValues,
|
||||
int32_t initialValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) {
|
||||
value->type = HAL_UNASSIGNED;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,12 @@ const char** HALSIM_GetSimValueEnumOptions(HAL_SimValueHandle handle,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const double* HALSIM_GetSimValueEnumDoubleValues(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions) {
|
||||
*numOptions = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HALSIM_ResetSimDeviceData(void) {}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -69,25 +69,25 @@ Java_edu_wpi_first_hal_SimDeviceJNI_freeSimDevice
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: createSimValueNative
|
||||
* Signature: (ILjava/lang/String;ZIJD)I
|
||||
* Signature: (ILjava/lang/String;IIJD)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueNative
|
||||
(JNIEnv* env, jclass, jint device, jstring name, jboolean readonly, jint type,
|
||||
(JNIEnv* env, jclass, jint device, jstring name, jint direction, jint type,
|
||||
jlong value1, jdouble value2)
|
||||
{
|
||||
return HAL_CreateSimValue(device, JStringRef{env, name}.c_str(), readonly,
|
||||
return HAL_CreateSimValue(device, JStringRef{env, name}.c_str(), direction,
|
||||
ValueFromJava(type, value1, value2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: createSimValueEnum
|
||||
* Signature: (ILjava/lang/String;Z[Ljava/lang/Object;I)I
|
||||
* Signature: (ILjava/lang/String;I[Ljava/lang/Object;I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueEnum
|
||||
(JNIEnv* env, jclass, jint device, jstring name, jboolean readonly,
|
||||
(JNIEnv* env, jclass, jint device, jstring name, jint direction,
|
||||
jobjectArray options, jint initialValue)
|
||||
{
|
||||
size_t len = env->GetArrayLength(options);
|
||||
@@ -101,8 +101,37 @@ Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueEnum
|
||||
}
|
||||
wpi::SmallVector<const char*, 8> carr;
|
||||
for (auto&& val : arr) carr.push_back(val.c_str());
|
||||
return HAL_CreateSimValueEnum(device, JStringRef{env, name}.c_str(), readonly,
|
||||
len, carr.data(), initialValue);
|
||||
return HAL_CreateSimValueEnum(device, JStringRef{env, name}.c_str(),
|
||||
direction, len, carr.data(), initialValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: createSimValueEnumDouble
|
||||
* Signature: (ILjava/lang/String;I[Ljava/lang/Object;[DI)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueEnumDouble
|
||||
(JNIEnv* env, jclass, jint device, jstring name, jint direction,
|
||||
jobjectArray options, jdoubleArray optionValues, jint initialValue)
|
||||
{
|
||||
size_t len = env->GetArrayLength(options);
|
||||
size_t len2 = env->GetArrayLength(optionValues);
|
||||
if (len != len2) return 0;
|
||||
std::vector<std::string> arr;
|
||||
arr.reserve(len);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
JLocal<jstring> elem{
|
||||
env, static_cast<jstring>(env->GetObjectArrayElement(options, i))};
|
||||
if (!elem) return 0;
|
||||
arr.push_back(JStringRef{env, elem}.str());
|
||||
}
|
||||
|
||||
wpi::SmallVector<const char*, 8> carr;
|
||||
for (auto&& val : arr) carr.push_back(val.c_str());
|
||||
return HAL_CreateSimValueEnumDouble(
|
||||
device, JStringRef{env, name}.c_str(), direction, len, carr.data(),
|
||||
JDoubleArrayRef{env, optionValues}.array().data(), initialValue);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "SimulatorJNI.h"
|
||||
#include "edu_wpi_first_hal_simulation_SimDeviceDataJNI.h"
|
||||
#include "hal/SimDevice.h"
|
||||
#include "hal/handles/UnlimitedHandleResource.h"
|
||||
#include "hal/simulation/SimDeviceData.h"
|
||||
|
||||
@@ -40,12 +41,12 @@ struct DeviceInfo {
|
||||
};
|
||||
|
||||
struct ValueInfo {
|
||||
ValueInfo(const char* name_, HAL_SimValueHandle handle_, bool readonly_,
|
||||
ValueInfo(const char* name_, HAL_SimValueHandle handle_, int32_t direction_,
|
||||
const HAL_Value& value_)
|
||||
: name{name_}, handle{handle_}, readonly{readonly_}, value{value_} {}
|
||||
: name{name_}, handle{handle_}, direction{direction_}, value{value_} {}
|
||||
std::string name;
|
||||
HAL_SimValueHandle handle;
|
||||
bool readonly;
|
||||
int32_t direction;
|
||||
HAL_Value value;
|
||||
|
||||
jobject MakeJava(JNIEnv* env) const;
|
||||
@@ -87,11 +88,11 @@ static std::pair<jlong, jdouble> ToValue12(const HAL_Value& value) {
|
||||
|
||||
jobject ValueInfo::MakeJava(JNIEnv* env) const {
|
||||
static jmethodID func =
|
||||
env->GetMethodID(simValueInfoCls, "<init>", "(Ljava/lang/String;IZIJD)V");
|
||||
env->GetMethodID(simValueInfoCls, "<init>", "(Ljava/lang/String;IIIJD)V");
|
||||
auto [value1, value2] = ToValue12(value);
|
||||
return env->NewObject(simValueInfoCls, func, MakeJString(env, name),
|
||||
(jint)handle, (jboolean)readonly, (jint)value.type,
|
||||
value1, value2);
|
||||
(jint)handle, (jint)direction, (jint)value.type, value1,
|
||||
value2);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -111,16 +112,19 @@ class DeviceCallbackStore {
|
||||
|
||||
class ValueCallbackStore {
|
||||
public:
|
||||
explicit ValueCallbackStore(bool dirCallback) : m_dirCallback{dirCallback} {}
|
||||
|
||||
void create(JNIEnv* env, jobject obj) { m_call = JGlobal<jobject>(env, obj); }
|
||||
void performCallback(const char* name, HAL_SimValueHandle handle,
|
||||
bool readonly, const HAL_Value& value);
|
||||
int32_t direction, const HAL_Value& value);
|
||||
void free(JNIEnv* env) { m_call.free(env); }
|
||||
void setCallbackId(int32_t id) { callbackId = id; }
|
||||
int32_t getCallbackId() { return callbackId; }
|
||||
void setCallbackId(int32_t id) { m_callbackId = id; }
|
||||
int32_t getCallbackId() { return m_callbackId; }
|
||||
|
||||
private:
|
||||
wpi::java::JGlobal<jobject> m_call;
|
||||
int32_t callbackId;
|
||||
int32_t m_callbackId;
|
||||
bool m_dirCallback;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -159,7 +163,7 @@ void DeviceCallbackStore::performCallback(const char* name,
|
||||
|
||||
void ValueCallbackStore::performCallback(const char* name,
|
||||
HAL_SimValueHandle handle,
|
||||
bool readonly,
|
||||
int32_t direction,
|
||||
const HAL_Value& value) {
|
||||
JNIEnv* env;
|
||||
JavaVM* vm = sim::GetJVM();
|
||||
@@ -180,9 +184,16 @@ void ValueCallbackStore::performCallback(const char* name,
|
||||
}
|
||||
|
||||
auto [value1, value2] = ToValue12(value);
|
||||
env->CallVoidMethod(m_call, simValueCallbackCallback, MakeJString(env, name),
|
||||
(jint)handle, (jboolean)readonly, (jint)value.type,
|
||||
value1, value2);
|
||||
if (m_dirCallback) {
|
||||
env->CallVoidMethod(m_call, simValueCallbackCallback,
|
||||
MakeJString(env, name), (jint)handle, (jint)direction,
|
||||
(jint)value.type, value1, value2);
|
||||
} else {
|
||||
env->CallVoidMethod(m_call, simValueCallbackCallback,
|
||||
MakeJString(env, name), (jint)handle,
|
||||
(jboolean)(direction == HAL_SimValueOutput),
|
||||
(jint)value.type, value1, value2);
|
||||
}
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
@@ -255,11 +266,12 @@ typedef void (*FreeValueCallbackFunc)(int32_t uid);
|
||||
|
||||
template <typename THandle>
|
||||
static SIM_JniHandle AllocateValueCallback(
|
||||
JNIEnv* env, THandle h, jobject callback, jboolean initialNotify,
|
||||
JNIEnv* env, THandle h, jobject callback, bool dirCallback,
|
||||
jboolean initialNotify,
|
||||
int32_t (*createCallback)(THandle handle, void* param,
|
||||
HALSIM_SimValueCallback callback,
|
||||
HAL_Bool initialNotify)) {
|
||||
auto callbackStore = std::make_shared<ValueCallbackStore>();
|
||||
auto callbackStore = std::make_shared<ValueCallbackStore>(dirCallback);
|
||||
|
||||
auto handle = valueCallbackHandles->Allocate(callbackStore);
|
||||
|
||||
@@ -273,14 +285,14 @@ static SIM_JniHandle AllocateValueCallback(
|
||||
callbackStore->create(env, callback);
|
||||
|
||||
auto callbackFunc = [](const char* name, void* param,
|
||||
HAL_SimValueHandle handle, HAL_Bool readonly,
|
||||
HAL_SimValueHandle handle, int32_t direction,
|
||||
const HAL_Value* value) {
|
||||
uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
|
||||
SIM_JniHandle jnihandle = static_cast<SIM_JniHandle>(handleTmp);
|
||||
auto data = valueCallbackHandles->Get(jnihandle);
|
||||
if (!data) return;
|
||||
|
||||
data->performCallback(name, handle, readonly, *value);
|
||||
data->performCallback(name, handle, direction, *value);
|
||||
};
|
||||
|
||||
auto id = createCallback(h, handleAsVoidPtr, callbackFunc, initialNotify);
|
||||
@@ -504,7 +516,21 @@ Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimValueCreatedCallba
|
||||
(JNIEnv* env, jclass, jint device, jobject callback, jboolean initialNotify)
|
||||
{
|
||||
return AllocateValueCallback(env, static_cast<HAL_SimDeviceHandle>(device),
|
||||
callback, initialNotify,
|
||||
callback, false, initialNotify,
|
||||
&HALSIM_RegisterSimValueCreatedCallback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI
|
||||
* Method: registerSimValueCreatedCallback2
|
||||
* Signature: (ILjava/lang/Object;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimValueCreatedCallback2
|
||||
(JNIEnv* env, jclass, jint device, jobject callback, jboolean initialNotify)
|
||||
{
|
||||
return AllocateValueCallback(env, static_cast<HAL_SimDeviceHandle>(device),
|
||||
callback, true, initialNotify,
|
||||
&HALSIM_RegisterSimValueCreatedCallback);
|
||||
}
|
||||
|
||||
@@ -530,7 +556,21 @@ Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimValueChangedCallba
|
||||
(JNIEnv* env, jclass, jint handle, jobject callback, jboolean initialNotify)
|
||||
{
|
||||
return AllocateValueCallback(env, static_cast<HAL_SimValueHandle>(handle),
|
||||
callback, initialNotify,
|
||||
callback, false, initialNotify,
|
||||
&HALSIM_RegisterSimValueChangedCallback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI
|
||||
* Method: registerSimValueChangedCallback2
|
||||
* Signature: (ILjava/lang/Object;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimValueChangedCallback2
|
||||
(JNIEnv* env, jclass, jint handle, jobject callback, jboolean initialNotify)
|
||||
{
|
||||
return AllocateValueCallback(env, static_cast<HAL_SimValueHandle>(handle),
|
||||
callback, true, initialNotify,
|
||||
&HALSIM_RegisterSimValueChangedCallback);
|
||||
}
|
||||
|
||||
@@ -610,6 +650,20 @@ Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_getSimValueEnumOptions
|
||||
return jarr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI
|
||||
* Method: getSimValueEnumDoubleValues
|
||||
* Signature: (I)[D
|
||||
*/
|
||||
JNIEXPORT jdoubleArray JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_getSimValueEnumDoubleValues
|
||||
(JNIEnv* env, jclass, jint handle)
|
||||
{
|
||||
int32_t numElems = 0;
|
||||
const double* elems = HALSIM_GetSimValueEnumDoubleValues(handle, &numElems);
|
||||
return MakeJDoubleArray(env, wpi::makeArrayRef(elems, numElems));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI
|
||||
* Method: resetSimDeviceData
|
||||
|
||||
@@ -30,6 +30,17 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Direction of a simulated value (from the perspective of user code).
|
||||
*/
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_SimValueDirection) {
|
||||
HAL_SimValueInput = 0, /**< input to user code from the simulator */
|
||||
HAL_SimValueOutput, /**< output from user code to the simulator */
|
||||
HAL_SimValueBidir /**< bidirectional between user code and simulator */
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -67,21 +78,21 @@ void HAL_FreeSimDevice(HAL_SimDeviceHandle handle);
|
||||
*
|
||||
* @param device simulated device handle
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
const char* name, int32_t direction,
|
||||
const struct HAL_Value* initialValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C++" {
|
||||
inline HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
|
||||
const char* name,
|
||||
HAL_Bool readonly,
|
||||
int32_t direction,
|
||||
const HAL_Value& initialValue) {
|
||||
return HAL_CreateSimValue(device, name, readonly, &initialValue);
|
||||
return HAL_CreateSimValue(device, name, direction, &initialValue);
|
||||
}
|
||||
} // extern "C++"
|
||||
#endif
|
||||
@@ -94,16 +105,16 @@ inline HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
|
||||
*
|
||||
* @param device simulated device handle
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
inline HAL_SimValueHandle HAL_CreateSimValueDouble(HAL_SimDeviceHandle device,
|
||||
const char* name,
|
||||
HAL_Bool readonly,
|
||||
int32_t direction,
|
||||
double initialValue) {
|
||||
struct HAL_Value v = HAL_MakeDouble(initialValue);
|
||||
return HAL_CreateSimValue(device, name, readonly, &v);
|
||||
return HAL_CreateSimValue(device, name, direction, &v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,18 +127,40 @@ inline HAL_SimValueHandle HAL_CreateSimValueDouble(HAL_SimDeviceHandle device,
|
||||
*
|
||||
* @param device simulated device handle
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param numOptions number of enumerated value options (length of options)
|
||||
* @param options array of option descriptions
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated value handle
|
||||
*/
|
||||
HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
const char* name, int32_t direction,
|
||||
int32_t numOptions,
|
||||
const char** options,
|
||||
int32_t initialValue);
|
||||
|
||||
/**
|
||||
* Creates an enumerated value on a simulated device with double values.
|
||||
*
|
||||
* Enumerated values are always in the range 0 to numOptions-1.
|
||||
*
|
||||
* Returns 0 if not in simulation; this can be used to avoid calls
|
||||
* to Set/Get functions.
|
||||
*
|
||||
* @param device simulated device handle
|
||||
* @param name value name
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param numOptions number of enumerated value options (length of options)
|
||||
* @param options array of option descriptions
|
||||
* @param optionValues array of option double values
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated value handle
|
||||
*/
|
||||
HAL_SimValueHandle HAL_CreateSimValueEnumDouble(
|
||||
HAL_SimDeviceHandle device, const char* name, int32_t direction,
|
||||
int32_t numOptions, const char** options, const double* optionValues,
|
||||
int32_t initialValue);
|
||||
|
||||
/**
|
||||
* Creates a boolean value on a simulated device.
|
||||
*
|
||||
@@ -136,16 +169,16 @@ HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
|
||||
*
|
||||
* @param device simulated device handle
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
inline HAL_SimValueHandle HAL_CreateSimValueBoolean(HAL_SimDeviceHandle device,
|
||||
const char* name,
|
||||
HAL_Bool readonly,
|
||||
int32_t direction,
|
||||
HAL_Bool initialValue) {
|
||||
struct HAL_Value v = HAL_MakeBoolean(initialValue);
|
||||
return HAL_CreateSimValue(device, name, readonly, &v);
|
||||
return HAL_CreateSimValue(device, name, direction, &v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -419,6 +452,15 @@ class SimBoolean : public SimValue {
|
||||
*/
|
||||
class SimDevice {
|
||||
public:
|
||||
/**
|
||||
* Direction of a simulated value (from the perspective of user code).
|
||||
*/
|
||||
enum Direction {
|
||||
kInput = HAL_SimValueInput,
|
||||
kOutput = HAL_SimValueOutput,
|
||||
kBidir = HAL_SimValueBidir
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor that results in an "empty" object that is false in
|
||||
* a boolean context.
|
||||
@@ -512,13 +554,13 @@ class SimDevice {
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param initialValue initial value
|
||||
* @return simulated value object
|
||||
*/
|
||||
SimValue CreateValue(const char* name, bool readonly,
|
||||
SimValue CreateValue(const char* name, int32_t direction,
|
||||
const HAL_Value& initialValue) {
|
||||
return HAL_CreateSimValue(m_handle, name, readonly, &initialValue);
|
||||
return HAL_CreateSimValue(m_handle, name, direction, &initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,12 +570,13 @@ class SimDevice {
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param initialValue initial value
|
||||
* @return simulated double value object
|
||||
*/
|
||||
SimDouble CreateDouble(const char* name, bool readonly, double initialValue) {
|
||||
return HAL_CreateSimValueDouble(m_handle, name, readonly, initialValue);
|
||||
SimDouble CreateDouble(const char* name, int32_t direction,
|
||||
double initialValue) {
|
||||
return HAL_CreateSimValueDouble(m_handle, name, direction, initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,15 +588,15 @@ class SimDevice {
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param options array of option descriptions
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated enum value object
|
||||
*/
|
||||
SimEnum CreateEnum(const char* name, bool readonly,
|
||||
SimEnum CreateEnum(const char* name, int32_t direction,
|
||||
std::initializer_list<const char*> options,
|
||||
int32_t initialValue) {
|
||||
return HAL_CreateSimValueEnum(m_handle, name, readonly, options.size(),
|
||||
return HAL_CreateSimValueEnum(m_handle, name, direction, options.size(),
|
||||
const_cast<const char**>(options.begin()),
|
||||
initialValue);
|
||||
}
|
||||
@@ -567,18 +610,72 @@ class SimDevice {
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param options array of option descriptions
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated enum value object
|
||||
*/
|
||||
SimEnum CreateEnum(const char* name, bool readonly,
|
||||
SimEnum CreateEnum(const char* name, int32_t direction,
|
||||
wpi::ArrayRef<const char*> options, int32_t initialValue) {
|
||||
return HAL_CreateSimValueEnum(m_handle, name, readonly, options.size(),
|
||||
return HAL_CreateSimValueEnum(m_handle, name, direction, options.size(),
|
||||
const_cast<const char**>(options.data()),
|
||||
initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enumerated value on the simulated device with double values.
|
||||
*
|
||||
* Enumerated values are always in the range 0 to numOptions-1.
|
||||
*
|
||||
* If not in simulation, results in an "empty" object that evaluates to false
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param options array of option descriptions
|
||||
* @param optionValues array of option values (must be the same size as
|
||||
* options)
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated enum value object
|
||||
*/
|
||||
SimEnum CreateEnumDouble(const char* name, int32_t direction,
|
||||
std::initializer_list<const char*> options,
|
||||
std::initializer_list<double> optionValues,
|
||||
int32_t initialValue) {
|
||||
if (options.size() != optionValues.size()) return {};
|
||||
return HAL_CreateSimValueEnumDouble(
|
||||
m_handle, name, direction, options.size(),
|
||||
const_cast<const char**>(options.begin()), optionValues.begin(),
|
||||
initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enumerated value on the simulated device with double values.
|
||||
*
|
||||
* Enumerated values are always in the range 0 to numOptions-1.
|
||||
*
|
||||
* If not in simulation, results in an "empty" object that evaluates to false
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param options array of option descriptions
|
||||
* @param optionValues array of option values (must be the same size as
|
||||
* options)
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated enum value object
|
||||
*/
|
||||
SimEnum CreateEnumDouble(const char* name, int32_t direction,
|
||||
wpi::ArrayRef<const char*> options,
|
||||
wpi::ArrayRef<double> optionValues,
|
||||
int32_t initialValue) {
|
||||
if (options.size() != optionValues.size()) return {};
|
||||
return HAL_CreateSimValueEnumDouble(
|
||||
m_handle, name, direction, options.size(),
|
||||
const_cast<const char**>(options.data()), optionValues.data(),
|
||||
initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a boolean value on the simulated device.
|
||||
*
|
||||
@@ -586,12 +683,13 @@ class SimDevice {
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param direction input/output/bidir (from perspective of user code)
|
||||
* @param initialValue initial value
|
||||
* @return simulated boolean value object
|
||||
*/
|
||||
SimBoolean CreateBoolean(const char* name, bool readonly, bool initialValue) {
|
||||
return HAL_CreateSimValueBoolean(m_handle, name, readonly, initialValue);
|
||||
SimBoolean CreateBoolean(const char* name, int32_t direction,
|
||||
bool initialValue) {
|
||||
return HAL_CreateSimValueBoolean(m_handle, name, direction, initialValue);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -15,7 +15,7 @@ typedef void (*HALSIM_SimDeviceCallback)(const char* name, void* param,
|
||||
|
||||
typedef void (*HALSIM_SimValueCallback)(const char* name, void* param,
|
||||
HAL_SimValueHandle handle,
|
||||
HAL_Bool readonly,
|
||||
int32_t direction,
|
||||
const struct HAL_Value* value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -69,6 +69,9 @@ void HALSIM_EnumerateSimValues(HAL_SimDeviceHandle device, void* param,
|
||||
const char** HALSIM_GetSimValueEnumOptions(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions);
|
||||
|
||||
const double* HALSIM_GetSimValueEnumDoubleValues(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions);
|
||||
|
||||
void HALSIM_ResetSimDeviceData(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2019-2020 FIRST. 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. */
|
||||
@@ -33,19 +33,29 @@ void HAL_FreeSimDevice(HAL_SimDeviceHandle handle) {
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
const char* name, int32_t direction,
|
||||
const struct HAL_Value* initialValue) {
|
||||
return SimSimDeviceData->CreateValue(device, name, readonly, 0, nullptr,
|
||||
*initialValue);
|
||||
return SimSimDeviceData->CreateValue(device, name, direction, 0, nullptr,
|
||||
nullptr, *initialValue);
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
const char* name, int32_t direction,
|
||||
int32_t numOptions,
|
||||
const char** options,
|
||||
int32_t initialValue) {
|
||||
return SimSimDeviceData->CreateValue(device, name, readonly, numOptions,
|
||||
options, HAL_MakeEnum(initialValue));
|
||||
return SimSimDeviceData->CreateValue(device, name, direction, numOptions,
|
||||
options, nullptr,
|
||||
HAL_MakeEnum(initialValue));
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValueEnumDouble(
|
||||
HAL_SimDeviceHandle device, const char* name, int32_t direction,
|
||||
int32_t numOptions, const char** options, const double* optionValues,
|
||||
int32_t initialValue) {
|
||||
return SimSimDeviceData->CreateValue(device, name, direction, numOptions,
|
||||
options, optionValues,
|
||||
HAL_MakeEnum(initialValue));
|
||||
}
|
||||
|
||||
void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) {
|
||||
|
||||
@@ -122,11 +122,10 @@ void SimDeviceData::FreeDevice(HAL_SimDeviceHandle handle) {
|
||||
m_deviceFreed(deviceImpl->name.c_str(), handle + 1);
|
||||
}
|
||||
|
||||
HAL_SimValueHandle SimDeviceData::CreateValue(HAL_SimDeviceHandle device,
|
||||
const char* name, bool readonly,
|
||||
int32_t numOptions,
|
||||
const char** options,
|
||||
const HAL_Value& initialValue) {
|
||||
HAL_SimValueHandle SimDeviceData::CreateValue(
|
||||
HAL_SimDeviceHandle device, const char* name, int32_t direction,
|
||||
int32_t numOptions, const char** options, const double* optionValues,
|
||||
const HAL_Value& initialValue) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// look up device
|
||||
@@ -142,7 +141,7 @@ HAL_SimValueHandle SimDeviceData::CreateValue(HAL_SimDeviceHandle device,
|
||||
if (deviceImpl->values.size() >= 4095) return 0;
|
||||
|
||||
// create and save; encode device into handle
|
||||
auto valueImplPtr = std::make_unique<Value>(name, readonly, initialValue);
|
||||
auto valueImplPtr = std::make_unique<Value>(name, direction, initialValue);
|
||||
Value* valueImpl = valueImplPtr.get();
|
||||
HAL_SimValueHandle valueHandle =
|
||||
(device << 16) |
|
||||
@@ -159,10 +158,14 @@ HAL_SimValueHandle SimDeviceData::CreateValue(HAL_SimDeviceHandle device,
|
||||
valueImpl->enumOptions.back().c_str());
|
||||
}
|
||||
}
|
||||
// copy option values (if any provided)
|
||||
if (numOptions > 0 && optionValues) {
|
||||
valueImpl->enumOptionValues.assign(optionValues, optionValues + numOptions);
|
||||
}
|
||||
deviceImpl->valueMap[name] = valueImpl;
|
||||
|
||||
// notify callbacks
|
||||
deviceImpl->valueCreated(name, valueHandle, readonly, &initialValue);
|
||||
deviceImpl->valueCreated(name, valueHandle, direction, &initialValue);
|
||||
|
||||
return valueHandle;
|
||||
}
|
||||
@@ -191,7 +194,7 @@ void SimDeviceData::SetValue(HAL_SimValueHandle handle,
|
||||
|
||||
// notify callbacks
|
||||
valueImpl->changed(valueImpl->name.c_str(), valueImpl->handle,
|
||||
valueImpl->readonly, &value);
|
||||
valueImpl->direction, &value);
|
||||
}
|
||||
|
||||
int32_t SimDeviceData::RegisterDeviceCreatedCallback(
|
||||
@@ -273,7 +276,7 @@ int32_t SimDeviceData::RegisterValueCreatedCallback(
|
||||
// initial notifications
|
||||
if (initialNotify) {
|
||||
for (auto&& value : deviceImpl->values)
|
||||
callback(value->name.c_str(), param, value->handle, value->readonly,
|
||||
callback(value->name.c_str(), param, value->handle, value->direction,
|
||||
&value->value);
|
||||
}
|
||||
|
||||
@@ -302,7 +305,7 @@ int32_t SimDeviceData::RegisterValueChangedCallback(
|
||||
// initial notification
|
||||
if (initialNotify)
|
||||
callback(valueImpl->name.c_str(), param, valueImpl->handle,
|
||||
valueImpl->readonly, &valueImpl->value);
|
||||
valueImpl->direction, &valueImpl->value);
|
||||
|
||||
// encode device and value into uid
|
||||
return (((handle >> 16) & 0xfff) << 19) | ((handle & 0xfff) << 7) |
|
||||
@@ -337,7 +340,7 @@ void SimDeviceData::EnumerateValues(HAL_SimDeviceHandle device, void* param,
|
||||
if (!deviceImpl) return;
|
||||
|
||||
for (auto&& value : deviceImpl->values)
|
||||
callback(value->name.c_str(), param, value->handle, value->readonly,
|
||||
callback(value->name.c_str(), param, value->handle, value->direction,
|
||||
&value->value);
|
||||
}
|
||||
|
||||
@@ -355,6 +358,20 @@ const char** SimDeviceData::GetValueEnumOptions(HAL_SimValueHandle handle,
|
||||
return options.data();
|
||||
}
|
||||
|
||||
const double* SimDeviceData::GetValueEnumDoubleValues(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions) {
|
||||
*numOptions = 0;
|
||||
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Value* valueImpl = LookupValue(handle);
|
||||
if (!valueImpl) return nullptr;
|
||||
|
||||
// get list of option values (safe to return as they never change)
|
||||
auto& optionValues = valueImpl->enumOptionValues;
|
||||
*numOptions = optionValues.size();
|
||||
return optionValues.data();
|
||||
}
|
||||
|
||||
void SimDeviceData::ResetData() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_devices.clear();
|
||||
@@ -452,6 +469,11 @@ const char** HALSIM_GetSimValueEnumOptions(HAL_SimValueHandle handle,
|
||||
return SimSimDeviceData->GetValueEnumOptions(handle, numOptions);
|
||||
}
|
||||
|
||||
const double* HALSIM_GetSimValueEnumDoubleValues(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions) {
|
||||
return SimSimDeviceData->GetValueEnumDoubleValues(handle, numOptions);
|
||||
}
|
||||
|
||||
void HALSIM_ResetSimDeviceData(void) { SimSimDeviceData->ResetData(); }
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -126,15 +126,16 @@ class SimPrefixCallbackRegistry {
|
||||
class SimDeviceData {
|
||||
private:
|
||||
struct Value {
|
||||
Value(const char* name_, bool readonly_, const HAL_Value& value_)
|
||||
: name{name_}, readonly{readonly_}, value{value_} {}
|
||||
Value(const char* name_, int32_t direction_, const HAL_Value& value_)
|
||||
: name{name_}, direction{direction_}, value{value_} {}
|
||||
|
||||
HAL_SimValueHandle handle{0};
|
||||
std::string name;
|
||||
bool readonly;
|
||||
int32_t direction;
|
||||
HAL_Value value;
|
||||
std::vector<std::string> enumOptions;
|
||||
std::vector<const char*> cstrEnumOptions;
|
||||
std::vector<double> enumOptionValues;
|
||||
impl::SimUnnamedCallbackRegistry<HALSIM_SimValueCallback> changed;
|
||||
};
|
||||
|
||||
@@ -168,8 +169,9 @@ class SimDeviceData {
|
||||
HAL_SimDeviceHandle CreateDevice(const char* name);
|
||||
void FreeDevice(HAL_SimDeviceHandle handle);
|
||||
HAL_SimValueHandle CreateValue(HAL_SimDeviceHandle device, const char* name,
|
||||
bool readonly, int32_t numOptions,
|
||||
int32_t direction, int32_t numOptions,
|
||||
const char** options,
|
||||
const double* optionValues,
|
||||
const HAL_Value& initialValue);
|
||||
HAL_Value GetValue(HAL_SimValueHandle handle);
|
||||
void SetValue(HAL_SimValueHandle handle, const HAL_Value& value);
|
||||
@@ -212,6 +214,9 @@ class SimDeviceData {
|
||||
const char** GetValueEnumOptions(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions);
|
||||
|
||||
const double* GetValueEnumDoubleValues(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions);
|
||||
|
||||
void ResetData();
|
||||
};
|
||||
extern SimDeviceData* SimSimDeviceData;
|
||||
|
||||
Reference in New Issue
Block a user