[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:
Peter Johnson
2020-12-23 15:54:11 -08:00
committed by GitHub
parent 699bbe21a4
commit 10b396b4c2
38 changed files with 1264 additions and 187 deletions

View File

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

View File

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

View File

@@ -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);
}
/*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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