mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-25 01:41:43 +00:00
Adds interrupts to Java
Implements the JNI bindings for java Adds integration tests for Digital Inputs and AnalogTriggers. Adds the ability to get the value and message from errno in java using the HALUtil JNI class. Change-Id: I853529fdab9744ce95ee15d4cc73dc3953265552
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