mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
Add simulation generic device/value support
This allows high-level library classes to implement enhanced simulation support even if no low-level corresponding simulation library exists, and avoids the need for bit-banging complex interfaces like SPI or CAN.
This commit is contained in:
169
hal/src/main/java/edu/wpi/first/hal/HALValue.java
Normal file
169
hal/src/main/java/edu/wpi/first/hal/HALValue.java
Normal file
@@ -0,0 +1,169 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
@SuppressWarnings("AbbreviationAsWordInName")
|
||||
public final class HALValue {
|
||||
public static final int kUnassigned = 0;
|
||||
public static final int kBoolean = 0x01;
|
||||
public static final int kDouble = 0x02;
|
||||
public static final int kEnum = 0x04;
|
||||
public static final int kInt = 0x08;
|
||||
public static final int kLong = 0x10;
|
||||
|
||||
private int m_type;
|
||||
private long m_long;
|
||||
private double m_double;
|
||||
|
||||
private HALValue(double value, int type) {
|
||||
m_type = type;
|
||||
m_double = value;
|
||||
}
|
||||
|
||||
private HALValue(long value, int type) {
|
||||
m_type = type;
|
||||
m_long = value;
|
||||
}
|
||||
|
||||
private HALValue() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of the value.
|
||||
*
|
||||
* @return Type (e.g. kBoolean).
|
||||
*/
|
||||
public int getType() {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value as a boolean. Does not perform type checking.
|
||||
*
|
||||
* @return value contents
|
||||
*/
|
||||
public boolean getBoolean() {
|
||||
return m_long != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value as a long. Does not perform type checking.
|
||||
*
|
||||
* @return value contents
|
||||
*/
|
||||
public long getLong() {
|
||||
return m_long;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value as a double. Does not perform type checking.
|
||||
*
|
||||
* @return value contents
|
||||
*/
|
||||
public double getDouble() {
|
||||
return m_double;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the native long value. Does not perform type checking.
|
||||
*
|
||||
* @return value contents
|
||||
*/
|
||||
public long getNativeLong() {
|
||||
return m_long;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the native double value. Does not perform type checking.
|
||||
*
|
||||
* @return value contents
|
||||
*/
|
||||
public double getNativeDouble() {
|
||||
return m_double;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a HAL boolean value.
|
||||
*
|
||||
* @param value value
|
||||
* @return HAL value
|
||||
*/
|
||||
public static HALValue makeBoolean(boolean value) {
|
||||
return new HALValue(value ? 1 : 0, kBoolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a HAL enum value.
|
||||
*
|
||||
* @param value value
|
||||
* @return HAL value
|
||||
*/
|
||||
public static HALValue makeEnum(int value) {
|
||||
return new HALValue(value, kEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a HAL integer value.
|
||||
*
|
||||
* @param value value
|
||||
* @return HAL value
|
||||
*/
|
||||
public static HALValue makeInt(int value) {
|
||||
return new HALValue(value, kInt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a HAL long value.
|
||||
*
|
||||
* @param value value
|
||||
* @return HAL value
|
||||
*/
|
||||
public static HALValue makeLong(long value) {
|
||||
return new HALValue(value, kLong);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a HAL double value.
|
||||
*
|
||||
* @param value value
|
||||
* @return HAL value
|
||||
*/
|
||||
public static HALValue makeDouble(double value) {
|
||||
return new HALValue(value, kDouble);
|
||||
}
|
||||
|
||||
public static HALValue makeUnassigned() {
|
||||
return new HALValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a HAL value from its native components.
|
||||
*
|
||||
* @param type type
|
||||
* @param value1 long value (all except double)
|
||||
* @param value2 double value (for double only)
|
||||
* @return HAL value
|
||||
*/
|
||||
public static HALValue fromNative(int type, long value1, double value2) {
|
||||
switch (type) {
|
||||
case 0x01:
|
||||
return makeBoolean(value1 != 0);
|
||||
case 0x02:
|
||||
return makeDouble(value2);
|
||||
case 0x16:
|
||||
return makeEnum((int) value1);
|
||||
case 0x32:
|
||||
return makeInt((int) value1);
|
||||
case 0x64:
|
||||
return makeLong(value1);
|
||||
default:
|
||||
return makeUnassigned();
|
||||
}
|
||||
}
|
||||
}
|
||||
40
hal/src/main/java/edu/wpi/first/hal/SimBoolean.java
Normal file
40
hal/src/main/java/edu/wpi/first/hal/SimBoolean.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
/**
|
||||
* A wrapper around a simulator boolean value handle.
|
||||
*/
|
||||
public class SimBoolean extends SimValue {
|
||||
/**
|
||||
* Wraps a simulated value handle as returned by SimDeviceJNI.createSimValueBoolean().
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
*/
|
||||
public SimBoolean(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the simulated value.
|
||||
*
|
||||
* @return The current value
|
||||
*/
|
||||
public boolean get() {
|
||||
return SimDeviceJNI.getSimValueBoolean(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the simulated value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void set(boolean value) {
|
||||
SimDeviceJNI.setSimValueBoolean(m_handle, value);
|
||||
}
|
||||
}
|
||||
171
hal/src/main/java/edu/wpi/first/hal/SimDevice.java
Normal file
171
hal/src/main/java/edu/wpi/first/hal/SimDevice.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
/**
|
||||
* A wrapper around a simulator device handle.
|
||||
*/
|
||||
public class SimDevice implements AutoCloseable {
|
||||
/**
|
||||
* Creates a simulated device.
|
||||
*
|
||||
* <p>The device name must be unique. Returns null if the device name
|
||||
* already exists. If multiple instances of the same device are desired,
|
||||
* recommend appending the instance/unique identifer in brackets to the base
|
||||
* name, e.g. "device[1]".
|
||||
*
|
||||
* <p>null is returned if not in simulation.
|
||||
*
|
||||
* @param name device name
|
||||
* @return simulated device object
|
||||
*/
|
||||
public static SimDevice create(String name) {
|
||||
int handle = SimDeviceJNI.createSimDevice(name);
|
||||
if (handle <= 0) {
|
||||
return null;
|
||||
}
|
||||
return new SimDevice(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simulated device.
|
||||
*
|
||||
* <p>The device name must be unique. Returns null if the device name
|
||||
* already exists. This is a convenience method that appends index in
|
||||
* brackets to the device name, e.g. passing index=1 results in "device[1]"
|
||||
* for the device name.
|
||||
*
|
||||
* <p>null is returned if not in simulation.
|
||||
*
|
||||
* @param name device name
|
||||
* @param index device index number to append to name
|
||||
* @return simulated device object
|
||||
*/
|
||||
public static SimDevice create(String name, int index) {
|
||||
return create(name + "[" + index + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simulated device.
|
||||
*
|
||||
* <p>The device name must be unique. Returns null if the device name
|
||||
* already exists. This is a convenience method that appends index and
|
||||
* channel in brackets to the device name, e.g. passing index=1 and channel=2
|
||||
* results in "device[1,2]" for the device name.
|
||||
*
|
||||
* <p>null is returned if not in simulation.
|
||||
*
|
||||
* @param name device name
|
||||
* @param index device index number to append to name
|
||||
* @param channel device channel number to append to name
|
||||
* @return simulated device object
|
||||
*/
|
||||
public static SimDevice create(String name, int index, int channel) {
|
||||
return create(name + "[" + index + "," + channel + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a simulated device handle as returned by SimDeviceJNI.createSimDevice().
|
||||
*
|
||||
* @param handle simulated device handle
|
||||
*/
|
||||
public SimDevice(int handle) {
|
||||
m_handle = handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SimDeviceJNI.freeSimDevice(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal device handle.
|
||||
*
|
||||
* @return internal handle
|
||||
*/
|
||||
public int getNativeHandle() {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a value on the simulated device.
|
||||
*
|
||||
* <p>Returns null if not in simulation.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated value object
|
||||
*/
|
||||
public SimValue createValue(String name, boolean readonly, HALValue initialValue) {
|
||||
int handle = SimDeviceJNI.createSimValue(m_handle, name, readonly, initialValue);
|
||||
if (handle <= 0) {
|
||||
return null;
|
||||
}
|
||||
return new SimValue(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double value on the simulated device.
|
||||
*
|
||||
* <p>Returns null if not in simulation.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated double value object
|
||||
*/
|
||||
public SimDouble createDouble(String name, boolean readonly, double initialValue) {
|
||||
int handle = SimDeviceJNI.createSimValueDouble(m_handle, name, readonly, initialValue);
|
||||
if (handle <= 0) {
|
||||
return null;
|
||||
}
|
||||
return new SimDouble(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enumerated value on the simulated device.
|
||||
*
|
||||
* <p>Enumerated values are always in the range 0 to numOptions-1.
|
||||
*
|
||||
* <p>Returns null if not in simulation.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param options array of option descriptions
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated enum value object
|
||||
*/
|
||||
public SimEnum createEnum(String name, boolean readonly, String[] options, int initialValue) {
|
||||
int handle = SimDeviceJNI.createSimValueEnum(m_handle, name, readonly, options, initialValue);
|
||||
if (handle <= 0) {
|
||||
return null;
|
||||
}
|
||||
return new SimEnum(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a boolean value on the simulated device.
|
||||
*
|
||||
* <p>Returns null if not in simulation.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated boolean value object
|
||||
*/
|
||||
public SimBoolean createBoolean(String name, boolean readonly, boolean initialValue) {
|
||||
int handle = SimDeviceJNI.createSimValueBoolean(m_handle, name, readonly, initialValue);
|
||||
if (handle <= 0) {
|
||||
return null;
|
||||
}
|
||||
return new SimBoolean(handle);
|
||||
}
|
||||
|
||||
private final int m_handle;
|
||||
}
|
||||
183
hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java
Normal file
183
hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
public class SimDeviceJNI extends JNIWrapper {
|
||||
/**
|
||||
* Creates a simulated device.
|
||||
*
|
||||
* <p>The device name must be unique. 0 is returned if the device name
|
||||
* already exists. If multiple instances of the same device are desired,
|
||||
* recommend appending the instance/unique identifer in brackets to the base
|
||||
* name, e.g. "device[1]".
|
||||
*
|
||||
* <p>0 is returned if not in simulation.
|
||||
*
|
||||
* @param name device name
|
||||
* @return simulated device handle
|
||||
*/
|
||||
public static native int createSimDevice(String name);
|
||||
|
||||
/**
|
||||
* Frees a simulated device.
|
||||
*
|
||||
* <p>This also allows the same device name to be used again.
|
||||
* This also frees all the simulated values created on the device.
|
||||
*
|
||||
* @param handle simulated device handle
|
||||
*/
|
||||
public static native void freeSimDevice(int handle);
|
||||
|
||||
private static native int createSimValueNative(int device, String name, boolean readonly,
|
||||
int type, long value1, double value2);
|
||||
|
||||
/**
|
||||
* Creates a value on a simulated device.
|
||||
*
|
||||
* <p>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 readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
public static int createSimValue(int device, String name, boolean readonly,
|
||||
HALValue initialValue) {
|
||||
return createSimValueNative(device, name, readonly, initialValue.getType(),
|
||||
initialValue.getNativeLong(), initialValue.getNativeDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double value on a simulated device.
|
||||
*
|
||||
* <p>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 readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
public static int createSimValueDouble(int device, String name, boolean readonly,
|
||||
double initialValue) {
|
||||
return createSimValueNative(device, name, readonly, HALValue.kDouble, 0, initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enumerated value on a simulated device.
|
||||
*
|
||||
* <p>Enumerated values are always in the range 0 to numOptions-1.
|
||||
*
|
||||
* <p>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 readonly if the value should not be written from simulation side
|
||||
* @param options array of option descriptions
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated value handle
|
||||
*/
|
||||
public static native int createSimValueEnum(int device, String name, boolean readonly,
|
||||
String[] options, int initialValue);
|
||||
|
||||
/**
|
||||
* Creates a boolean value on a simulated device.
|
||||
*
|
||||
* <p>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 readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
public static int createSimValueBoolean(int device, String name, boolean readonly,
|
||||
boolean initialValue) {
|
||||
return createSimValueNative(device, name, readonly, HALValue.kBoolean,
|
||||
initialValue ? 1 : 0, 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a simulated value.
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @return The current value
|
||||
*/
|
||||
public static native HALValue getSimValue(int handle);
|
||||
|
||||
/**
|
||||
* Gets a simulated value (double).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @return The current value
|
||||
*/
|
||||
public static native double getSimValueDouble(int handle);
|
||||
|
||||
/**
|
||||
* Gets a simulated value (enum).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @return The current value
|
||||
*/
|
||||
public static native int getSimValueEnum(int handle);
|
||||
|
||||
/**
|
||||
* Gets a simulated value (boolean).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @return The current value
|
||||
*/
|
||||
public static native boolean getSimValueBoolean(int handle);
|
||||
|
||||
private static native void setSimValueNative(int handle, int type, long value1, double value2);
|
||||
|
||||
/**
|
||||
* Sets a simulated value.
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value the value to set
|
||||
*/
|
||||
public static void setSimValue(int handle, HALValue value) {
|
||||
setSimValueNative(handle, value.getType(), value.getNativeLong(), value.getNativeDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a simulated value (double).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value the value to set
|
||||
*/
|
||||
public static void setSimValueDouble(int handle, double value) {
|
||||
setSimValueNative(handle, HALValue.kDouble, 0, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a simulated value (enum).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value the value to set
|
||||
*/
|
||||
public static void setSimValueEnum(int handle, int value) {
|
||||
setSimValueNative(handle, HALValue.kEnum, value, 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a simulated value (boolean).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value the value to set
|
||||
*/
|
||||
public static void setSimValueBoolean(int handle, boolean value) {
|
||||
setSimValueNative(handle, HALValue.kBoolean, value ? 1 : 0, 0.0);
|
||||
}
|
||||
}
|
||||
40
hal/src/main/java/edu/wpi/first/hal/SimDouble.java
Normal file
40
hal/src/main/java/edu/wpi/first/hal/SimDouble.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
/**
|
||||
* A wrapper around a simulator double value handle.
|
||||
*/
|
||||
public class SimDouble extends SimValue {
|
||||
/**
|
||||
* Wraps a simulated value handle as returned by SimDeviceJNI.createSimValueDouble().
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
*/
|
||||
public SimDouble(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the simulated value.
|
||||
*
|
||||
* @return The current value
|
||||
*/
|
||||
public double get() {
|
||||
return SimDeviceJNI.getSimValueDouble(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the simulated value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void set(double value) {
|
||||
SimDeviceJNI.setSimValueDouble(m_handle, value);
|
||||
}
|
||||
}
|
||||
40
hal/src/main/java/edu/wpi/first/hal/SimEnum.java
Normal file
40
hal/src/main/java/edu/wpi/first/hal/SimEnum.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
/**
|
||||
* A wrapper around a simulator enum value handle.
|
||||
*/
|
||||
public class SimEnum extends SimValue {
|
||||
/**
|
||||
* Wraps a simulated value handle as returned by SimDeviceJNI.createSimValueEnum().
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
*/
|
||||
public SimEnum(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the simulated value.
|
||||
*
|
||||
* @return The current value
|
||||
*/
|
||||
public int get() {
|
||||
return SimDeviceJNI.getSimValueEnum(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the simulated value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void set(int value) {
|
||||
SimDeviceJNI.setSimValueEnum(m_handle, value);
|
||||
}
|
||||
}
|
||||
51
hal/src/main/java/edu/wpi/first/hal/SimValue.java
Normal file
51
hal/src/main/java/edu/wpi/first/hal/SimValue.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
/**
|
||||
* A wrapper around a simulator value handle.
|
||||
*/
|
||||
public class SimValue {
|
||||
/**
|
||||
* Wraps a simulated value handle as returned by SimDeviceJNI.createSimValue().
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
*/
|
||||
public SimValue(int handle) {
|
||||
m_handle = handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal device handle.
|
||||
*
|
||||
* @return internal handle
|
||||
*/
|
||||
public int getNativeHandle() {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the simulated value.
|
||||
*
|
||||
* @return The current value
|
||||
*/
|
||||
public HALValue getValue() {
|
||||
return SimDeviceJNI.getSimValue(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the simulated value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(HALValue value) {
|
||||
SimDeviceJNI.setSimValue(m_handle, value);
|
||||
}
|
||||
|
||||
protected final int m_handle;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2018-2019 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. */
|
||||
@@ -7,29 +7,12 @@
|
||||
|
||||
package edu.wpi.first.hal.sim;
|
||||
|
||||
import edu.wpi.first.hal.HALValue;
|
||||
|
||||
public interface NotifyCallback {
|
||||
void callback(String name, SimValue value);
|
||||
void callback(String name, HALValue value);
|
||||
|
||||
default void callbackNative(String name, int type, long value1, double value2) {
|
||||
switch (type) {
|
||||
case 0x01:
|
||||
callback(name, SimValue.makeBoolean(value1 != 0));
|
||||
break;
|
||||
case 0x02:
|
||||
callback(name, SimValue.makeDouble(value2));
|
||||
break;
|
||||
case 0x16:
|
||||
callback(name, SimValue.makeEnum((int) value1));
|
||||
break;
|
||||
case 0x32:
|
||||
callback(name, SimValue.makeInt((int) value1));
|
||||
break;
|
||||
case 0x64:
|
||||
callback(name, SimValue.makeLong(value1));
|
||||
break;
|
||||
default:
|
||||
callback(name, SimValue.makeUnassigned());
|
||||
break;
|
||||
}
|
||||
callback(name, HALValue.fromNative(type, value1, value2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal.sim;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SimDeviceCallback {
|
||||
void callback(String name, int handle);
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal.sim;
|
||||
|
||||
public final class SimValue {
|
||||
private boolean m_boolean;
|
||||
private long m_long;
|
||||
private double m_double;
|
||||
|
||||
private SimValue(boolean b) {
|
||||
m_boolean = b;
|
||||
}
|
||||
|
||||
private SimValue(double v) {
|
||||
m_double = v;
|
||||
}
|
||||
|
||||
private SimValue(long v) {
|
||||
m_long = v;
|
||||
}
|
||||
|
||||
private SimValue() {
|
||||
|
||||
}
|
||||
|
||||
public boolean getBoolean() {
|
||||
return m_boolean;
|
||||
}
|
||||
|
||||
public long getLong() {
|
||||
return m_long;
|
||||
}
|
||||
|
||||
public double getDouble() {
|
||||
return m_double;
|
||||
}
|
||||
|
||||
public static SimValue makeBoolean(boolean value) {
|
||||
return new SimValue(value);
|
||||
}
|
||||
|
||||
public static SimValue makeEnum(int value) {
|
||||
return new SimValue(value);
|
||||
}
|
||||
|
||||
public static SimValue makeInt(int value) {
|
||||
return new SimValue(value);
|
||||
}
|
||||
|
||||
public static SimValue makeLong(long value) {
|
||||
return new SimValue(value);
|
||||
}
|
||||
|
||||
public static SimValue makeDouble(double value) {
|
||||
return new SimValue(value);
|
||||
}
|
||||
|
||||
public static SimValue makeUnassigned() {
|
||||
return new SimValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal.sim;
|
||||
|
||||
import edu.wpi.first.hal.HALValue;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SimValueCallback {
|
||||
void callback(String name, int handle, boolean readonly, HALValue value);
|
||||
|
||||
default void callbackNative(String name, int handle, boolean readonly, int type, long value1, double value2) {
|
||||
callback(name, handle, readonly, HALValue.fromNative(type, value1, value2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal.sim.mockdata;
|
||||
|
||||
import edu.wpi.first.hal.sim.SimDeviceCallback;
|
||||
import edu.wpi.first.hal.sim.SimValueCallback;
|
||||
import edu.wpi.first.hal.HALValue;
|
||||
import edu.wpi.first.hal.JNIWrapper;
|
||||
|
||||
public class SimDeviceDataJNI extends JNIWrapper {
|
||||
public static native int registerSimDeviceCreatedCallback(String prefix, SimDeviceCallback callback, boolean initialNotify);
|
||||
public static native void cancelSimDeviceCreatedCallback(int uid);
|
||||
|
||||
public static native int registerSimDeviceFreedCallback(String prefix, SimDeviceCallback callback);
|
||||
public static native void cancelSimDeviceFreedCallback(int uid);
|
||||
|
||||
public static native int getSimDeviceHandle(String name);
|
||||
|
||||
public static native int getSimValueDeviceHandle(int handle);
|
||||
|
||||
public static class SimDeviceInfo {
|
||||
public SimDeviceInfo(String name, int handle) {
|
||||
this.name = name;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
String name;
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
int handle;
|
||||
}
|
||||
public static native SimDeviceInfo[] enumerateSimDevices(String prefix);
|
||||
|
||||
public static native int registerSimValueCreatedCallback(int device, SimValueCallback callback, boolean initialNotify);
|
||||
public static native void cancelSimValueCreatedCallback(int uid);
|
||||
|
||||
public static native int registerSimValueChangedCallback(int handle, SimValueCallback callback, boolean initialNotify);
|
||||
public static native void cancelSimValueChangedCallback(int uid);
|
||||
|
||||
public static native int getSimValueHandle(int device, String name);
|
||||
|
||||
public static class SimValueInfo {
|
||||
public SimValueInfo(String name, int handle, boolean readonly, int type, long value1, double value2) {
|
||||
this.name = name;
|
||||
this.handle = handle;
|
||||
this.readonly = readonly;
|
||||
this.value = HALValue.fromNative(type, value1, value2);
|
||||
}
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
String name;
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
int handle;
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
boolean readonly;
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
HALValue value;
|
||||
}
|
||||
public static native SimValueInfo[] enumerateSimValues(int device);
|
||||
|
||||
public static native String[] getSimValueEnumOptions(int handle);
|
||||
|
||||
public static native void resetSimDeviceData();
|
||||
}
|
||||
41
hal/src/main/native/athena/SimDevice.cpp
Normal file
41
hal/src/main/native/athena/SimDevice.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "hal/SimDevice.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
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 struct HAL_Value* initialValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
int32_t numOptions,
|
||||
const char** options,
|
||||
int32_t initialValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) {
|
||||
value->type = HAL_UNASSIGNED;
|
||||
}
|
||||
|
||||
void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value) {
|
||||
}
|
||||
|
||||
hal::SimDevice::SimDevice(const char* name, int index) {}
|
||||
|
||||
hal::SimDevice::SimDevice(const char* name, int index, int channel) {}
|
||||
|
||||
} // extern "C"
|
||||
@@ -49,13 +49,15 @@ static JClass canStatusCls;
|
||||
static JClass matchInfoDataCls;
|
||||
static JClass accumulatorResultCls;
|
||||
static JClass canDataCls;
|
||||
static JClass halValueCls;
|
||||
|
||||
static const JClassInit classes[] = {
|
||||
{"edu/wpi/first/hal/PWMConfigDataResult", &pwmConfigDataResultCls},
|
||||
{"edu/wpi/first/hal/can/CANStatus", &canStatusCls},
|
||||
{"edu/wpi/first/hal/MatchInfoData", &matchInfoDataCls},
|
||||
{"edu/wpi/first/hal/AccumulatorResult", &accumulatorResultCls},
|
||||
{"edu/wpi/first/hal/CANData", &canDataCls}};
|
||||
{"edu/wpi/first/hal/CANData", &canDataCls},
|
||||
{"edu/wpi/first/hal/HALValue", &halValueCls}};
|
||||
|
||||
static const JExceptionInit exceptions[] = {
|
||||
{"java/lang/IllegalArgumentException", &illegalArgExCls},
|
||||
@@ -224,8 +226,9 @@ jobject CreatePWMConfigDataResult(JNIEnv* env, int32_t maxPwm,
|
||||
int32_t deadbandMinPwm, int32_t minPwm) {
|
||||
static jmethodID constructor =
|
||||
env->GetMethodID(pwmConfigDataResultCls, "<init>", "(IIIII)V");
|
||||
return env->NewObject(pwmConfigDataResultCls, constructor, maxPwm,
|
||||
deadbandMaxPwm, centerPwm, deadbandMinPwm, minPwm);
|
||||
return env->NewObject(pwmConfigDataResultCls, constructor, (jint)maxPwm,
|
||||
(jint)deadbandMaxPwm, (jint)centerPwm,
|
||||
(jint)deadbandMinPwm, (jint)minPwm);
|
||||
}
|
||||
|
||||
void SetCanStatusObject(JNIEnv* env, jobject canStatus,
|
||||
@@ -271,6 +274,34 @@ jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
|
||||
return retVal;
|
||||
}
|
||||
|
||||
jobject CreateHALValue(JNIEnv* env, const HAL_Value& value) {
|
||||
static jmethodID fromNative = env->GetStaticMethodID(
|
||||
halValueCls, "fromNative", "(IJD)Ledu/wpi/first/hal/HALValue;");
|
||||
jlong value1 = 0;
|
||||
jdouble value2 = 0.0;
|
||||
switch (value.type) {
|
||||
case HAL_BOOLEAN:
|
||||
value1 = value.data.v_boolean;
|
||||
break;
|
||||
case HAL_DOUBLE:
|
||||
value2 = value.data.v_double;
|
||||
break;
|
||||
case HAL_ENUM:
|
||||
value1 = value.data.v_enum;
|
||||
break;
|
||||
case HAL_INT:
|
||||
value1 = value.data.v_int;
|
||||
break;
|
||||
case HAL_LONG:
|
||||
value1 = value.data.v_long;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return env->CallStaticObjectMethod(halValueCls, fromNative, (jint)value.type,
|
||||
value1, value2);
|
||||
}
|
||||
|
||||
JavaVM* GetJVM() { return jvm; }
|
||||
|
||||
} // namespace frc
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2016-2019 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,6 +14,7 @@
|
||||
#include <wpi/StringRef.h>
|
||||
|
||||
struct HAL_MatchInfo;
|
||||
struct HAL_Value;
|
||||
|
||||
namespace frc {
|
||||
|
||||
@@ -67,6 +68,8 @@ void SetAccumulatorResultObject(JNIEnv* env, jobject accumulatorResult,
|
||||
jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
|
||||
uint64_t timestamp);
|
||||
|
||||
jobject CreateHALValue(JNIEnv* env, const HAL_Value& value);
|
||||
|
||||
JavaVM* GetJVM();
|
||||
|
||||
} // namespace frc
|
||||
|
||||
168
hal/src/main/native/cpp/jni/SimDeviceJNI.cpp
Normal file
168
hal/src/main/native/cpp/jni/SimDeviceJNI.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <wpi/jni_util.h>
|
||||
|
||||
#include "HALUtil.h"
|
||||
#include "edu_wpi_first_hal_SimDeviceJNI.h"
|
||||
#include "hal/SimDevice.h"
|
||||
|
||||
using namespace wpi::java;
|
||||
|
||||
static HAL_Value ValueFromJava(jint type, jlong value1, jdouble value2) {
|
||||
HAL_Value value;
|
||||
value.type = static_cast<HAL_Type>(type);
|
||||
switch (value.type) {
|
||||
case HAL_BOOLEAN:
|
||||
value.data.v_boolean = value1;
|
||||
break;
|
||||
case HAL_DOUBLE:
|
||||
value.data.v_double = value2;
|
||||
break;
|
||||
case HAL_ENUM:
|
||||
value.data.v_enum = value1;
|
||||
break;
|
||||
case HAL_INT:
|
||||
value.data.v_int = value1;
|
||||
break;
|
||||
case HAL_LONG:
|
||||
value.data.v_long = value1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: createSimDevice
|
||||
* Signature: (Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_createSimDevice
|
||||
(JNIEnv* env, jclass, jstring name)
|
||||
{
|
||||
return HAL_CreateSimDevice(JStringRef{env, name}.c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: freeSimDevice
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_freeSimDevice
|
||||
(JNIEnv*, jclass, jint handle)
|
||||
{
|
||||
HAL_FreeSimDevice(handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: createSimValueNative
|
||||
* Signature: (ILjava/lang/String;ZIJD)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueNative
|
||||
(JNIEnv* env, jclass, jint device, jstring name, jboolean readonly, jint type,
|
||||
jlong value1, jdouble value2)
|
||||
{
|
||||
return HAL_CreateSimValue(device, JStringRef{env, name}.c_str(), readonly,
|
||||
ValueFromJava(type, value1, value2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: createSimValueEnum
|
||||
* Signature: (ILjava/lang/String;Z[Ljava/lang/Object;I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueEnum
|
||||
(JNIEnv* env, jclass, jint device, jstring name, jboolean readonly,
|
||||
jobjectArray options, jint initialValue)
|
||||
{
|
||||
size_t len = env->GetArrayLength(options);
|
||||
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_CreateSimValueEnum(device, JStringRef{env, name}.c_str(), readonly,
|
||||
len, carr.data(), initialValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: getSimValue
|
||||
* Signature: (I)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_getSimValue
|
||||
(JNIEnv* env, jclass, jint handle)
|
||||
{
|
||||
return frc::CreateHALValue(env, HAL_GetSimValue(handle));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: getSimValueDouble
|
||||
* Signature: (I)D
|
||||
*/
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_getSimValueDouble
|
||||
(JNIEnv*, jclass, jint handle)
|
||||
{
|
||||
return HAL_GetSimValueDouble(handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: getSimValueEnum
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_getSimValueEnum
|
||||
(JNIEnv*, jclass, jint handle)
|
||||
{
|
||||
return HAL_GetSimValueEnum(handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: getSimValueBoolean
|
||||
* Signature: (I)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_getSimValueBoolean
|
||||
(JNIEnv*, jclass, jint handle)
|
||||
{
|
||||
return HAL_GetSimValueBoolean(handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_SimDeviceJNI
|
||||
* Method: setSimValueNative
|
||||
* Signature: (IIJD)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_SimDeviceJNI_setSimValueNative
|
||||
(JNIEnv*, jclass, jint handle, jint type, jlong value1, jdouble value2)
|
||||
{
|
||||
HAL_SetSimValue(handle, ValueFromJava(type, value1, value2));
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "hal/Relay.h"
|
||||
#include "hal/SPI.h"
|
||||
#include "hal/SerialPort.h"
|
||||
#include "hal/SimDevice.h"
|
||||
#include "hal/Solenoid.h"
|
||||
#include "hal/Threads.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
610
hal/src/main/native/include/hal/SimDevice.h
Normal file
610
hal/src/main/native/include/hal/SimDevice.h
Normal file
@@ -0,0 +1,610 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <initializer_list>
|
||||
|
||||
#include <wpi/ArrayRef.h>
|
||||
#endif
|
||||
|
||||
#include "hal/Types.h"
|
||||
#include "hal/Value.h"
|
||||
|
||||
/**
|
||||
* @defgroup hal_simdevice Simulator Device Framework
|
||||
* @ingroup hal_capi
|
||||
* HAL Simulator Device Framework. This enables creating simulation-only
|
||||
* variables for higher level device access. For example, a device such as
|
||||
* a SPI gyro can expose angle and rate variables to enable direct access
|
||||
* from simulation extensions or user test code instead of requiring that
|
||||
* the SPI bit-level protocol be implemented in simulation code.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a simulated device.
|
||||
*
|
||||
* The device name must be unique. 0 is returned if the device name already
|
||||
* exists. If multiple instances of the same device are desired, recommend
|
||||
* appending the instance/unique identifer in brackets to the base name,
|
||||
* e.g. "device[1]".
|
||||
*
|
||||
* 0 is returned if not in simulation.
|
||||
*
|
||||
* @param name device name
|
||||
* @return simulated device handle
|
||||
*/
|
||||
HAL_SimDeviceHandle HAL_CreateSimDevice(const char* name);
|
||||
|
||||
/**
|
||||
* Frees a simulated device.
|
||||
*
|
||||
* This also allows the same device name to be used again.
|
||||
* This also frees all the simulated values created on the device.
|
||||
*
|
||||
* @param handle simulated device handle
|
||||
*/
|
||||
void HAL_FreeSimDevice(HAL_SimDeviceHandle handle);
|
||||
|
||||
/**
|
||||
* Creates a value on a simulated device.
|
||||
*
|
||||
* 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 readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
const struct HAL_Value* initialValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C++" {
|
||||
inline HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
|
||||
const char* name,
|
||||
HAL_Bool readonly,
|
||||
const HAL_Value& initialValue) {
|
||||
return HAL_CreateSimValue(device, name, readonly, &initialValue);
|
||||
}
|
||||
} // extern "C++"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a double value on a simulated device.
|
||||
*
|
||||
* 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 readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
inline HAL_SimValueHandle HAL_CreateSimValueDouble(HAL_SimDeviceHandle device,
|
||||
const char* name,
|
||||
HAL_Bool readonly,
|
||||
double initialValue) {
|
||||
struct HAL_Value v = HAL_MakeDouble(initialValue);
|
||||
return HAL_CreateSimValue(device, name, readonly, &v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enumerated value on a simulated device.
|
||||
*
|
||||
* 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 readonly if the value should not be written from simulation side
|
||||
* @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,
|
||||
int32_t numOptions,
|
||||
const char** options,
|
||||
int32_t initialValue);
|
||||
|
||||
/**
|
||||
* Creates a boolean value on a simulated device.
|
||||
*
|
||||
* 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 readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated value handle
|
||||
*/
|
||||
inline HAL_SimValueHandle HAL_CreateSimValueBoolean(HAL_SimDeviceHandle device,
|
||||
const char* name,
|
||||
HAL_Bool readonly,
|
||||
HAL_Bool initialValue) {
|
||||
struct HAL_Value v = HAL_MakeBoolean(initialValue);
|
||||
return HAL_CreateSimValue(device, name, readonly, &v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a simulated value.
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value value (output parameter)
|
||||
*/
|
||||
void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C++" {
|
||||
inline HAL_Value HAL_GetSimValue(HAL_SimValueHandle handle) {
|
||||
HAL_Value v;
|
||||
HAL_GetSimValue(handle, &v);
|
||||
return v;
|
||||
}
|
||||
} // extern "C++"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets a simulated value (double).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @return The current value
|
||||
*/
|
||||
inline double HAL_GetSimValueDouble(HAL_SimValueHandle handle) {
|
||||
struct HAL_Value v;
|
||||
HAL_GetSimValue(handle, &v);
|
||||
return v.type == HAL_DOUBLE ? v.data.v_double : 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a simulated value (enum).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @return The current value
|
||||
*/
|
||||
inline int32_t HAL_GetSimValueEnum(HAL_SimValueHandle handle) {
|
||||
struct HAL_Value v;
|
||||
HAL_GetSimValue(handle, &v);
|
||||
return v.type == HAL_ENUM ? v.data.v_enum : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a simulated value (boolean).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @return The current value
|
||||
*/
|
||||
inline HAL_Bool HAL_GetSimValueBoolean(HAL_SimValueHandle handle) {
|
||||
struct HAL_Value v;
|
||||
HAL_GetSimValue(handle, &v);
|
||||
return v.type == HAL_BOOLEAN ? v.data.v_boolean : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a simulated value.
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value the value to set
|
||||
*/
|
||||
void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C++" {
|
||||
inline void HAL_SetSimValue(HAL_SimValueHandle handle, const HAL_Value& value) {
|
||||
HAL_SetSimValue(handle, &value);
|
||||
}
|
||||
} // extern "C++"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets a simulated value (double).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value the value to set
|
||||
*/
|
||||
inline void HAL_SetSimValueDouble(HAL_SimValueHandle handle, double value) {
|
||||
struct HAL_Value v = HAL_MakeDouble(value);
|
||||
HAL_SetSimValue(handle, &v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a simulated value (enum).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value the value to set
|
||||
*/
|
||||
inline void HAL_SetSimValueEnum(HAL_SimValueHandle handle, int32_t value) {
|
||||
struct HAL_Value v = HAL_MakeEnum(value);
|
||||
HAL_SetSimValue(handle, &v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a simulated value (boolean).
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
* @param value the value to set
|
||||
*/
|
||||
inline void HAL_SetSimValueBoolean(HAL_SimValueHandle handle, HAL_Bool value) {
|
||||
struct HAL_Value v = HAL_MakeBoolean(value);
|
||||
HAL_SetSimValue(handle, &v);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* C++ wrapper around a HAL simulator value handle.
|
||||
*/
|
||||
class SimValue {
|
||||
public:
|
||||
/**
|
||||
* Default constructor that results in an "empty" object that is false in
|
||||
* a boolean context.
|
||||
*/
|
||||
SimValue() = default;
|
||||
|
||||
/**
|
||||
* Wraps a simulated value handle as returned by HAL_CreateSimValue().
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
*/
|
||||
/*implicit*/ SimValue(HAL_SimValueHandle val) // NOLINT(runtime/explicit)
|
||||
: m_handle(val) {}
|
||||
|
||||
/**
|
||||
* Determine if handle is empty. Should be used to optimize out code paths
|
||||
* that are taken/not taken in simulation.
|
||||
*
|
||||
* @return False if handle is empty, true if handle is valid.
|
||||
*/
|
||||
explicit operator bool() const { return m_handle != HAL_kInvalidHandle; }
|
||||
|
||||
/**
|
||||
* Get the internal device handle.
|
||||
*
|
||||
* @return internal handle
|
||||
*/
|
||||
operator HAL_SimValueHandle() const { return m_handle; }
|
||||
|
||||
/**
|
||||
* Gets the simulated value.
|
||||
*
|
||||
* @return The current value
|
||||
*/
|
||||
HAL_Value GetValue() const { return HAL_GetSimValue(m_handle); }
|
||||
|
||||
/**
|
||||
* Sets the simulated value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
void SetValue(const HAL_Value& value) { HAL_SetSimValue(m_handle, value); }
|
||||
|
||||
protected:
|
||||
HAL_SimValueHandle m_handle = HAL_kInvalidHandle;
|
||||
};
|
||||
|
||||
/**
|
||||
* C++ wrapper around a HAL simulator double value handle.
|
||||
*/
|
||||
class SimDouble : public SimValue {
|
||||
public:
|
||||
/**
|
||||
* Default constructor that results in an "empty" object that is false in
|
||||
* a boolean context.
|
||||
*/
|
||||
SimDouble() = default;
|
||||
|
||||
/**
|
||||
* Wraps a simulated value handle as returned by HAL_CreateSimValueDouble().
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
*/
|
||||
/*implicit*/ SimDouble(HAL_SimValueHandle val) // NOLINT(runtime/explicit)
|
||||
: SimValue(val) {}
|
||||
|
||||
/**
|
||||
* Gets the simulated value.
|
||||
*
|
||||
* @return The current value
|
||||
*/
|
||||
double Get() const { return HAL_GetSimValueDouble(m_handle); }
|
||||
|
||||
/**
|
||||
* Sets the simulated value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
void Set(double value) { HAL_SetSimValueDouble(m_handle, value); }
|
||||
};
|
||||
|
||||
/**
|
||||
* C++ wrapper around a HAL simulator enum value handle.
|
||||
*/
|
||||
class SimEnum : public SimValue {
|
||||
public:
|
||||
/**
|
||||
* Default constructor that results in an "empty" object that is false in
|
||||
* a boolean context.
|
||||
*/
|
||||
SimEnum() = default;
|
||||
|
||||
/**
|
||||
* Wraps a simulated value handle as returned by HAL_CreateSimValueEnum().
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
*/
|
||||
/*implicit*/ SimEnum(HAL_SimValueHandle val) // NOLINT(runtime/explicit)
|
||||
: SimValue(val) {}
|
||||
|
||||
/**
|
||||
* Gets the simulated value.
|
||||
*
|
||||
* @return The current value
|
||||
*/
|
||||
int32_t Get() const { return HAL_GetSimValueEnum(m_handle); }
|
||||
|
||||
/**
|
||||
* Sets the simulated value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
void Set(int32_t value) { HAL_SetSimValueEnum(m_handle, value); }
|
||||
};
|
||||
|
||||
/**
|
||||
* C++ wrapper around a HAL simulator boolean value handle.
|
||||
*/
|
||||
class SimBoolean : public SimValue {
|
||||
public:
|
||||
/**
|
||||
* Default constructor that results in an "empty" object that is false in
|
||||
* a boolean context.
|
||||
*/
|
||||
SimBoolean() = default;
|
||||
|
||||
/**
|
||||
* Wraps a simulated value handle as returned by HAL_CreateSimValueBoolean().
|
||||
*
|
||||
* @param handle simulated value handle
|
||||
*/
|
||||
/*implicit*/ SimBoolean(HAL_SimValueHandle val) // NOLINT(runtime/explicit)
|
||||
: SimValue(val) {}
|
||||
|
||||
/**
|
||||
* Gets the simulated value.
|
||||
*
|
||||
* @return The current value
|
||||
*/
|
||||
bool Get() const { return HAL_GetSimValueBoolean(m_handle); }
|
||||
|
||||
/**
|
||||
* Sets the simulated value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
void Set(bool value) { HAL_SetSimValueBoolean(m_handle, value); }
|
||||
};
|
||||
|
||||
/**
|
||||
* A move-only C++ wrapper around a HAL simulator device handle.
|
||||
*/
|
||||
class SimDevice {
|
||||
public:
|
||||
/**
|
||||
* Default constructor that results in an "empty" object that is false in
|
||||
* a boolean context.
|
||||
*/
|
||||
SimDevice() = default;
|
||||
|
||||
/**
|
||||
* Creates a simulated device.
|
||||
*
|
||||
* The device name must be unique. Returns null if the device name
|
||||
* already exists. If multiple instances of the same device are desired,
|
||||
* recommend appending the instance/unique identifer in brackets to the base
|
||||
* name, e.g. "device[1]".
|
||||
*
|
||||
* If not in simulation, results in an "empty" object that evaluates to false
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name device name
|
||||
*/
|
||||
explicit SimDevice(const char* name) : m_handle(HAL_CreateSimDevice(name)) {}
|
||||
|
||||
/**
|
||||
* Creates a simulated device.
|
||||
*
|
||||
* The device name must be unique. Returns null if the device name
|
||||
* already exists. This is a convenience method that appends index in
|
||||
* brackets to the device name, e.g. passing index=1 results in "device[1]"
|
||||
* for the device name.
|
||||
*
|
||||
* If not in simulation, results in an "empty" object that evaluates to false
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name device name
|
||||
* @param index device index number to append to name
|
||||
*/
|
||||
SimDevice(const char* name, int index);
|
||||
|
||||
/**
|
||||
* Creates a simulated device.
|
||||
*
|
||||
* The device name must be unique. Returns null if the device name
|
||||
* already exists. This is a convenience method that appends index and
|
||||
* channel in brackets to the device name, e.g. passing index=1 and channel=2
|
||||
* results in "device[1,2]" for the device name.
|
||||
*
|
||||
* If not in simulation, results in an "empty" object that evaluates to false
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name device name
|
||||
* @param index device index number to append to name
|
||||
* @param channel device channel number to append to name
|
||||
*/
|
||||
SimDevice(const char* name, int index, int channel);
|
||||
|
||||
/**
|
||||
* Wraps a simulated device handle as returned by HAL_CreateSimDevice().
|
||||
*
|
||||
* @param handle simulated device handle
|
||||
*/
|
||||
/*implicit*/ SimDevice(HAL_SimDeviceHandle val) // NOLINT(runtime/explicit)
|
||||
: m_handle(val) {}
|
||||
|
||||
~SimDevice() {
|
||||
if (m_handle != HAL_kInvalidHandle) HAL_FreeSimDevice(m_handle);
|
||||
}
|
||||
|
||||
SimDevice(const SimDevice&) = delete;
|
||||
SimDevice& operator=(const SimDevice&) = delete;
|
||||
|
||||
SimDevice(SimDevice&& rhs) : m_handle(rhs.m_handle) {
|
||||
rhs.m_handle = HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
SimDevice& operator=(SimDevice&& rhs) {
|
||||
m_handle = rhs.m_handle;
|
||||
rhs.m_handle = HAL_kInvalidHandle;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if handle is empty. Should be used to optimize out code paths
|
||||
* that are taken/not taken in simulation.
|
||||
*
|
||||
* @return False if handle is empty, true if handle is valid.
|
||||
*/
|
||||
explicit operator bool() const { return m_handle != HAL_kInvalidHandle; }
|
||||
|
||||
/**
|
||||
* Get the internal device handle.
|
||||
*
|
||||
* @return internal handle
|
||||
*/
|
||||
operator HAL_SimDeviceHandle() const { return m_handle; }
|
||||
|
||||
/**
|
||||
* Creates a value on the simulated device.
|
||||
*
|
||||
* If not in simulation, results in an "empty" object that evaluates to false
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @param initialValue initial value
|
||||
* @return simulated value object
|
||||
*/
|
||||
SimValue CreateValue(const char* name, bool readonly,
|
||||
const HAL_Value& initialValue) {
|
||||
return HAL_CreateSimValue(m_handle, name, readonly, &initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double value on the simulated device.
|
||||
*
|
||||
* If not in simulation, results in an "empty" object that evaluates to false
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enumerated value on the simulated device.
|
||||
*
|
||||
* 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 readonly if the value should not be written from simulation side
|
||||
* @param options array of option descriptions
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated enum value object
|
||||
*/
|
||||
SimEnum CreateEnum(const char* name, bool readonly,
|
||||
std::initializer_list<const char*> options,
|
||||
int32_t initialValue) {
|
||||
return HAL_CreateSimValueEnum(m_handle, name, readonly, options.size(),
|
||||
const_cast<const char**>(options.begin()),
|
||||
initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enumerated value on the simulated device.
|
||||
*
|
||||
* 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 readonly if the value should not be written from simulation side
|
||||
* @param options array of option descriptions
|
||||
* @param initialValue initial value (selection)
|
||||
* @return simulated enum value object
|
||||
*/
|
||||
SimEnum CreateEnum(const char* name, bool readonly,
|
||||
wpi::ArrayRef<const char*> options, int32_t initialValue) {
|
||||
return HAL_CreateSimValueEnum(m_handle, name, readonly, options.size(),
|
||||
const_cast<const char**>(options.data()),
|
||||
initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a boolean value on the simulated device.
|
||||
*
|
||||
* If not in simulation, results in an "empty" object that evaluates to false
|
||||
* in a boolean context.
|
||||
*
|
||||
* @param name value name
|
||||
* @param readonly if the value should not be written from simulation side
|
||||
* @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);
|
||||
}
|
||||
|
||||
protected:
|
||||
HAL_SimDeviceHandle m_handle = HAL_kInvalidHandle;
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
#endif // __cplusplus
|
||||
@@ -14,9 +14,9 @@ enum HAL_Type {
|
||||
HAL_UNASSIGNED = 0,
|
||||
HAL_BOOLEAN = 0x01,
|
||||
HAL_DOUBLE = 0x02,
|
||||
HAL_ENUM = 0x16,
|
||||
HAL_INT = 0x32,
|
||||
HAL_LONG = 0x64,
|
||||
HAL_ENUM = 0x04,
|
||||
HAL_INT = 0x08,
|
||||
HAL_LONG = 0x10,
|
||||
};
|
||||
|
||||
/** HAL Entry Value. Note this is a typed union. */
|
||||
|
||||
73
hal/src/main/native/include/mockdata/SimDeviceData.h
Normal file
73
hal/src/main/native/include/mockdata/SimDeviceData.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/Types.h"
|
||||
#include "hal/Value.h"
|
||||
|
||||
typedef void (*HALSIM_SimDeviceCallback)(const char* name, void* param,
|
||||
HAL_SimDeviceHandle handle);
|
||||
|
||||
typedef void (*HALSIM_SimValueCallback)(const char* name, void* param,
|
||||
HAL_SimValueHandle handle,
|
||||
HAL_Bool readonly,
|
||||
const struct HAL_Value* value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int32_t HALSIM_RegisterSimDeviceCreatedCallback(
|
||||
const char* prefix, void* param, HALSIM_SimDeviceCallback callback,
|
||||
HAL_Bool initialNotify);
|
||||
|
||||
void HALSIM_CancelSimDeviceCreatedCallback(int32_t uid);
|
||||
|
||||
int32_t HALSIM_RegisterSimDeviceFreedCallback(
|
||||
const char* prefix, void* param, HALSIM_SimDeviceCallback callback);
|
||||
|
||||
void HALSIM_CancelSimDeviceFreedCallback(int32_t uid);
|
||||
|
||||
HAL_SimDeviceHandle HALSIM_GetSimDeviceHandle(const char* name);
|
||||
|
||||
const char* HALSIM_GetSimDeviceName(HAL_SimDeviceHandle handle);
|
||||
|
||||
HAL_SimDeviceHandle HALSIM_GetSimValueDeviceHandle(HAL_SimValueHandle handle);
|
||||
|
||||
void HALSIM_EnumerateSimDevices(const char* prefix, void* param,
|
||||
HALSIM_SimDeviceCallback callback);
|
||||
|
||||
int32_t HALSIM_RegisterSimValueCreatedCallback(HAL_SimDeviceHandle device,
|
||||
void* param,
|
||||
HALSIM_SimValueCallback callback,
|
||||
HAL_Bool initialNotify);
|
||||
|
||||
void HALSIM_CancelSimValueCreatedCallback(int32_t uid);
|
||||
|
||||
int32_t HALSIM_RegisterSimValueChangedCallback(HAL_SimValueHandle handle,
|
||||
void* param,
|
||||
HALSIM_SimValueCallback callback,
|
||||
HAL_Bool initialNotify);
|
||||
|
||||
void HALSIM_CancelSimValueChangedCallback(int32_t uid);
|
||||
|
||||
HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device,
|
||||
const char* name);
|
||||
|
||||
void HALSIM_EnumerateSimValues(HAL_SimDeviceHandle device, void* param,
|
||||
HALSIM_SimValueCallback callback);
|
||||
|
||||
const char** HALSIM_GetSimValueEnumOptions(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions);
|
||||
|
||||
void HALSIM_ResetSimDeviceData(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -41,6 +41,7 @@ void InitializeHAL() {
|
||||
InitializePWMData();
|
||||
InitializeRelayData();
|
||||
InitializeRoboRioData();
|
||||
InitializeSimDeviceData();
|
||||
InitializeSPIAccelerometerData();
|
||||
InitializeSPIData();
|
||||
InitializeAccelerometer();
|
||||
@@ -69,6 +70,7 @@ void InitializeHAL() {
|
||||
InitializePWM();
|
||||
InitializeRelay();
|
||||
InitializeSerialPort();
|
||||
InitializeSimDevice();
|
||||
InitializeSolenoid();
|
||||
InitializeSPI();
|
||||
InitializeThreads();
|
||||
|
||||
@@ -35,6 +35,7 @@ extern void InitializePDPData();
|
||||
extern void InitializePWMData();
|
||||
extern void InitializeRelayData();
|
||||
extern void InitializeRoboRioData();
|
||||
extern void InitializeSimDeviceData();
|
||||
extern void InitializeSPIAccelerometerData();
|
||||
extern void InitializeSPIData();
|
||||
extern void InitializeAccelerometer();
|
||||
@@ -64,6 +65,7 @@ extern void InitializePower();
|
||||
extern void InitializePWM();
|
||||
extern void InitializeRelay();
|
||||
extern void InitializeSerialPort();
|
||||
extern void InitializeSimDevice();
|
||||
extern void InitializeSolenoid();
|
||||
extern void InitializeSPI();
|
||||
extern void InitializeThreads();
|
||||
|
||||
75
hal/src/main/native/sim/SimDevice.cpp
Normal file
75
hal/src/main/native/sim/SimDevice.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "hal/SimDevice.h"
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
#include "HALInitializer.h"
|
||||
#include "mockdata/SimDeviceDataInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace hal {
|
||||
namespace init {
|
||||
void InitializeSimDevice() {}
|
||||
} // namespace init
|
||||
} // namespace hal
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_SimDeviceHandle HAL_CreateSimDevice(const char* name) {
|
||||
hal::init::CheckInit();
|
||||
return SimSimDeviceData->CreateDevice(name);
|
||||
}
|
||||
|
||||
void HAL_FreeSimDevice(HAL_SimDeviceHandle handle) {
|
||||
SimSimDeviceData->FreeDevice(handle);
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
const struct HAL_Value* initialValue) {
|
||||
return SimSimDeviceData->CreateValue(device, name, readonly, 0, nullptr,
|
||||
*initialValue);
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
|
||||
const char* name, HAL_Bool readonly,
|
||||
int32_t numOptions,
|
||||
const char** options,
|
||||
int32_t initialValue) {
|
||||
return SimSimDeviceData->CreateValue(device, name, readonly, numOptions,
|
||||
options, HAL_MakeEnum(initialValue));
|
||||
}
|
||||
|
||||
void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) {
|
||||
*value = SimSimDeviceData->GetValue(handle);
|
||||
}
|
||||
|
||||
void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value) {
|
||||
SimSimDeviceData->SetValue(handle, *value);
|
||||
}
|
||||
|
||||
hal::SimDevice::SimDevice(const char* name, int index) {
|
||||
wpi::SmallString<128> fullname;
|
||||
wpi::raw_svector_ostream os(fullname);
|
||||
os << name << '[' << index << ']';
|
||||
|
||||
m_handle = HAL_CreateSimDevice(fullname.c_str());
|
||||
}
|
||||
|
||||
hal::SimDevice::SimDevice(const char* name, int index, int channel) {
|
||||
wpi::SmallString<128> fullname;
|
||||
wpi::raw_svector_ostream os(fullname);
|
||||
os << name << '[' << index << ',' << channel << ']';
|
||||
|
||||
m_handle = HAL_CreateSimDevice(fullname.c_str());
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
573
hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp
Normal file
573
hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp
Normal file
@@ -0,0 +1,573 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "SimDeviceDataJNI.h"
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/UidVector.h>
|
||||
#include <wpi/jni_util.h>
|
||||
|
||||
#include "SimulatorJNI.h"
|
||||
#include "edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI.h"
|
||||
#include "mockdata/SimDeviceData.h"
|
||||
|
||||
using namespace wpi::java;
|
||||
|
||||
static JClass simDeviceInfoCls;
|
||||
static JClass simValueInfoCls;
|
||||
static JClass simDeviceCallbackCls;
|
||||
static JClass simValueCallbackCls;
|
||||
static jmethodID simDeviceCallbackCallback;
|
||||
static jmethodID simValueCallbackCallback;
|
||||
|
||||
namespace {
|
||||
|
||||
struct DeviceInfo {
|
||||
DeviceInfo(const char* name_, HAL_SimDeviceHandle handle_)
|
||||
: name{name_}, handle{handle_} {}
|
||||
std::string name;
|
||||
HAL_SimValueHandle handle;
|
||||
|
||||
jobject MakeJava(JNIEnv* env) const;
|
||||
void CallJava(JNIEnv* env, jobject callobj) const;
|
||||
};
|
||||
|
||||
struct ValueInfo {
|
||||
ValueInfo(const char* name_, HAL_SimValueHandle handle_, bool readonly_,
|
||||
const HAL_Value& value_)
|
||||
: name{name_}, handle{handle_}, readonly{readonly_}, value{value_} {}
|
||||
std::string name;
|
||||
HAL_SimValueHandle handle;
|
||||
bool readonly;
|
||||
HAL_Value value;
|
||||
|
||||
jobject MakeJava(JNIEnv* env) const;
|
||||
void CallJava(JNIEnv* env, jobject callobj) const;
|
||||
|
||||
private:
|
||||
std::pair<jlong, jdouble> ToValue12() const;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
jobject DeviceInfo::MakeJava(JNIEnv* env) const {
|
||||
static jmethodID func =
|
||||
env->GetMethodID(simDeviceInfoCls, "<init>", "(Ljava/lang/String;I)V");
|
||||
return env->NewObject(simDeviceInfoCls, func, MakeJString(env, name),
|
||||
(jint)handle);
|
||||
}
|
||||
|
||||
void DeviceInfo::CallJava(JNIEnv* env, jobject callobj) const {
|
||||
env->CallVoidMethod(callobj, simDeviceCallbackCallback,
|
||||
MakeJString(env, name), (jint)handle);
|
||||
}
|
||||
|
||||
std::pair<jlong, jdouble> ValueInfo::ToValue12() const {
|
||||
jlong value1 = 0;
|
||||
jdouble value2 = 0.0;
|
||||
switch (value.type) {
|
||||
case HAL_BOOLEAN:
|
||||
value1 = value.data.v_boolean;
|
||||
break;
|
||||
case HAL_DOUBLE:
|
||||
value2 = value.data.v_double;
|
||||
break;
|
||||
case HAL_ENUM:
|
||||
value1 = value.data.v_enum;
|
||||
break;
|
||||
case HAL_INT:
|
||||
value1 = value.data.v_int;
|
||||
break;
|
||||
case HAL_LONG:
|
||||
value1 = value.data.v_long;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return std::pair(value1, value2);
|
||||
}
|
||||
|
||||
jobject ValueInfo::MakeJava(JNIEnv* env) const {
|
||||
static jmethodID func =
|
||||
env->GetMethodID(simValueInfoCls, "<init>", "(Ljava/lang/String;IZIJD)V");
|
||||
auto [value1, value2] = ToValue12();
|
||||
return env->NewObject(simValueInfoCls, func, MakeJString(env, name),
|
||||
(jint)handle, (jboolean)readonly, (jint)value.type,
|
||||
value1, value2);
|
||||
}
|
||||
|
||||
void ValueInfo::CallJava(JNIEnv* env, jobject callobj) const {
|
||||
auto [value1, value2] = ToValue12();
|
||||
env->CallVoidMethod(callobj, simValueCallbackCallback, MakeJString(env, name),
|
||||
(jint)handle, (jboolean)readonly, (jint)value.type,
|
||||
value1, value2);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class CallbackStore {
|
||||
public:
|
||||
explicit CallbackStore(JNIEnv* env, jobject obj) : m_call{env, obj} {}
|
||||
~CallbackStore() {
|
||||
if (m_cancelCallback) m_cancelCallback();
|
||||
}
|
||||
|
||||
void SetCancel(std::function<void()> cancelCallback) {
|
||||
m_cancelCallback = std::move(cancelCallback);
|
||||
}
|
||||
void Free(JNIEnv* env) { m_call.free(env); }
|
||||
jobject Get() const { return m_call; }
|
||||
|
||||
private:
|
||||
wpi::java::JGlobal<jobject> m_call;
|
||||
std::function<void()> m_cancelCallback;
|
||||
};
|
||||
|
||||
class CallbackThreadJNI : public wpi::SafeThread {
|
||||
public:
|
||||
void Main();
|
||||
|
||||
using DeviceCalls =
|
||||
std::vector<std::pair<std::weak_ptr<CallbackStore>, DeviceInfo>>;
|
||||
DeviceCalls m_deviceCalls;
|
||||
using ValueCalls =
|
||||
std::vector<std::pair<std::weak_ptr<CallbackStore>, ValueInfo>>;
|
||||
ValueCalls m_valueCalls;
|
||||
|
||||
wpi::UidVector<std::shared_ptr<CallbackStore>, 4> m_callbacks;
|
||||
};
|
||||
|
||||
class CallbackJNI {
|
||||
public:
|
||||
static CallbackJNI& GetInstance() {
|
||||
static CallbackJNI inst;
|
||||
return inst;
|
||||
}
|
||||
void SendDevice(int32_t callback, DeviceInfo info);
|
||||
void SendValue(int32_t callback, ValueInfo info);
|
||||
|
||||
std::pair<int32_t, std::shared_ptr<CallbackStore>> AllocateCallback(
|
||||
JNIEnv* env, jobject obj);
|
||||
|
||||
void FreeCallback(JNIEnv* env, int32_t uid);
|
||||
|
||||
private:
|
||||
CallbackJNI() { m_owner.Start(); }
|
||||
|
||||
wpi::SafeThreadOwner<CallbackThreadJNI> m_owner;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void CallbackThreadJNI::Main() {
|
||||
JNIEnv* env;
|
||||
JavaVMAttachArgs args;
|
||||
args.version = JNI_VERSION_1_2;
|
||||
args.name = const_cast<char*>("SimDeviceCallback");
|
||||
args.group = nullptr;
|
||||
jint rs = sim::GetJVM()->AttachCurrentThreadAsDaemon(
|
||||
reinterpret_cast<void**>(&env), &args);
|
||||
if (rs != JNI_OK) return;
|
||||
|
||||
DeviceCalls deviceCalls;
|
||||
ValueCalls valueCalls;
|
||||
|
||||
std::unique_lock lock(m_mutex);
|
||||
while (m_active) {
|
||||
m_cond.wait(lock, [&] { return !m_active; });
|
||||
if (!m_active) break;
|
||||
|
||||
deviceCalls.swap(m_deviceCalls);
|
||||
valueCalls.swap(m_valueCalls);
|
||||
|
||||
lock.unlock(); // don't hold mutex during callback execution
|
||||
|
||||
for (auto&& call : deviceCalls) {
|
||||
if (auto store = call.first.lock()) {
|
||||
if (jobject callobj = store->Get()) {
|
||||
call.second.CallJava(env, callobj);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto&& call : valueCalls) {
|
||||
if (auto store = call.first.lock()) {
|
||||
if (jobject callobj = store->Get()) {
|
||||
call.second.CallJava(env, callobj);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deviceCalls.clear();
|
||||
valueCalls.clear();
|
||||
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
// free global references
|
||||
for (auto&& callback : m_callbacks) callback->Free(env);
|
||||
|
||||
sim::GetJVM()->DetachCurrentThread();
|
||||
}
|
||||
|
||||
void CallbackJNI::SendDevice(int32_t callback, DeviceInfo info) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
thr->m_deviceCalls.emplace_back(thr->m_callbacks[callback], std::move(info));
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
|
||||
void CallbackJNI::SendValue(int32_t callback, ValueInfo info) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
thr->m_valueCalls.emplace_back(thr->m_callbacks[callback], std::move(info));
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
|
||||
std::pair<int32_t, std::shared_ptr<CallbackStore>>
|
||||
CallbackJNI::AllocateCallback(JNIEnv* env, jobject obj) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return std::pair(0, nullptr);
|
||||
auto store = std::make_shared<CallbackStore>(env, obj);
|
||||
return std::pair(thr->m_callbacks.emplace_back(store) + 1, store);
|
||||
}
|
||||
|
||||
void CallbackJNI::FreeCallback(JNIEnv* env, int32_t uid) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (uid <= 0 || static_cast<uint32_t>(uid) >= thr->m_callbacks.size()) return;
|
||||
--uid;
|
||||
auto store = std::move(thr->m_callbacks[uid]);
|
||||
thr->m_callbacks.erase(uid);
|
||||
store->Free(env);
|
||||
}
|
||||
|
||||
namespace sim {
|
||||
|
||||
bool InitializeSimDeviceDataJNI(JNIEnv* env) {
|
||||
simDeviceInfoCls = JClass(
|
||||
env, "edu/wpi/first/hal/sim/mockdata/SimDeviceDataJNI$SimDeviceInfo");
|
||||
if (!simDeviceInfoCls) return false;
|
||||
|
||||
simValueInfoCls = JClass(
|
||||
env, "edu/wpi/first/hal/sim/mockdata/SimDeviceDataJNI$SimValueInfo");
|
||||
if (!simValueInfoCls) return false;
|
||||
|
||||
simDeviceCallbackCls = JClass(env, "edu/wpi/first/hal/sim/SimDeviceCallback");
|
||||
if (!simDeviceCallbackCls) return false;
|
||||
|
||||
simDeviceCallbackCallback = env->GetMethodID(simDeviceCallbackCls, "callback",
|
||||
"(Ljava/lang/String;I)V");
|
||||
if (!simDeviceCallbackCallback) return false;
|
||||
|
||||
simValueCallbackCls = JClass(env, "edu/wpi/first/hal/sim/SimValueCallback");
|
||||
if (!simValueCallbackCls) return false;
|
||||
|
||||
simValueCallbackCallback = env->GetMethodID(
|
||||
simValueCallbackCls, "callbackNative", "(Ljava/lang/String;IZIJD)V");
|
||||
if (!simValueCallbackCallback) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FreeSimDeviceDataJNI(JNIEnv* env) {
|
||||
simDeviceInfoCls.free(env);
|
||||
simValueInfoCls.free(env);
|
||||
simDeviceCallbackCls.free(env);
|
||||
simValueCallbackCls.free(env);
|
||||
}
|
||||
|
||||
} // namespace sim
|
||||
|
||||
extern "C" {
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: registerSimDeviceCreatedCallback
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/Object;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_registerSimDeviceCreatedCallback
|
||||
(JNIEnv* env, jclass, jstring prefix, jobject callback,
|
||||
jboolean initialNotify)
|
||||
{
|
||||
auto [uid, store] =
|
||||
CallbackJNI::GetInstance().AllocateCallback(env, callback);
|
||||
int32_t cuid = HALSIM_RegisterSimDeviceCreatedCallback(
|
||||
JStringRef{env, prefix}.c_str(),
|
||||
reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
|
||||
[](const char* name, void* param, HAL_SimDeviceHandle handle) {
|
||||
int32_t uid = reinterpret_cast<intptr_t>(param);
|
||||
CallbackJNI::GetInstance().SendDevice(uid, DeviceInfo{name, handle});
|
||||
},
|
||||
initialNotify);
|
||||
store->SetCancel([cuid] { HALSIM_CancelSimDeviceCreatedCallback(cuid); });
|
||||
return uid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: cancelSimDeviceCreatedCallback
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_cancelSimDeviceCreatedCallback
|
||||
(JNIEnv* env, jclass, jint uid)
|
||||
{
|
||||
CallbackJNI::GetInstance().FreeCallback(env, uid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: registerSimDeviceFreedCallback
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/Object;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_registerSimDeviceFreedCallback
|
||||
(JNIEnv* env, jclass, jstring prefix, jobject callback)
|
||||
{
|
||||
auto [uid, store] =
|
||||
CallbackJNI::GetInstance().AllocateCallback(env, callback);
|
||||
int32_t cuid = HALSIM_RegisterSimDeviceFreedCallback(
|
||||
JStringRef{env, prefix}.c_str(),
|
||||
reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
|
||||
[](const char* name, void* param, HAL_SimDeviceHandle handle) {
|
||||
int32_t uid = reinterpret_cast<intptr_t>(param);
|
||||
CallbackJNI::GetInstance().SendDevice(uid, DeviceInfo{name, handle});
|
||||
});
|
||||
store->SetCancel([cuid] { HALSIM_CancelSimDeviceFreedCallback(cuid); });
|
||||
return uid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: cancelSimDeviceFreedCallback
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_cancelSimDeviceFreedCallback
|
||||
(JNIEnv* env, jclass, jint uid)
|
||||
{
|
||||
CallbackJNI::GetInstance().FreeCallback(env, uid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: getSimDeviceHandle
|
||||
* Signature: (Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_getSimDeviceHandle
|
||||
(JNIEnv* env, jclass, jstring name)
|
||||
{
|
||||
return HALSIM_GetSimDeviceHandle(JStringRef{env, name}.c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: getSimValueDeviceHandle
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_getSimValueDeviceHandle
|
||||
(JNIEnv*, jclass, jint handle)
|
||||
{
|
||||
return HALSIM_GetSimValueDeviceHandle(handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: enumerateSimDevices
|
||||
* Signature: (Ljava/lang/String;)[Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_enumerateSimDevices
|
||||
(JNIEnv* env, jclass, jstring prefix)
|
||||
{
|
||||
// get values
|
||||
std::vector<DeviceInfo> arr;
|
||||
HALSIM_EnumerateSimDevices(
|
||||
JStringRef{env, prefix}.c_str(), &arr,
|
||||
[](const char* name, void* param, HAL_SimDeviceHandle handle) {
|
||||
auto arr = static_cast<std::vector<DeviceInfo>*>(param);
|
||||
arr->emplace_back(name, handle);
|
||||
});
|
||||
|
||||
// convert to java
|
||||
size_t numElems = arr.size();
|
||||
jobjectArray jarr =
|
||||
env->NewObjectArray(arr.size(), simDeviceInfoCls, nullptr);
|
||||
if (!jarr) return nullptr;
|
||||
for (size_t i = 0; i < numElems; ++i) {
|
||||
JLocal<jobject> elem{env, arr[i].MakeJava(env)};
|
||||
env->SetObjectArrayElement(jarr, i, elem.obj());
|
||||
}
|
||||
return jarr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: registerSimValueCreatedCallback
|
||||
* Signature: (ILjava/lang/Object;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_registerSimValueCreatedCallback
|
||||
(JNIEnv* env, jclass, jint device, jobject callback, jboolean initialNotify)
|
||||
{
|
||||
auto [uid, store] =
|
||||
CallbackJNI::GetInstance().AllocateCallback(env, callback);
|
||||
int32_t cuid = HALSIM_RegisterSimValueCreatedCallback(
|
||||
device, reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
|
||||
[](const char* name, void* param, HAL_SimValueHandle handle,
|
||||
HAL_Bool readonly, const HAL_Value* value) {
|
||||
int32_t uid = reinterpret_cast<intptr_t>(param);
|
||||
CallbackJNI::GetInstance().SendValue(
|
||||
uid, ValueInfo{name, handle, static_cast<bool>(readonly), *value});
|
||||
},
|
||||
initialNotify);
|
||||
store->SetCancel([cuid] { HALSIM_CancelSimValueCreatedCallback(cuid); });
|
||||
return uid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: cancelSimValueCreatedCallback
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_cancelSimValueCreatedCallback
|
||||
(JNIEnv* env, jclass, jint uid)
|
||||
{
|
||||
CallbackJNI::GetInstance().FreeCallback(env, uid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: registerSimValueChangedCallback
|
||||
* Signature: (ILjava/lang/Object;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_registerSimValueChangedCallback
|
||||
(JNIEnv* env, jclass, jint handle, jobject callback, jboolean initialNotify)
|
||||
{
|
||||
auto [uid, store] =
|
||||
CallbackJNI::GetInstance().AllocateCallback(env, callback);
|
||||
int32_t cuid = HALSIM_RegisterSimValueChangedCallback(
|
||||
handle, reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
|
||||
[](const char* name, void* param, HAL_SimValueHandle handle,
|
||||
HAL_Bool readonly, const HAL_Value* value) {
|
||||
int32_t uid = reinterpret_cast<intptr_t>(param);
|
||||
CallbackJNI::GetInstance().SendValue(
|
||||
uid, ValueInfo{name, handle, static_cast<bool>(readonly), *value});
|
||||
},
|
||||
initialNotify);
|
||||
store->SetCancel([cuid] { HALSIM_CancelSimValueChangedCallback(cuid); });
|
||||
return uid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: cancelSimValueChangedCallback
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_cancelSimValueChangedCallback
|
||||
(JNIEnv* env, jclass, jint uid)
|
||||
{
|
||||
CallbackJNI::GetInstance().FreeCallback(env, uid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: getSimValueHandle
|
||||
* Signature: (ILjava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_getSimValueHandle
|
||||
(JNIEnv* env, jclass, jint device, jstring name)
|
||||
{
|
||||
return HALSIM_GetSimValueHandle(device, JStringRef{env, name}.c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: enumerateSimValues
|
||||
* Signature: (I)[Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_enumerateSimValues
|
||||
(JNIEnv* env, jclass, jint device)
|
||||
{
|
||||
// get values
|
||||
std::vector<ValueInfo> arr;
|
||||
HALSIM_EnumerateSimValues(
|
||||
device, &arr,
|
||||
[](const char* name, void* param, HAL_SimValueHandle handle,
|
||||
HAL_Bool readonly, const HAL_Value* value) {
|
||||
auto arr = static_cast<std::vector<ValueInfo>*>(param);
|
||||
arr->emplace_back(name, handle, readonly, *value);
|
||||
});
|
||||
|
||||
// convert to java
|
||||
size_t numElems = arr.size();
|
||||
jobjectArray jarr = env->NewObjectArray(arr.size(), simValueInfoCls, nullptr);
|
||||
if (!jarr) return nullptr;
|
||||
for (size_t i = 0; i < numElems; ++i) {
|
||||
JLocal<jobject> elem{env, arr[i].MakeJava(env)};
|
||||
env->SetObjectArrayElement(jarr, i, elem.obj());
|
||||
}
|
||||
return jarr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: getSimValueEnumOptions
|
||||
* Signature: (I)[Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_getSimValueEnumOptions
|
||||
(JNIEnv* env, jclass, jint handle)
|
||||
{
|
||||
static JClass stringCls{env, "java/lang/String"};
|
||||
if (!stringCls) return nullptr;
|
||||
int32_t numElems = 0;
|
||||
const char** elems = HALSIM_GetSimValueEnumOptions(handle, &numElems);
|
||||
jobjectArray jarr = env->NewObjectArray(numElems, stringCls, nullptr);
|
||||
if (!jarr) return nullptr;
|
||||
for (int32_t i = 0; i < numElems; ++i) {
|
||||
JLocal<jstring> elem{env, MakeJString(env, elems[i])};
|
||||
env->SetObjectArrayElement(jarr, i, elem.obj());
|
||||
}
|
||||
return jarr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
|
||||
* Method: resetSimDeviceData
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_resetSimDeviceData
|
||||
(JNIEnv*, jclass)
|
||||
{
|
||||
HALSIM_ResetSimDeviceData();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
15
hal/src/main/native/sim/jni/SimDeviceDataJNI.h
Normal file
15
hal/src/main/native/sim/jni/SimDeviceDataJNI.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
namespace sim {
|
||||
bool InitializeSimDeviceDataJNI(JNIEnv* env);
|
||||
void FreeSimDeviceDataJNI(JNIEnv* env);
|
||||
} // namespace sim
|
||||
@@ -7,9 +7,12 @@
|
||||
|
||||
#include "SimulatorJNI.h"
|
||||
|
||||
#include <wpi/jni_util.h>
|
||||
|
||||
#include "BufferCallbackStore.h"
|
||||
#include "CallbackStore.h"
|
||||
#include "ConstBufferCallbackStore.h"
|
||||
#include "SimDeviceDataJNI.h"
|
||||
#include "SpiReadAutoReceiveBufferCallbackStore.h"
|
||||
#include "edu_wpi_first_hal_sim_mockdata_SimulatorJNI.h"
|
||||
#include "hal/HAL.h"
|
||||
@@ -19,7 +22,6 @@
|
||||
using namespace wpi::java;
|
||||
|
||||
static JavaVM* jvm = nullptr;
|
||||
static JClass simValueCls;
|
||||
static JClass notifyCallbackCls;
|
||||
static JClass bufferCallbackCls;
|
||||
static JClass constBufferCallbackCls;
|
||||
@@ -37,9 +39,6 @@ jint SimOnLoad(JavaVM* vm, void* reserved) {
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||
return JNI_ERR;
|
||||
|
||||
simValueCls = JClass(env, "edu/wpi/first/hal/sim/SimValue");
|
||||
if (!simValueCls) return JNI_ERR;
|
||||
|
||||
notifyCallbackCls = JClass(env, "edu/wpi/first/hal/sim/NotifyCallback");
|
||||
if (!notifyCallbackCls) return JNI_ERR;
|
||||
|
||||
@@ -75,6 +74,7 @@ jint SimOnLoad(JavaVM* vm, void* reserved) {
|
||||
InitializeBufferStore();
|
||||
InitializeConstBufferStore();
|
||||
InitializeSpiBufferStore();
|
||||
if (!InitializeSimDeviceDataJNI(env)) return JNI_ERR;
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
@@ -84,11 +84,11 @@ void SimOnUnload(JavaVM* vm, void* reserved) {
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||
return;
|
||||
|
||||
simValueCls.free(env);
|
||||
notifyCallbackCls.free(env);
|
||||
bufferCallbackCls.free(env);
|
||||
constBufferCallbackCls.free(env);
|
||||
spiReadAutoReceiveBufferCallbackCls.free(env);
|
||||
FreeSimDeviceDataJNI(env);
|
||||
jvm = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wpi/jni_util.h>
|
||||
|
||||
#include "hal/Types.h"
|
||||
#include "hal/Value.h"
|
||||
#include "jni.h"
|
||||
|
||||
typedef HAL_Handle SIM_JniHandle;
|
||||
|
||||
413
hal/src/main/native/sim/mockdata/SimDeviceData.cpp
Normal file
413
hal/src/main/native/sim/mockdata/SimDeviceData.cpp
Normal file
@@ -0,0 +1,413 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "mockdata/SimDeviceData.h" // NOLINT(build/include_order)
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "SimDeviceDataInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace hal {
|
||||
namespace init {
|
||||
void InitializeSimDeviceData() {
|
||||
static SimDeviceData sdd;
|
||||
::hal::SimSimDeviceData = &sdd;
|
||||
}
|
||||
} // namespace init
|
||||
} // namespace hal
|
||||
|
||||
SimDeviceData* hal::SimSimDeviceData;
|
||||
|
||||
SimDeviceData::Device* SimDeviceData::LookupDevice(HAL_SimDeviceHandle handle) {
|
||||
if (handle <= 0) return nullptr;
|
||||
--handle;
|
||||
if (static_cast<uint32_t>(handle) >= m_devices.size() || !m_devices[handle])
|
||||
return nullptr;
|
||||
return m_devices[handle].get();
|
||||
}
|
||||
|
||||
SimDeviceData::Value* SimDeviceData::LookupValue(HAL_SimValueHandle handle) {
|
||||
if (handle <= 0) return nullptr;
|
||||
|
||||
// look up device
|
||||
Device* deviceImpl = LookupDevice(handle >> 16);
|
||||
|
||||
// look up value
|
||||
handle &= 0xffff;
|
||||
--handle;
|
||||
if (static_cast<uint32_t>(handle) >= deviceImpl->values.size() ||
|
||||
!deviceImpl->values[handle])
|
||||
return nullptr;
|
||||
|
||||
return deviceImpl->values[handle].get();
|
||||
}
|
||||
|
||||
HAL_SimDeviceHandle SimDeviceData::CreateDevice(const char* name) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// check for duplicates and don't overwrite them
|
||||
auto it = m_deviceMap.find(name);
|
||||
if (it != m_deviceMap.end()) return 0;
|
||||
|
||||
// don't allow more than 4096 devices (limit driven by 12-bit allocation in
|
||||
// value changed callback uid)
|
||||
if (m_devices.size() >= 4095) return 0;
|
||||
|
||||
// create and save
|
||||
auto deviceImpl = std::make_shared<Device>(name);
|
||||
HAL_SimDeviceHandle deviceHandle = m_devices.emplace_back(deviceImpl) + 1;
|
||||
deviceImpl->handle = deviceHandle;
|
||||
m_deviceMap[name] = deviceImpl;
|
||||
|
||||
// notify callbacks
|
||||
m_deviceCreated(name, deviceHandle);
|
||||
|
||||
return deviceHandle;
|
||||
}
|
||||
|
||||
void SimDeviceData::FreeDevice(HAL_SimDeviceHandle handle) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
--handle;
|
||||
|
||||
// see if it exists
|
||||
if (handle < 0 || static_cast<uint32_t>(handle) >= m_devices.size()) return;
|
||||
auto deviceImpl = std::move(m_devices[handle]);
|
||||
if (!deviceImpl) return;
|
||||
|
||||
// remove from map
|
||||
m_deviceMap.erase(deviceImpl->name);
|
||||
|
||||
// remove from vector
|
||||
m_devices.erase(handle);
|
||||
|
||||
// notify callbacks
|
||||
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) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// look up device
|
||||
Device* deviceImpl = LookupDevice(device);
|
||||
if (!deviceImpl) return 0;
|
||||
|
||||
// check for duplicates and don't overwrite them
|
||||
auto it = deviceImpl->valueMap.find(name);
|
||||
if (it != deviceImpl->valueMap.end()) return 0;
|
||||
|
||||
// don't allow more than 4096 values per device (limit driven by 12-bit
|
||||
// allocation in value changed callback uid)
|
||||
if (deviceImpl->values.size() >= 4095) return 0;
|
||||
|
||||
// create and save; encode device into handle
|
||||
auto valueImplPtr = std::make_unique<Value>(name, readonly, initialValue);
|
||||
Value* valueImpl = valueImplPtr.get();
|
||||
HAL_SimValueHandle valueHandle =
|
||||
(device << 16) |
|
||||
(deviceImpl->values.emplace_back(std::move(valueImplPtr)) + 1);
|
||||
valueImpl->handle = valueHandle;
|
||||
// copy options (if any provided)
|
||||
if (numOptions > 0 && options) {
|
||||
valueImpl->enumOptions.reserve(numOptions);
|
||||
valueImpl->cstrEnumOptions.reserve(numOptions);
|
||||
for (int32_t i = 0; i < numOptions; ++i) {
|
||||
valueImpl->enumOptions.emplace_back(options[i]);
|
||||
// point to our copy of the string, not the passed-in one
|
||||
valueImpl->cstrEnumOptions.emplace_back(
|
||||
valueImpl->enumOptions.back().c_str());
|
||||
}
|
||||
}
|
||||
deviceImpl->valueMap[name] = valueImpl;
|
||||
|
||||
// notify callbacks
|
||||
deviceImpl->valueCreated(name, valueHandle, readonly, &initialValue);
|
||||
|
||||
return valueHandle;
|
||||
}
|
||||
|
||||
HAL_Value SimDeviceData::GetValue(HAL_SimValueHandle handle) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Value* valueImpl = LookupValue(handle);
|
||||
|
||||
if (!valueImpl) {
|
||||
HAL_Value value;
|
||||
value.data.v_int = 0;
|
||||
value.type = HAL_UNASSIGNED;
|
||||
return value;
|
||||
}
|
||||
|
||||
return valueImpl->value;
|
||||
}
|
||||
|
||||
void SimDeviceData::SetValue(HAL_SimValueHandle handle,
|
||||
const HAL_Value& value) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Value* valueImpl = LookupValue(handle);
|
||||
if (!valueImpl) return;
|
||||
|
||||
valueImpl->value = value;
|
||||
|
||||
// notify callbacks
|
||||
valueImpl->changed(valueImpl->name.c_str(), valueImpl->handle,
|
||||
valueImpl->readonly, &value);
|
||||
}
|
||||
|
||||
int32_t SimDeviceData::RegisterDeviceCreatedCallback(
|
||||
const char* prefix, void* param, HALSIM_SimDeviceCallback callback,
|
||||
bool initialNotify) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// register callback
|
||||
int32_t index = m_deviceCreated.Register(prefix, param, callback);
|
||||
|
||||
// initial notifications
|
||||
if (initialNotify) {
|
||||
for (auto&& device : m_devices)
|
||||
callback(device->name.c_str(), param, device->handle);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void SimDeviceData::CancelDeviceCreatedCallback(int32_t uid) {
|
||||
if (uid <= 0) return;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_deviceCreated.Cancel(uid);
|
||||
}
|
||||
|
||||
int32_t SimDeviceData::RegisterDeviceFreedCallback(
|
||||
const char* prefix, void* param, HALSIM_SimDeviceCallback callback) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
return m_deviceFreed.Register(prefix, param, callback);
|
||||
}
|
||||
|
||||
void SimDeviceData::CancelDeviceFreedCallback(int32_t uid) {
|
||||
if (uid <= 0) return;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_deviceFreed.Cancel(uid);
|
||||
}
|
||||
|
||||
HAL_SimDeviceHandle SimDeviceData::GetDeviceHandle(const char* name) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto it = m_deviceMap.find(name);
|
||||
if (it == m_deviceMap.end()) return 0;
|
||||
if (auto deviceImpl = it->getValue().lock())
|
||||
return deviceImpl->handle;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* SimDeviceData::GetDeviceName(HAL_SimDeviceHandle handle) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// look up device
|
||||
Device* deviceImpl = LookupDevice(handle);
|
||||
if (!deviceImpl) return nullptr;
|
||||
|
||||
return deviceImpl->name.c_str();
|
||||
}
|
||||
|
||||
void SimDeviceData::EnumerateDevices(const char* prefix, void* param,
|
||||
HALSIM_SimDeviceCallback callback) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
for (auto&& device : m_devices) {
|
||||
if (wpi::StringRef{device->name}.startswith(prefix))
|
||||
callback(device->name.c_str(), param, device->handle);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t SimDeviceData::RegisterValueCreatedCallback(
|
||||
HAL_SimDeviceHandle device, void* param, HALSIM_SimValueCallback callback,
|
||||
bool initialNotify) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Device* deviceImpl = LookupDevice(device);
|
||||
if (!deviceImpl) return -1;
|
||||
|
||||
// register callback
|
||||
int32_t index = deviceImpl->valueCreated.Register(callback, param);
|
||||
|
||||
// initial notifications
|
||||
if (initialNotify) {
|
||||
for (auto&& value : deviceImpl->values)
|
||||
callback(value->name.c_str(), param, value->handle, value->readonly,
|
||||
&value->value);
|
||||
}
|
||||
|
||||
// encode device into uid
|
||||
return (device << 16) | (index & 0xffff);
|
||||
}
|
||||
|
||||
void SimDeviceData::CancelValueCreatedCallback(int32_t uid) {
|
||||
if (uid <= 0) return;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Device* deviceImpl = LookupDevice(uid >> 16);
|
||||
if (!deviceImpl) return;
|
||||
deviceImpl->valueCreated.Cancel(uid & 0xffff);
|
||||
}
|
||||
|
||||
int32_t SimDeviceData::RegisterValueChangedCallback(
|
||||
HAL_SimValueHandle handle, void* param, HALSIM_SimValueCallback callback,
|
||||
bool initialNotify) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Value* valueImpl = LookupValue(handle);
|
||||
if (!valueImpl) return -1;
|
||||
|
||||
// register callback
|
||||
int32_t index = valueImpl->changed.Register(callback, param);
|
||||
|
||||
// initial notification
|
||||
if (initialNotify)
|
||||
callback(valueImpl->name.c_str(), param, valueImpl->handle,
|
||||
valueImpl->readonly, &valueImpl->value);
|
||||
|
||||
// encode device and value into uid
|
||||
return (((handle >> 16) & 0xfff) << 19) | ((handle & 0xfff) << 7) |
|
||||
(index & 0x7f);
|
||||
}
|
||||
|
||||
void SimDeviceData::CancelValueChangedCallback(int32_t uid) {
|
||||
if (uid <= 0) return;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Value* valueImpl = LookupValue(((uid >> 19) << 16) | ((uid >> 7) & 0xfff));
|
||||
if (!valueImpl) return;
|
||||
valueImpl->changed.Cancel(uid & 0x7f);
|
||||
}
|
||||
|
||||
HAL_SimValueHandle SimDeviceData::GetValueHandle(HAL_SimDeviceHandle device,
|
||||
const char* name) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Device* deviceImpl = LookupDevice(device);
|
||||
if (!deviceImpl) return 0;
|
||||
|
||||
// lookup value
|
||||
auto it = deviceImpl->valueMap.find(name);
|
||||
if (it == deviceImpl->valueMap.end()) return 0;
|
||||
if (!it->getValue()) return 0;
|
||||
return it->getValue()->handle;
|
||||
}
|
||||
|
||||
void SimDeviceData::EnumerateValues(HAL_SimDeviceHandle device, void* param,
|
||||
HALSIM_SimValueCallback callback) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
Device* deviceImpl = LookupDevice(device);
|
||||
if (!deviceImpl) return;
|
||||
|
||||
for (auto&& value : deviceImpl->values)
|
||||
callback(value->name.c_str(), param, value->handle, value->readonly,
|
||||
&value->value);
|
||||
}
|
||||
|
||||
const char** SimDeviceData::GetValueEnumOptions(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 options (safe to return as they never change)
|
||||
auto& options = valueImpl->cstrEnumOptions;
|
||||
*numOptions = options.size();
|
||||
return options.data();
|
||||
}
|
||||
|
||||
void SimDeviceData::ResetData() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_devices.clear();
|
||||
m_deviceMap.clear();
|
||||
m_deviceCreated.Reset();
|
||||
m_deviceFreed.Reset();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int32_t HALSIM_RegisterSimDeviceCreatedCallback(
|
||||
const char* prefix, void* param, HALSIM_SimDeviceCallback callback,
|
||||
HAL_Bool initialNotify) {
|
||||
return SimSimDeviceData->RegisterDeviceCreatedCallback(
|
||||
prefix, param, callback, initialNotify);
|
||||
}
|
||||
|
||||
void HALSIM_CancelSimDeviceCreatedCallback(int32_t uid) {
|
||||
SimSimDeviceData->CancelDeviceCreatedCallback(uid);
|
||||
}
|
||||
|
||||
int32_t HALSIM_RegisterSimDeviceFreedCallback(
|
||||
const char* prefix, void* param, HALSIM_SimDeviceCallback callback) {
|
||||
return SimSimDeviceData->RegisterDeviceFreedCallback(prefix, param, callback);
|
||||
}
|
||||
|
||||
void HALSIM_CancelSimDeviceFreedCallback(int32_t uid) {
|
||||
SimSimDeviceData->CancelDeviceFreedCallback(uid);
|
||||
}
|
||||
|
||||
HAL_SimDeviceHandle HALSIM_GetSimDeviceHandle(const char* name) {
|
||||
return SimSimDeviceData->GetDeviceHandle(name);
|
||||
}
|
||||
|
||||
const char* HALSIM_GetSimDeviceName(HAL_SimDeviceHandle handle) {
|
||||
return SimSimDeviceData->GetDeviceName(handle);
|
||||
}
|
||||
|
||||
HAL_SimDeviceHandle HALSIM_GetSimValueDeviceHandle(HAL_SimValueHandle handle) {
|
||||
if (handle <= 0) return 0;
|
||||
return handle >> 16;
|
||||
}
|
||||
|
||||
void HALSIM_EnumerateSimDevices(const char* prefix, void* param,
|
||||
HALSIM_SimDeviceCallback callback) {
|
||||
SimSimDeviceData->EnumerateDevices(prefix, param, callback);
|
||||
}
|
||||
|
||||
int32_t HALSIM_RegisterSimValueCreatedCallback(HAL_SimDeviceHandle device,
|
||||
void* param,
|
||||
HALSIM_SimValueCallback callback,
|
||||
HAL_Bool initialNotify) {
|
||||
return SimSimDeviceData->RegisterValueCreatedCallback(device, param, callback,
|
||||
initialNotify);
|
||||
}
|
||||
|
||||
void HALSIM_CancelSimValueCreatedCallback(int32_t uid) {
|
||||
SimSimDeviceData->CancelValueCreatedCallback(uid);
|
||||
}
|
||||
|
||||
int32_t HALSIM_RegisterSimValueChangedCallback(HAL_SimValueHandle handle,
|
||||
void* param,
|
||||
HALSIM_SimValueCallback callback,
|
||||
HAL_Bool initialNotify) {
|
||||
return SimSimDeviceData->RegisterValueChangedCallback(handle, param, callback,
|
||||
initialNotify);
|
||||
}
|
||||
|
||||
void HALSIM_CancelSimValueChangedCallback(int32_t uid) {
|
||||
SimSimDeviceData->CancelValueChangedCallback(uid);
|
||||
}
|
||||
|
||||
HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device,
|
||||
const char* name) {
|
||||
return SimSimDeviceData->GetValueHandle(device, name);
|
||||
}
|
||||
|
||||
void HALSIM_EnumerateSimValues(HAL_SimDeviceHandle device, void* param,
|
||||
HALSIM_SimValueCallback callback) {
|
||||
SimSimDeviceData->EnumerateValues(device, param, callback);
|
||||
}
|
||||
|
||||
const char** HALSIM_GetSimValueEnumOptions(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions) {
|
||||
return SimSimDeviceData->GetValueEnumOptions(handle, numOptions);
|
||||
}
|
||||
|
||||
void HALSIM_ResetSimDeviceData(void) { SimSimDeviceData->ResetData(); }
|
||||
|
||||
} // extern "C"
|
||||
214
hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h
Normal file
214
hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h
Normal file
@@ -0,0 +1,214 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/StringMap.h>
|
||||
#include <wpi/UidVector.h>
|
||||
#include <wpi/spinlock.h>
|
||||
|
||||
#include "hal/Value.h"
|
||||
#include "mockdata/SimCallbackRegistry.h"
|
||||
#include "mockdata/SimDeviceData.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
namespace impl {
|
||||
|
||||
template <typename CallbackFunction>
|
||||
class SimUnnamedCallbackRegistry {
|
||||
public:
|
||||
using RawFunctor = void (*)();
|
||||
|
||||
protected:
|
||||
using CallbackVector = wpi::UidVector<HalCallbackListener<RawFunctor>, 4>;
|
||||
|
||||
public:
|
||||
void Cancel(int32_t uid) {
|
||||
if (m_callbacks) m_callbacks->erase(uid - 1);
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
if (m_callbacks) m_callbacks->clear();
|
||||
}
|
||||
|
||||
int32_t Register(CallbackFunction callback, void* param) {
|
||||
// Must return -1 on a null callback for error handling
|
||||
if (callback == nullptr) return -1;
|
||||
if (!m_callbacks) m_callbacks = std::make_unique<CallbackVector>();
|
||||
return m_callbacks->emplace_back(param,
|
||||
reinterpret_cast<RawFunctor>(callback)) +
|
||||
1;
|
||||
}
|
||||
|
||||
template <typename... U>
|
||||
void Invoke(const char* name, U&&... u) const {
|
||||
if (m_callbacks) {
|
||||
for (auto&& cb : *m_callbacks) {
|
||||
reinterpret_cast<CallbackFunction>(cb.callback)(name, cb.param,
|
||||
std::forward<U>(u)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... U>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE void operator()(U&&... u) const {
|
||||
return Invoke(std::forward<U>(u)...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<CallbackVector> m_callbacks;
|
||||
};
|
||||
|
||||
template <typename CallbackFunction>
|
||||
class SimPrefixCallbackRegistry {
|
||||
struct CallbackData {
|
||||
CallbackData() = default;
|
||||
CallbackData(const char* prefix_, void* param_, CallbackFunction callback_)
|
||||
: prefix{prefix_}, callback{callback_}, param{param_} {}
|
||||
std::string prefix;
|
||||
CallbackFunction callback;
|
||||
void* param;
|
||||
|
||||
explicit operator bool() const { return callback != nullptr; }
|
||||
};
|
||||
using CallbackVector = wpi::UidVector<CallbackData, 4>;
|
||||
|
||||
public:
|
||||
void Cancel(int32_t uid) {
|
||||
if (m_callbacks) m_callbacks->erase(uid - 1);
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
if (m_callbacks) m_callbacks->clear();
|
||||
}
|
||||
|
||||
int32_t Register(const char* prefix, void* param, CallbackFunction callback) {
|
||||
// Must return -1 on a null callback for error handling
|
||||
if (callback == nullptr) return -1;
|
||||
if (!m_callbacks) m_callbacks = std::make_unique<CallbackVector>();
|
||||
return m_callbacks->emplace_back(prefix, param, callback) + 1;
|
||||
}
|
||||
|
||||
template <typename... U>
|
||||
void Invoke(const char* name, U&&... u) const {
|
||||
if (m_callbacks) {
|
||||
for (auto&& cb : *m_callbacks) {
|
||||
if (wpi::StringRef{name}.startswith(cb.prefix)) {
|
||||
cb.callback(name, cb.param, std::forward<U>(u)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... U>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE void operator()(U&&... u) const {
|
||||
return Invoke(std::forward<U>(u)...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<CallbackVector> m_callbacks;
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
class SimDeviceData {
|
||||
private:
|
||||
struct Value {
|
||||
Value(const char* name_, bool readonly_, const HAL_Value& value_)
|
||||
: name{name_}, readonly{readonly_}, value{value_} {}
|
||||
|
||||
HAL_SimValueHandle handle{0};
|
||||
std::string name;
|
||||
bool readonly;
|
||||
HAL_Value value;
|
||||
std::vector<std::string> enumOptions;
|
||||
std::vector<const char*> cstrEnumOptions;
|
||||
impl::SimUnnamedCallbackRegistry<HALSIM_SimValueCallback> changed;
|
||||
};
|
||||
|
||||
struct Device {
|
||||
explicit Device(const char* name_) : name{name_} {}
|
||||
|
||||
HAL_SimDeviceHandle handle{0};
|
||||
std::string name;
|
||||
wpi::UidVector<std::unique_ptr<Value>, 16> values;
|
||||
wpi::StringMap<Value*> valueMap;
|
||||
impl::SimUnnamedCallbackRegistry<HALSIM_SimValueCallback> valueCreated;
|
||||
};
|
||||
|
||||
wpi::UidVector<std::shared_ptr<Device>, 4> m_devices;
|
||||
wpi::StringMap<std::weak_ptr<Device>> m_deviceMap;
|
||||
|
||||
wpi::recursive_spinlock m_mutex;
|
||||
|
||||
impl::SimPrefixCallbackRegistry<HALSIM_SimDeviceCallback> m_deviceCreated;
|
||||
impl::SimPrefixCallbackRegistry<HALSIM_SimDeviceCallback> m_deviceFreed;
|
||||
|
||||
// call with lock held, returns null if does not exist
|
||||
Device* LookupDevice(HAL_SimDeviceHandle handle);
|
||||
Value* LookupValue(HAL_SimValueHandle handle);
|
||||
|
||||
public:
|
||||
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,
|
||||
const char** options,
|
||||
const HAL_Value& initialValue);
|
||||
HAL_Value GetValue(HAL_SimValueHandle handle);
|
||||
void SetValue(HAL_SimValueHandle handle, const HAL_Value& value);
|
||||
|
||||
int32_t RegisterDeviceCreatedCallback(const char* prefix, void* param,
|
||||
HALSIM_SimDeviceCallback callback,
|
||||
bool initialNotify);
|
||||
|
||||
void CancelDeviceCreatedCallback(int32_t uid);
|
||||
|
||||
int32_t RegisterDeviceFreedCallback(const char* prefix, void* param,
|
||||
HALSIM_SimDeviceCallback callback);
|
||||
|
||||
void CancelDeviceFreedCallback(int32_t uid);
|
||||
|
||||
HAL_SimDeviceHandle GetDeviceHandle(const char* name);
|
||||
const char* GetDeviceName(HAL_SimDeviceHandle handle);
|
||||
|
||||
void EnumerateDevices(const char* prefix, void* param,
|
||||
HALSIM_SimDeviceCallback callback);
|
||||
|
||||
int32_t RegisterValueCreatedCallback(HAL_SimDeviceHandle device, void* param,
|
||||
HALSIM_SimValueCallback callback,
|
||||
bool initialNotify);
|
||||
|
||||
void CancelValueCreatedCallback(int32_t uid);
|
||||
|
||||
int32_t RegisterValueChangedCallback(HAL_SimValueHandle handle, void* param,
|
||||
HALSIM_SimValueCallback callback,
|
||||
bool initialNotify);
|
||||
|
||||
void CancelValueChangedCallback(int32_t uid);
|
||||
|
||||
HAL_SimValueHandle GetValueHandle(HAL_SimDeviceHandle device,
|
||||
const char* name);
|
||||
|
||||
void EnumerateValues(HAL_SimDeviceHandle device, void* param,
|
||||
HALSIM_SimValueCallback callback);
|
||||
|
||||
const char** GetValueEnumOptions(HAL_SimValueHandle handle,
|
||||
int32_t* numOptions);
|
||||
|
||||
void ResetData();
|
||||
};
|
||||
extern SimDeviceData* SimSimDeviceData;
|
||||
} // namespace hal
|
||||
Reference in New Issue
Block a user