mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-23 01:21:42 +00:00
Merge "Adds interrupts to Java"
This commit is contained in:
@@ -6,6 +6,9 @@
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include "errno.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
typedef void (*InterruptHandlerFunction)(uint32_t interruptAssertedMask, void *param);
|
||||
|
||||
@@ -52,8 +52,10 @@ void enableInterrupts(void* interrupt_pointer, int32_t *status)
|
||||
*/
|
||||
void disableInterrupts(void* interrupt_pointer, int32_t *status)
|
||||
{
|
||||
|
||||
Interrupt* anInterrupt = (Interrupt*)interrupt_pointer;
|
||||
anInterrupt->manager->disable(status);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Binary file not shown.
@@ -92,6 +92,7 @@ public class AnalogTriggerOutput extends DigitalSource {
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,8 +114,8 @@ public class AnalogTriggerOutput extends DigitalSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getModuleForRouting() {
|
||||
return m_trigger.m_index >> 2;
|
||||
public byte getModuleForRouting() {
|
||||
return (byte) (m_trigger.m_index >> 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,27 +123,6 @@ public class AnalogTriggerOutput extends DigitalSource {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request interrupts asynchronously on this digital input.
|
||||
*
|
||||
* @param handler
|
||||
* the interrupt service routine
|
||||
* @param param
|
||||
* a parameter for the ISR
|
||||
*/
|
||||
// public void requestInterrupts(/*tInterruptHandler*/Object handler, Object
|
||||
// param) {
|
||||
// TODO: add interrupt support
|
||||
// TODO: throw exception
|
||||
// }
|
||||
|
||||
/**
|
||||
* Request interrupts synchronously on this digital input.
|
||||
*/
|
||||
// public void requestInterrupts() {
|
||||
// TODO: throw exception
|
||||
// }
|
||||
|
||||
/**
|
||||
* Defines the state in which the AnalogTrigger triggers
|
||||
* @author jonathanleitschuh
|
||||
|
||||
@@ -12,14 +12,10 @@ import java.nio.ByteOrder;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.hal.InterruptJNI;
|
||||
import edu.wpi.first.wpilibj.hal.DIOJNI;
|
||||
import edu.wpi.first.wpilibj.hal.InterruptJNI.InterruptHandlerFunction;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* Class to read a digital input. This class will read digital inputs and return
|
||||
@@ -67,97 +63,15 @@ public class DigitalInput extends DigitalSource implements LiveWindowSendable {
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAnalogTriggerForRouting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request interrupts asynchronously on this digital input.
|
||||
*
|
||||
* @param handler
|
||||
* The address of the interrupt handler function of type
|
||||
* tInterruptHandler that will be called whenever there is an
|
||||
* interrupt on the digitial input port. Request interrupts in
|
||||
* synchronus mode where the user program interrupt handler will
|
||||
* be called when an interrupt occurs. The default is interrupt
|
||||
* on rising edges only.
|
||||
*/
|
||||
public void requestInterrupts(InterruptHandlerFunction handler) {
|
||||
// TODO: add interrupt support
|
||||
|
||||
try {
|
||||
m_interruptIndex = interrupts.allocate();
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"No interrupts are left to be allocated");
|
||||
}
|
||||
|
||||
allocateInterrupts(false);
|
||||
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.requestInterrupts(m_interrupt, (byte) getModuleForRouting(),
|
||||
getChannelForRouting(),
|
||||
(byte) (getAnalogTriggerForRouting() ? 1 : 0), status.asIntBuffer());
|
||||
setUpSourceEdge(true, false);
|
||||
InterruptJNI.attachInterruptHandler(m_interrupt, handler, null, status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Request interrupts synchronously on this digital input. Request
|
||||
* interrupts in synchronus mode where the user program will have to
|
||||
* explicitly wait for the interrupt to occur. The default is interrupt on
|
||||
* rising edges only.
|
||||
*/
|
||||
public void requestInterrupts() {
|
||||
try {
|
||||
m_interruptIndex = interrupts.allocate();
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"No interrupts are left to be allocated");
|
||||
}
|
||||
|
||||
allocateInterrupts(true);
|
||||
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.requestInterrupts(m_interrupt, (byte) getModuleForRouting(),
|
||||
getChannelForRouting(),
|
||||
(byte) (getAnalogTriggerForRouting() ? 1 : 0), status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
setUpSourceEdge(true, false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set which edge to trigger interrupts on
|
||||
*
|
||||
* @param risingEdge
|
||||
* true to interrupt on rising edge
|
||||
* @param fallingEdge
|
||||
* true to interrupt on falling edge
|
||||
*/
|
||||
public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
|
||||
if (m_interrupt != null) {
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.setInterruptUpSourceEdge(m_interrupt,
|
||||
(byte) (risingEdge ? 1 : 0), (byte) (fallingEdge ? 1 : 0),
|
||||
status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"You must call RequestInterrupts before setUpSourceEdge");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
@Override
|
||||
public String getSmartDashboardType() {
|
||||
return "Digital Input";
|
||||
}
|
||||
@@ -167,6 +81,7 @@ public class DigitalInput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void initTable(ITable subtable) {
|
||||
m_table = subtable;
|
||||
updateTable();
|
||||
@@ -175,6 +90,7 @@ public class DigitalInput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void updateTable() {
|
||||
if (m_table != null) {
|
||||
m_table.putBoolean("Value", get());
|
||||
@@ -184,6 +100,7 @@ public class DigitalInput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ITable getTable() {
|
||||
return m_table;
|
||||
}
|
||||
@@ -191,12 +108,14 @@ public class DigitalInput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void startLiveWindowMode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void stopLiveWindowMode() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,24 +7,21 @@
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
//import com.sun.jna.Pointer;
|
||||
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.hal.DIOJNI;
|
||||
import edu.wpi.first.wpilibj.hal.PWMJNI;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.hal.PWMJNI;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
//import com.sun.jna.Pointer;
|
||||
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
|
||||
|
||||
/**
|
||||
* Class to write digital outputs. This class will wrtie digital outputs. Other
|
||||
* Class to write digital outputs. This class will write digital outputs. Other
|
||||
* devices that are implemented elsewhere will automatically allocate digital
|
||||
* inputs and outputs as required.
|
||||
*/
|
||||
@@ -48,6 +45,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* Free the resources associated with a digital output.
|
||||
*/
|
||||
@Override
|
||||
public void free() {
|
||||
// disable the pwm only if we have allocated it
|
||||
if (m_pwmGenerator != null) {
|
||||
@@ -104,6 +102,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
|
||||
* @param pulseLength
|
||||
* The length of the pulse.
|
||||
*/
|
||||
@Deprecated
|
||||
public void pulse(final int channel, final int pulseLength) {
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
@@ -212,6 +211,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
@Override
|
||||
public String getSmartDashboardType() {
|
||||
return "Digital Output";
|
||||
}
|
||||
@@ -222,6 +222,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void initTable(ITable subtable) {
|
||||
m_table = subtable;
|
||||
updateTable();
|
||||
@@ -230,6 +231,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ITable getTable() {
|
||||
return m_table;
|
||||
}
|
||||
@@ -237,6 +239,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void updateTable() {
|
||||
// TODO: Put current value.
|
||||
}
|
||||
@@ -244,8 +247,10 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void startLiveWindowMode() {
|
||||
m_table_listener = new ITableListener() {
|
||||
@Override
|
||||
public void valueChanged(ITable itable, String key, Object value,
|
||||
boolean bln) {
|
||||
set(((Boolean) value).booleanValue());
|
||||
@@ -257,6 +262,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void stopLiveWindowMode() {
|
||||
// TODO: Broken, should only remove the listener from "Value" only.
|
||||
m_table.removeTableListener(m_table_listener);
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.DIOJNI;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
@@ -54,6 +53,7 @@ public abstract class DigitalSource extends InterruptableSensorBase {
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
channels.free(m_channel);
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
@@ -69,6 +69,7 @@ public abstract class DigitalSource extends InterruptableSensorBase {
|
||||
*
|
||||
* @return channel routing number
|
||||
*/
|
||||
@Override
|
||||
public int getChannelForRouting() {
|
||||
return m_channel;
|
||||
}
|
||||
@@ -78,15 +79,16 @@ public abstract class DigitalSource extends InterruptableSensorBase {
|
||||
*
|
||||
* @return 0
|
||||
*/
|
||||
public int getModuleForRouting() {
|
||||
@Override
|
||||
public byte getModuleForRouting() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an analog trigger
|
||||
*
|
||||
* @return true if this is an analog trigger
|
||||
*/
|
||||
@Override
|
||||
public boolean getAnalogTriggerForRouting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2008-2014. 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.wpilibj;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.InterruptJNI.InterruptJNIHandlerFunction;
|
||||
|
||||
|
||||
/**
|
||||
* It is recommended that you use this class in conjunction with classes from
|
||||
* {@link java.util.concurrent.atomic} as these objects are all thread safe.
|
||||
*
|
||||
* @author Jonathan Leitschuh
|
||||
*
|
||||
* @param <T> The type of the parameter that should be returned to the the
|
||||
* method {@link #interruptFired(int, Object)}
|
||||
*/
|
||||
public abstract class InterruptHandlerFunction<T>{
|
||||
/**
|
||||
* The entry point for the interrupt. When the interrupt fires the
|
||||
* {@link #apply(int, Object)} method is called.
|
||||
* The outer class is provided as an interface to allow the implementer to
|
||||
* pass a generic object to the interrupt fired method.
|
||||
* @author Jonathan Leitschuh
|
||||
*/
|
||||
private class Function implements InterruptJNIHandlerFunction{
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void apply(int interruptAssertedMask, Object param) {
|
||||
interruptFired(interruptAssertedMask, (T)param);
|
||||
}
|
||||
}
|
||||
final Function function = new Function();
|
||||
|
||||
/**
|
||||
* This method is run every time an interrupt is fired.
|
||||
* @param interruptAssertedMask
|
||||
* @param param The parameter provided by overriding the {@link #overridableParamater()}
|
||||
* method.
|
||||
*/
|
||||
abstract void interruptFired(int interruptAssertedMask, T param);
|
||||
|
||||
|
||||
/**
|
||||
* Override this method if you would like to pass a specific
|
||||
* parameter to the {@link #interruptFired(int, Object)} when it is fired by the interrupt.
|
||||
* This method is called once when {@link InterruptableSensorBase#requestInterrupts(InterruptHandlerFunction)}
|
||||
* is run.
|
||||
* @return The object that should be passed to the interrupt when it runs
|
||||
*/
|
||||
public T overridableParamater(){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -7,26 +7,40 @@
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.InterruptJNI;
|
||||
import edu.wpi.first.wpilibj.hal.InterruptJNI.InterruptHandlerFunction;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.hal.InterruptJNI;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* Base for sensors to be used with interrupts
|
||||
*/
|
||||
public abstract class InterruptableSensorBase extends SensorBase {
|
||||
/**
|
||||
* This is done to store the JVM variable in the InterruptJNI
|
||||
* This is done because the HAL must have access to the JVM variable
|
||||
* in order to attach the newly spawned thread when an interrupt is fired.
|
||||
*/
|
||||
static{
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.initializeInterruptJVM(status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* The interrupt resource
|
||||
*/
|
||||
protected ByteBuffer m_interrupt;
|
||||
protected ByteBuffer m_interrupt = null;
|
||||
|
||||
/**
|
||||
* The interrupt manager resource
|
||||
* Flags if the interrupt being allocated is synchronous
|
||||
*/
|
||||
protected InterruptHandlerFunction m_manager;
|
||||
protected boolean m_isSynchronousInterrupt = false;
|
||||
|
||||
/**
|
||||
* The index of the interrupt
|
||||
*/
|
||||
@@ -40,25 +54,102 @@ public abstract class InterruptableSensorBase extends SensorBase {
|
||||
* Create a new InterrupatableSensorBase
|
||||
*/
|
||||
public InterruptableSensorBase() {
|
||||
m_manager = null;
|
||||
m_interrupt = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
abstract boolean getAnalogTriggerForRouting();
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
abstract int getChannelForRouting();
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
abstract byte getModuleForRouting();
|
||||
|
||||
/**
|
||||
* Request interrupts asynchronously on this digital input.
|
||||
*
|
||||
* @param handler
|
||||
* The {@link #InterruptHandlerFunction} that contains the method
|
||||
* {@link InterruptHandlerFunction#interruptFired(int, Object)} that
|
||||
* will be called whenever there is an interrupt on this device.
|
||||
* Request interrupts in synchronus mode where the user program
|
||||
* interrupt handler will be called when an interrupt occurs. The
|
||||
* default is interrupt on rising edges only.
|
||||
*/
|
||||
public void requestInterrupts(InterruptHandlerFunction<?> handler) {
|
||||
if(m_interrupt != null){
|
||||
throw new AllocationException("The interrupt has already been allocated");
|
||||
}
|
||||
|
||||
allocateInterrupts(false);
|
||||
|
||||
assert (m_interrupt != null);
|
||||
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.requestInterrupts(m_interrupt, getModuleForRouting(),
|
||||
getChannelForRouting(),
|
||||
(byte) (getAnalogTriggerForRouting() ? 1 : 0), status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
setUpSourceEdge(true, false);
|
||||
InterruptJNI.attachInterruptHandler(m_interrupt, handler.function, handler.overridableParamater(), status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Request interrupts synchronously on this digital input. Request
|
||||
* interrupts in synchronous mode where the user program will have to
|
||||
* explicitly wait for the interrupt to occur. The default is interrupt on
|
||||
* rising edges only.
|
||||
*/
|
||||
public void requestInterrupts() {
|
||||
if(m_interrupt != null){
|
||||
throw new AllocationException("The interrupt has already been allocated");
|
||||
}
|
||||
|
||||
allocateInterrupts(true);
|
||||
|
||||
assert (m_interrupt != null);
|
||||
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.requestInterrupts(m_interrupt, getModuleForRouting(),
|
||||
getChannelForRouting(),
|
||||
(byte) (getAnalogTriggerForRouting() ? 1 : 0), status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
setUpSourceEdge(true, false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate the interrupt
|
||||
*
|
||||
* @param watcher
|
||||
* @param watcher true if the interrupt should be in synchronous mode where the user
|
||||
* program will have to explicitly wait for the interrupt to occur.
|
||||
*/
|
||||
public void allocateInterrupts(boolean watcher) {
|
||||
if (!watcher) {
|
||||
throw new IllegalArgumentException(
|
||||
"Interrupt callbacks not yet supported");
|
||||
protected void allocateInterrupts(boolean watcher) {
|
||||
try {
|
||||
m_interruptIndex = interrupts.allocate();
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"No interrupts are left to be allocated");
|
||||
}
|
||||
// Expects the calling leaf class to allocate an interrupt index.
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_isSynchronousInterrupt = watcher;
|
||||
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
m_interrupt = InterruptJNI.initializeInterrupts(m_interruptIndex,
|
||||
(byte) (watcher ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
(byte) (watcher ? 1 : 0), status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,13 +157,15 @@ public abstract class InterruptableSensorBase extends SensorBase {
|
||||
* structures and disables any interrupts.
|
||||
*/
|
||||
public void cancelInterrupts() {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
if (m_interrupt == null) {
|
||||
throw new IllegalStateException("The interrupt is not allocated.");
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
InterruptJNI.cleanInterrupts(m_interrupt, status);
|
||||
HALUtil.checkStatus(status);
|
||||
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.cleanInterrupts(m_interrupt, status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
m_interrupt = null;
|
||||
interrupts.free(m_interruptIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,12 +175,13 @@ public abstract class InterruptableSensorBase extends SensorBase {
|
||||
* Timeout in seconds
|
||||
*/
|
||||
public void waitForInterrupt(double timeout) {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
if (m_interrupt == null) {
|
||||
throw new IllegalStateException("The interrupt is not allocated.");
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
InterruptJNI.waitForInterrupt(m_interrupt, (float) timeout, status);
|
||||
HALUtil.checkStatus(status);
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.waitForInterrupt(m_interrupt, (float) timeout, status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,24 +190,32 @@ public abstract class InterruptableSensorBase extends SensorBase {
|
||||
* other options before starting to field interrupts.
|
||||
*/
|
||||
public void enableInterrupts() {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
if (m_interrupt == null) {
|
||||
throw new IllegalStateException("The interrupt is not allocated.");
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
InterruptJNI.enableInterrupts(m_interrupt, status);
|
||||
HALUtil.checkStatus(status);
|
||||
if(m_isSynchronousInterrupt){
|
||||
throw new IllegalStateException("You do not need to enable synchronous interrupts");
|
||||
}
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.enableInterrupts(m_interrupt, status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Interrupts without without deallocating structures.
|
||||
*/
|
||||
public void disableInterrupts() {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
if (m_interrupt == null) {
|
||||
throw new IllegalStateException("The interrupt is not allocated.");
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
InterruptJNI.disableInterrupts(m_interrupt, status);
|
||||
HALUtil.checkStatus(status);
|
||||
if(m_isSynchronousInterrupt){
|
||||
throw new IllegalStateException("You can not disable synchronous interrupts");
|
||||
}
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.disableInterrupts(m_interrupt, status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,12 +225,36 @@ public abstract class InterruptableSensorBase extends SensorBase {
|
||||
* @return Timestamp in seconds since boot.
|
||||
*/
|
||||
public double readInterruptTimestamp() {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
if (m_interrupt == null) {
|
||||
throw new IllegalStateException("The interrupt is not allocated.");
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
double timestamp = InterruptJNI.readInterruptTimestamp(m_interrupt, status);
|
||||
HALUtil.checkStatus(status);
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
double timestamp = InterruptJNI.readInterruptTimestamp(m_interrupt, status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set which edge to trigger interrupts on
|
||||
*
|
||||
* @param risingEdge
|
||||
* true to interrupt on rising edge
|
||||
* @param fallingEdge
|
||||
* true to interrupt on falling edge
|
||||
*/
|
||||
public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
|
||||
if (m_interrupt != null) {
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
InterruptJNI.setInterruptUpSourceEdge(m_interrupt,
|
||||
(byte) (risingEdge ? 1 : 0), (byte) (fallingEdge ? 1 : 0),
|
||||
status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"You must call RequestInterrupts before setUpSourceEdge");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package edu.wpi.first.wpilibj.hal;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
public class HALUtil extends JNIWrapper {
|
||||
public static final int NULL_PARAMETER = -5;
|
||||
@@ -28,6 +28,12 @@ public class HALUtil extends JNIWrapper {
|
||||
public static native boolean getFPGAButton(IntBuffer status);
|
||||
|
||||
public static native String getHALErrorMessage(int code);
|
||||
|
||||
public static native int getHALErrno();
|
||||
public static native String getHALstrerror(int errno);
|
||||
public static String getHALstrerror(){
|
||||
return getHALstrerror(getHALErrno());
|
||||
}
|
||||
|
||||
public static void checkStatus(IntBuffer status)
|
||||
{
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package edu.wpi.first.wpilibj.hal;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
public class InterruptJNI extends JNIWrapper {
|
||||
public interface InterruptHandlerFunction {
|
||||
void apply(int interruptAssertedMask, ByteBuffer param);
|
||||
public interface InterruptJNIHandlerFunction {
|
||||
void apply(int interruptAssertedMask, Object param);
|
||||
};
|
||||
public static native void initializeInterruptJVM(IntBuffer status);
|
||||
public static native ByteBuffer initializeInterrupts(int interruptIndex, byte watcher, IntBuffer status);
|
||||
public static native void cleanInterrupts(ByteBuffer interrupt_pointer, IntBuffer status);
|
||||
public static native void waitForInterrupt(ByteBuffer interrupt_pointer, double timeout, IntBuffer status);
|
||||
@@ -14,6 +15,6 @@ public class InterruptJNI extends JNIWrapper {
|
||||
public static native void disableInterrupts(ByteBuffer interrupt_pointer, IntBuffer status);
|
||||
public static native double readInterruptTimestamp(ByteBuffer interrupt_pointer, IntBuffer status);
|
||||
public static native void requestInterrupts(ByteBuffer interrupt_pointer, byte routing_module, int routing_pin, byte routing_analog_trigger, IntBuffer status);
|
||||
public static native void attachInterruptHandler(ByteBuffer interrupt_pointer, InterruptHandlerFunction handler, ByteBuffer param, IntBuffer status);
|
||||
public static native void attachInterruptHandler(ByteBuffer interrupt_pointer, InterruptJNIHandlerFunction handler, Object param, IntBuffer status);
|
||||
public static native void setInterruptUpSourceEdge(ByteBuffer interrupt_pointer, byte risingEdge, byte fallingEdge, IntBuffer status);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2008-2014. 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.wpilibj;
|
||||
|
||||
import static org.hamcrest.Matchers.both;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
|
||||
|
||||
/**
|
||||
* This class should not be run as a test explicitly. Instead it should be extended by tests that use the InterruptableSensorBase
|
||||
*
|
||||
* @author jonathanleitschuh
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractInterruptTest extends AbstractComsSetup {
|
||||
private InterruptableSensorBase interruptable = null;
|
||||
|
||||
private InterruptableSensorBase getInterruptable(){
|
||||
if(interruptable == null){
|
||||
interruptable = giveInterruptableSensorBase();
|
||||
}
|
||||
return interruptable;
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void interruptTeardown(){
|
||||
if(interruptable != null){
|
||||
freeInterruptableSensorBase();
|
||||
interruptable = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the interruptible sensor base that interrupts can be attached to.
|
||||
* @return
|
||||
*/
|
||||
abstract InterruptableSensorBase giveInterruptableSensorBase();
|
||||
/**
|
||||
* Cleans up the interruptible sensor base. This is only called if {@link #giveInterruptableSensorBase()} is called.
|
||||
*/
|
||||
abstract void freeInterruptableSensorBase();
|
||||
/**
|
||||
* Perform whatever action is required to set the interrupt high.
|
||||
*/
|
||||
abstract void setInterruptHigh();
|
||||
/**
|
||||
* Perform whatever action is required to set the interrupt low.
|
||||
*/
|
||||
abstract void setInterruptLow();
|
||||
|
||||
|
||||
private class InterruptCounter{
|
||||
private final AtomicInteger count = new AtomicInteger();
|
||||
void increment(){
|
||||
count.addAndGet(1);
|
||||
}
|
||||
|
||||
int getCount(){
|
||||
return count.get();
|
||||
}
|
||||
};
|
||||
|
||||
private class TestInterruptHandlerFunction extends InterruptHandlerFunction<InterruptCounter>{
|
||||
protected final AtomicBoolean exceptionThrown = new AtomicBoolean(false);
|
||||
/** Stores the time that the interrupt fires */
|
||||
final AtomicLong interruptFireTime = new AtomicLong();
|
||||
/** Stores if the interrupt has completed at least once */
|
||||
final AtomicBoolean interruptComplete = new AtomicBoolean(false);
|
||||
protected Exception ex;
|
||||
final InterruptCounter counter;
|
||||
|
||||
TestInterruptHandlerFunction(InterruptCounter counter){
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
@Override
|
||||
void interruptFired(int interruptAssertedMask, InterruptCounter param) {
|
||||
interruptFireTime.set(Utility.getFPGATime());
|
||||
counter.increment();
|
||||
try{
|
||||
//This won't cause the test to fail
|
||||
assertSame(counter, param);
|
||||
} catch (Exception ex){
|
||||
//So we must throw the exception within the test
|
||||
exceptionThrown.set(true);
|
||||
this.ex = ex;
|
||||
}
|
||||
interruptComplete.set(true);
|
||||
};
|
||||
|
||||
@Override
|
||||
public InterruptCounter overridableParamater(){
|
||||
return counter;
|
||||
}
|
||||
};
|
||||
|
||||
@Test(timeout = 1000)
|
||||
public void testSingleInterruptsTriggering() throws Exception{
|
||||
//Given
|
||||
final InterruptCounter counter = new InterruptCounter();
|
||||
TestInterruptHandlerFunction function = new TestInterruptHandlerFunction(counter);
|
||||
|
||||
//When
|
||||
getInterruptable().requestInterrupts(function);
|
||||
getInterruptable().enableInterrupts();
|
||||
|
||||
setInterruptLow();
|
||||
Timer.delay(0.01);
|
||||
//Note: Utility.getFPGATime() is used because double values can turn over after the robot has been running for a long time
|
||||
final long interruptTriggerTime = Utility.getFPGATime();
|
||||
setInterruptHigh();
|
||||
|
||||
//Delay until the interrupt is complete
|
||||
while(!function.interruptComplete.get()){
|
||||
Timer.delay(.005);
|
||||
}
|
||||
|
||||
|
||||
//Then
|
||||
assertEquals("The interrupt did not fire the expected number of times", 1, counter.getCount());
|
||||
//If the test within the interrupt failed
|
||||
if(function.exceptionThrown.get()){
|
||||
throw function.ex;
|
||||
}
|
||||
final long range = 10000; //in microseconds
|
||||
assertThat("The interrupt did not fire within the expected time period (values in milliseconds)",
|
||||
function.interruptFireTime.get(), both(greaterThan(interruptTriggerTime - range))
|
||||
.and(lessThan(interruptTriggerTime + range)));
|
||||
assertThat("The readInterruptTimestamp() did not return the correct value (values in seconds)",
|
||||
getInterruptable().readInterruptTimestamp(), both(greaterThan((interruptTriggerTime - range)/1e6))
|
||||
.and(lessThan((interruptTriggerTime + range)/1e6)));
|
||||
}
|
||||
|
||||
@Test(timeout = 1000)
|
||||
public void testMultipleInterruptsTriggering() throws Exception{
|
||||
//Given
|
||||
final InterruptCounter counter = new InterruptCounter();
|
||||
TestInterruptHandlerFunction function = new TestInterruptHandlerFunction(counter);
|
||||
|
||||
//When
|
||||
getInterruptable().requestInterrupts(function);
|
||||
getInterruptable().enableInterrupts();
|
||||
|
||||
final int fireCount = 50;
|
||||
for(int i = 0; i < fireCount; i ++){
|
||||
setInterruptLow();
|
||||
setInterruptHigh();
|
||||
//Wait for the interrupt to complete before moving on
|
||||
while(!function.interruptComplete.getAndSet(false)){
|
||||
Timer.delay(.005);
|
||||
}
|
||||
}
|
||||
//Then
|
||||
assertEquals("The interrupt did not fire the expected number of times", fireCount, counter.getCount());
|
||||
}
|
||||
|
||||
/** The timeout length for this test in seconds */
|
||||
private static final int synchronousTimeout = 5;
|
||||
@Test(timeout = (long)(synchronousTimeout*1e3))
|
||||
public void testSynchronousInterruptsTriggering(){
|
||||
//Given
|
||||
getInterruptable().requestInterrupts();
|
||||
|
||||
final double synchronousDelay = synchronousTimeout/2.;
|
||||
Runnable r = new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
Timer.delay(synchronousDelay);
|
||||
setInterruptLow();
|
||||
setInterruptHigh();
|
||||
}
|
||||
};
|
||||
|
||||
//When
|
||||
|
||||
//Note: the long time value is used because doubles can flip if the robot is left running for long enough
|
||||
final long startTimeStamp = Utility.getFPGATime();
|
||||
new Thread(r).start();
|
||||
//Delay for twice as long as the timeout so the test should fail first
|
||||
getInterruptable().waitForInterrupt(synchronousTimeout * 2);
|
||||
final long stopTimeStamp = Utility.getFPGATime();
|
||||
|
||||
//Then
|
||||
//The test will not have timed out and:
|
||||
final double interruptRunTime = (stopTimeStamp - startTimeStamp)*1e-6;
|
||||
assertEquals("The interrupt did not run for the expected amount of time (units in seconds)", synchronousDelay, interruptRunTime, .1);
|
||||
}
|
||||
|
||||
|
||||
@Test(timeout = 2000)
|
||||
public void testDisableStopsInterruptFiring(){
|
||||
final InterruptCounter counter = new InterruptCounter();
|
||||
TestInterruptHandlerFunction function = new TestInterruptHandlerFunction(counter);
|
||||
|
||||
//When
|
||||
getInterruptable().requestInterrupts(function);
|
||||
getInterruptable().enableInterrupts();
|
||||
|
||||
final int fireCount = 50;
|
||||
for(int i = 0; i < fireCount; i ++){
|
||||
setInterruptLow();
|
||||
setInterruptHigh();
|
||||
//Wait for the interrupt to complete before moving on
|
||||
while(!function.interruptComplete.getAndSet(false)){
|
||||
Timer.delay(.005);
|
||||
}
|
||||
}
|
||||
getInterruptable().disableInterrupts();
|
||||
//TestBench.out().println("Finished disabling the robot");
|
||||
|
||||
for(int i = 0; i < fireCount; i ++){
|
||||
setInterruptLow();
|
||||
setInterruptHigh();
|
||||
//Just wait because the interrupt should not fire
|
||||
Timer.delay(.005);
|
||||
}
|
||||
|
||||
//Then
|
||||
assertEquals("The interrupt did not fire the expected number of times", fireCount, counter.getCount());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,9 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -16,15 +18,15 @@ import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;
|
||||
import edu.wpi.first.wpilibj.fixtures.AnalogCrossConnectFixture;
|
||||
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
|
||||
import edu.wpi.first.wpilibj.test.TestBench;
|
||||
|
||||
/**
|
||||
* @author jonathanleitschuh
|
||||
*
|
||||
*/
|
||||
public class AnalogCrossConnectTest extends AbstractComsSetup {
|
||||
public class AnalogCrossConnectTest extends AbstractInterruptTest {
|
||||
private static final Logger logger = Logger.getLogger(AnalogCrossConnectTest.class.getName());
|
||||
|
||||
private static AnalogCrossConnectFixture analogIO;
|
||||
@@ -133,7 +135,6 @@ public class AnalogCrossConnectTest extends AbstractComsSetup {
|
||||
// Given
|
||||
AnalogTrigger trigger = new AnalogTrigger(analogIO.getInput());
|
||||
trigger.setLimitsVoltage(2.0f, 3.0f);
|
||||
|
||||
Counter counter = new Counter(trigger);
|
||||
|
||||
// When the analog output is turned low and high 50 times
|
||||
@@ -152,4 +153,48 @@ public class AnalogCrossConnectTest extends AbstractComsSetup {
|
||||
public void testRuntimeExceptionOnInvalidAccumulatorPort(){
|
||||
analogIO.getInput().getAccumulatorCount();
|
||||
}
|
||||
|
||||
private AnalogTrigger interruptTrigger;
|
||||
private AnalogTriggerOutput interruptTriggerOutput;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#giveInterruptableSensorBase()
|
||||
*/
|
||||
@Override
|
||||
InterruptableSensorBase giveInterruptableSensorBase() {
|
||||
interruptTrigger = new AnalogTrigger(analogIO.getInput());
|
||||
interruptTrigger.setLimitsVoltage(2.0f, 3.0f);
|
||||
interruptTriggerOutput = new AnalogTriggerOutput(interruptTrigger, AnalogTriggerType.STATE);
|
||||
return interruptTriggerOutput;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#freeInterruptableSensorBase()
|
||||
*/
|
||||
@Override
|
||||
void freeInterruptableSensorBase() {
|
||||
interruptTriggerOutput.cancelInterrupts();
|
||||
interruptTriggerOutput.free();
|
||||
interruptTriggerOutput = null;
|
||||
interruptTrigger.free();
|
||||
interruptTrigger = null;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#setInterruptHigh()
|
||||
*/
|
||||
@Override
|
||||
void setInterruptHigh() {
|
||||
analogIO.getOutput().setVoltage(4.0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#setInterruptLow()
|
||||
*/
|
||||
@Override
|
||||
void setInterruptLow() {
|
||||
analogIO.getOutput().setVoltage(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,12 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import edu.wpi.first.wpilibj.fixtures.AnalogCrossConnectFixture;
|
||||
@@ -68,8 +66,8 @@ public class AnalogPotentiometerTest extends AbstractComsSetup {
|
||||
public void testRangeValues(){
|
||||
for(double i = 0.0; i < 360.0; i = i+1.0){
|
||||
potSource.setAngle(i);
|
||||
assertEquals(i, pot.get(), DOUBLE_COMPARISON_DELTA);
|
||||
Timer.delay(.02);
|
||||
assertEquals(i, pot.get(), DOUBLE_COMPARISON_DELTA);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,16 +14,12 @@ import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import edu.wpi.first.wpilibj.fixtures.DIOCrossConnectFixture;
|
||||
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
|
||||
import edu.wpi.first.wpilibj.test.TestBench;
|
||||
|
||||
/**
|
||||
@@ -31,11 +27,12 @@ import edu.wpi.first.wpilibj.test.TestBench;
|
||||
* @author jonathanleitschuh
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class DIOCrossConnectTest extends AbstractComsSetup {
|
||||
public class DIOCrossConnectTest extends AbstractInterruptTest {
|
||||
private static final Logger logger = Logger.getLogger(DIOCrossConnectTest.class.getName());
|
||||
|
||||
private static DIOCrossConnectFixture dio = null;
|
||||
|
||||
@Override
|
||||
protected Logger getClassLogger(){
|
||||
return logger;
|
||||
}
|
||||
@@ -65,7 +62,7 @@ public class DIOCrossConnectTest extends AbstractComsSetup {
|
||||
* Array in the Collection, each array element corresponds to a parameter
|
||||
* in the constructor.
|
||||
*/
|
||||
@Parameters
|
||||
@Parameters(name= "{index}: Input Port: {0} Output Port: {1}")
|
||||
public static Collection<Integer[]> generateData() {
|
||||
// In this example, the parameter generator returns a List of
|
||||
// arrays. Each array has two elements: { Digital input port, Digital output port}.
|
||||
@@ -74,24 +71,14 @@ public class DIOCrossConnectTest extends AbstractComsSetup {
|
||||
return TestBench.getInstance().getDIOCrossConnectCollection();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownAfterClass() throws Exception {
|
||||
dio.teardown();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
dio.reset();
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
dio.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,4 +102,38 @@ public class DIOCrossConnectTest extends AbstractComsSetup {
|
||||
Timer.delay(.02);
|
||||
assertFalse("DIO Not Low after .05s delay", dio.getInput().get());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#giveInterruptableSensorBase()
|
||||
*/
|
||||
@Override
|
||||
InterruptableSensorBase giveInterruptableSensorBase() {
|
||||
return dio.getInput();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#freeInterruptableSensorBase()
|
||||
*/
|
||||
@Override
|
||||
void freeInterruptableSensorBase() {
|
||||
// Handled in the fixture
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#setInterruptHigh()
|
||||
*/
|
||||
@Override
|
||||
void setInterruptHigh() {
|
||||
dio.getOutput().set(true);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#setInterruptLow()
|
||||
*/
|
||||
@Override
|
||||
void setInterruptLow() {
|
||||
dio.getOutput().set(false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ public class DIOCrossConnectFixture implements ITestFixture {
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
try{
|
||||
input.cancelInterrupts();
|
||||
} catch(IllegalStateException e) {
|
||||
//This will happen if the interrupt has not been allocated for this test.
|
||||
}
|
||||
output.set(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "Log.hpp"
|
||||
#include "edu_wpi_first_wpilibj_hal_HALUtil.h"
|
||||
#include "HAL/HAL.hpp"
|
||||
#include "errno.h"
|
||||
#include <string.h>
|
||||
|
||||
// set the logging level
|
||||
TLogLevel halUtilLogLevel = logWARNING;
|
||||
@@ -145,3 +147,27 @@ JNIEXPORT jstring JNICALL Java_edu_wpi_first_wpilibj_hal_HALUtil_getHALErrorMess
|
||||
HALUTIL_LOG(logDEBUG) << "Calling HALUtil getHALErrorMessage id=" << paramId << " msg=" << msg;
|
||||
return paramEnv->NewStringUTF(msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_HALUtil
|
||||
* Method: getHALErrno
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_HALUtil_getHALErrno
|
||||
(JNIEnv *, jclass)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_HALUtil
|
||||
* Method: getHALstrerror
|
||||
* Signature: (I)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_edu_wpi_first_wpilibj_hal_HALUtil_getHALstrerror
|
||||
(JNIEnv * env, jclass, jint errorCode)
|
||||
{
|
||||
const char * msg = strerror(errno);
|
||||
HALUTIL_LOG(logDEBUG) << "Calling HALUtil getHALstrerror errorCode=" << errorCode << " msg=" << msg;
|
||||
return env->NewStringUTF(msg);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,33 @@
|
||||
#include "Log.hpp"
|
||||
|
||||
#include "edu_wpi_first_wpilibj_hal_InterruptJNI.h"
|
||||
#include "HAL/Interrupts.hpp"
|
||||
|
||||
TLogLevel interruptJNILogLevel = logERROR;
|
||||
|
||||
#define INTERRUPTJNI_LOG(level) \
|
||||
if (level > interruptJNILogLevel) ; \
|
||||
else Log().Get(level)
|
||||
|
||||
//Used for callback when an interrupt is fired.
|
||||
static JavaVM *jvm;
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_InterruptJNI
|
||||
* Method: initializeInterruptJVM
|
||||
* Signature: (Ljava/nio/IntBuffer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_initializeInterruptJVM
|
||||
(JNIEnv * env, jclass, jobject status)
|
||||
{
|
||||
//This method should be called once to setup the JVM
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI initializeInterruptJVM";
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
jint rs = env->GetJavaVM(&jvm);
|
||||
assert (rs == JNI_OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_InterruptJNI
|
||||
@@ -10,22 +37,41 @@
|
||||
* Signature: (IBLjava/nio/IntBuffer;)Ljava/nio/ByteBuffer;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_initializeInterrupts
|
||||
(JNIEnv *, jclass, jint, jbyte, jobject)
|
||||
(JNIEnv * env, jclass, jint interruptIndex, jbyte watcher, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI initializeInterrupts";
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "interruptIndex = " << interruptIndex;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "watcher = " << (bool) watcher;
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
void** interruptPtr = (void**)new unsigned char[4];
|
||||
*interruptPtr = (void**) initializeInterrupts(interruptIndex, watcher, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *interruptPtr;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
|
||||
return env->NewDirectByteBuffer(interruptPtr, 4);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_InterruptJNI
|
||||
* Method: cleanInterrupts
|
||||
* Signature: (Ljava/nio/ByteBuffer;Ljava/nio/IntBuffer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_cleanInterrupts
|
||||
(JNIEnv *, jclass, jobject, jobject)
|
||||
(JNIEnv * env, jclass, jobject interrupt_pointer, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI cleanInterrupts";
|
||||
void ** javaId = (void**)env->GetDirectBufferAddress(interrupt_pointer);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *javaId;
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
cleanInterrupts(*javaId, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -34,10 +80,17 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_cleanInterrup
|
||||
* Signature: (Ljava/nio/ByteBuffer;DLjava/nio/IntBuffer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_waitForInterrupt
|
||||
(JNIEnv *, jclass, jobject, jdouble, jobject)
|
||||
(JNIEnv * env, jclass, jobject interrupt_pointer, jdouble timeout, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI waitForInterrupt";
|
||||
void ** javaId = (void**)env->GetDirectBufferAddress(interrupt_pointer);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *javaId;
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
waitForInterrupt(*javaId, timeout, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -46,10 +99,17 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_waitForInterr
|
||||
* Signature: (Ljava/nio/ByteBuffer;Ljava/nio/IntBuffer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_enableInterrupts
|
||||
(JNIEnv *, jclass, jobject, jobject)
|
||||
(JNIEnv * env, jclass, jobject interrupt_pointer, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI enableInterrupts";
|
||||
void ** javaId = (void**)env->GetDirectBufferAddress(interrupt_pointer);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *javaId;
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
enableInterrupts(*javaId, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -58,10 +118,17 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_enableInterru
|
||||
* Signature: (Ljava/nio/ByteBuffer;Ljava/nio/IntBuffer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_disableInterrupts
|
||||
(JNIEnv *, jclass, jobject, jobject)
|
||||
(JNIEnv * env, jclass, jobject interrupt_pointer, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI disableInterrupts";
|
||||
void ** javaId = (void**)env->GetDirectBufferAddress(interrupt_pointer);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *javaId;
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
disableInterrupts(*javaId, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -70,10 +137,18 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_disableInterr
|
||||
* Signature: (Ljava/nio/ByteBuffer;Ljava/nio/IntBuffer;)D
|
||||
*/
|
||||
JNIEXPORT jdouble JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_readInterruptTimestamp
|
||||
(JNIEnv *, jclass, jobject, jobject)
|
||||
(JNIEnv * env, jclass, jobject interrupt_pointer, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI readInterruptTimestamp";
|
||||
void ** javaId = (void**)env->GetDirectBufferAddress(interrupt_pointer);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *javaId;
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
jdouble timeStamp = readInterruptTimestamp(*javaId, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -82,10 +157,73 @@ JNIEXPORT jdouble JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_readInterr
|
||||
* Signature: (Ljava/nio/ByteBuffer;BIBLjava/nio/IntBuffer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_requestInterrupts
|
||||
(JNIEnv *, jclass, jobject, jbyte, jint, jbyte, jobject)
|
||||
(JNIEnv * env, jclass, jobject interrupt_pointer, jbyte routing_module, jint routing_pin, jbyte routing_analog_trigger, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI requestInterrupts";
|
||||
void ** javaId = (void**)env->GetDirectBufferAddress(interrupt_pointer);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *javaId;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "routing module = " << (jint) routing_module;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "routing pin = " << routing_pin;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "routing analog trigger = " << (jint) routing_analog_trigger;
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
requestInterrupts(*javaId, (uint8_t) routing_module, (uint32_t) routing_pin, routing_analog_trigger, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct InterruptHandlerParam {
|
||||
/*
|
||||
* The object edu/wpi/first/wpilibj/hal/InterruptJNI/InterruptHandlerFunction
|
||||
* that contains the callback method [code]mid[/code].
|
||||
*/
|
||||
jobject handler_obj;
|
||||
|
||||
//The method id for the callback method
|
||||
jmethodID mid;
|
||||
|
||||
//The params passed to the function
|
||||
jobject param;
|
||||
|
||||
~InterruptHandlerParam(){
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI InterruptHandlerParam Destructor";
|
||||
JNIEnv *env;
|
||||
jint rs = jvm->AttachCurrentThread((void**)&env, NULL);
|
||||
assert (rs == JNI_OK);
|
||||
|
||||
env->DeleteGlobalRef(handler_obj);
|
||||
env->DeleteGlobalRef(param);
|
||||
rs = jvm->DetachCurrentThread();
|
||||
assert (rs == JNI_OK);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Leaving INTERRUPTJNI InterruptHandlerParam Destructor";
|
||||
}
|
||||
};
|
||||
|
||||
void interruptHandler(uint32_t mask, void *data) {
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI interruptHandler";
|
||||
InterruptHandlerParam *param = static_cast<InterruptHandlerParam *>(data);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "InterruptHandlerParam Ptr = " << param;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "InterruptHandlerParam->obj = " << param->handler_obj;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "InterruptHandlerParam->param = " << param->param;
|
||||
|
||||
//Because this is a callback in a new thread we must attach it to the JVM
|
||||
JNIEnv *env;
|
||||
jint rs = jvm->AttachCurrentThread((void**)&env, NULL);
|
||||
assert (rs == JNI_OK);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Attached to thread";
|
||||
|
||||
env->CallVoidMethod(param->handler_obj, param->mid, mask, param->param);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
rs = jvm->DetachCurrentThread();
|
||||
assert (rs == JNI_OK);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Leaving INTERRUPTJNI interruptHandler";
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,10 +232,47 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_requestInterr
|
||||
* Signature: (Ljava/nio/ByteBuffer;Ledu/wpi/first/wpilibj/hal/InterruptJNI/InterruptHandlerFunction;Ljava/nio/ByteBuffer;Ljava/nio/IntBuffer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_attachInterruptHandler
|
||||
(JNIEnv *, jclass, jobject, jobject, jobject, jobject)
|
||||
(JNIEnv * env, jclass, jobject interrupt_pointer, jobject handler, jobject param, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI attachInterruptHandler";
|
||||
void ** javaId = (void**)env->GetDirectBufferAddress(interrupt_pointer);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *javaId;
|
||||
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
//Store the interrupt callback paramaters
|
||||
InterruptHandlerParam *interruptHandlerParam = new InterruptHandlerParam();
|
||||
//Stores the object that contains the callback
|
||||
interruptHandlerParam->handler_obj = env->NewGlobalRef(handler);
|
||||
//The parameter that will be passed back to the JVM when the method is called
|
||||
interruptHandlerParam->param = env->NewGlobalRef(param);
|
||||
|
||||
jclass cls = env->GetObjectClass(handler);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "class = " << cls;
|
||||
if (cls == 0) {
|
||||
INTERRUPTJNI_LOG(logERROR) << "Error getting java class";
|
||||
assert (false);
|
||||
return;
|
||||
}
|
||||
|
||||
jmethodID mid = env->GetMethodID(cls, "apply", "(ILjava/lang/Object;)V");
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "method = " << mid;
|
||||
if (mid == 0) {
|
||||
INTERRUPTJNI_LOG(logERROR) << "Error getting java method ID";
|
||||
assert (false);
|
||||
return;
|
||||
}
|
||||
interruptHandlerParam->mid = mid;
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "InterruptHandlerParam Ptr = " << interruptHandlerParam;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "InterruptHandlerParam->obj (handler) = " << interruptHandlerParam->handler_obj;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "InterruptHandlerParam->mid = " << interruptHandlerParam->mid;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "InterruptHandlerParam->param = " << interruptHandlerParam->param;
|
||||
|
||||
attachInterruptHandler(*javaId, interruptHandler, interruptHandlerParam, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,8 +281,18 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_attachInterru
|
||||
* Signature: (Ljava/nio/ByteBuffer;BBLjava/nio/IntBuffer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_InterruptJNI_setInterruptUpSourceEdge
|
||||
(JNIEnv *, jclass, jobject, jbyte, jbyte, jobject)
|
||||
(JNIEnv * env, jclass, jobject interrupt_pointer, jbyte risingEdge, jbyte fallingEdge, jobject status)
|
||||
{
|
||||
assert(false);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI setInterruptUpSourceEdge";
|
||||
void ** javaId = (void**)env->GetDirectBufferAddress(interrupt_pointer);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Ptr = " << *javaId;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Rising Edge = " << (bool) risingEdge;
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Falling Edge = " << (bool) fallingEdge;
|
||||
|
||||
jint * statusPtr = (jint*)env->GetDirectBufferAddress(status);
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status Ptr = " << statusPtr;
|
||||
|
||||
setInterruptUpSourceEdge(*javaId, risingEdge, fallingEdge, statusPtr);
|
||||
|
||||
INTERRUPTJNI_LOG(logDEBUG) << "Status = " << *statusPtr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user