/* * Copyright 2015-2016 Cel Skeggs * Copyright 2015 Jake Springer * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with the CCRE. If not, see <http://www.gnu.org/licenses/>. * * * This file contains code inspired by/based on code Copyright 2008-2014 FIRST. * To see the license terms of that code (modified BSD), see the root of the CCRE. */ package ccre.frc; import edu.wpi.first.wpilibj.hal.DIOJNI; import edu.wpi.first.wpilibj.hal.InterruptJNI; import edu.wpi.first.wpilibj.hal.JNIWrapper; class DirectDigital { public static final int DIGITAL_NUM = 26, INTERRUPT_NUM = 8; static final boolean WATCH_ASYNCHRONOUS = false, WATCH_SYNCHRONOUS = true; static final boolean TRIGGER_DIGITAL = false, TRIGGER_ANALOG = true; /** * Number of digital pins on a roboRIO. */ static final int DIGITAL_PINS = 26; private static final long[] digitals = new long[DIGITAL_NUM]; private static final boolean[] asInputs = new boolean[DIGITAL_NUM]; private static final long[] interrupts = new long[INTERRUPT_NUM]; private static final Integer[] interruptMap = new Integer[DIGITAL_NUM]; public static synchronized void init(int channel, boolean asInput) { if (channel < 0 || channel >= DIGITAL_NUM) { throw new RuntimeException("Invalid digital port: " + channel); } if (digitals[channel] == 0) { long port = DIOJNI.initializeDigitalPort(JNIWrapper.getPort((byte) channel)); DIOJNI.allocateDIO(port, asInput); digitals[channel] = port; asInputs[channel] = asInput; } else if (asInputs[channel] != asInput) { throw new RuntimeException("Digital port allocated for I and O: " + channel); } } public static synchronized void free(int channel) { long port = digitals[channel]; if (port == 0) { throw new RuntimeException("Unallocated digital port: " + channel); } DIOJNI.freeDIO(port); } public static void set(int channel, boolean value) { long dig = digitals[channel]; if (dig == 0) { throw new RuntimeException("Unallocated digital port: " + channel); } if (asInputs[channel]) { throw new RuntimeException("Digital port not opened for writing: " + channel); } DIOJNI.setDIO(dig, (short) (value ? 1 : 0)); } public static boolean get(int channel) { long dig = digitals[channel]; if (dig == 0) { throw new RuntimeException("Unallocated digital port: " + channel); } if (!asInputs[channel]) { throw new RuntimeException("Digital port not opened for reading: " + channel); } return DIOJNI.getDIO(dig); } private static synchronized int allocateInterrupt() { for (int i = 0; i < INTERRUPT_NUM; i++) { if (interrupts[i] == 0) { // TODO: what if this fails? intr is leaked. interrupts[i] = InterruptJNI.initializeInterrupts(i, WATCH_SYNCHRONOUS); return i; } } throw new RuntimeException("Ran out of interrupts! Consider using fewer interrupts in your code."); } public static synchronized void initInterruptsSynchronous(int id, boolean risingEdge, boolean fallingEdge) { if (interruptMap[id] == null) { int intr = allocateInterrupt(); byte module_id = 0; InterruptJNI.requestInterrupts(interrupts[intr], module_id, id, TRIGGER_DIGITAL); interruptMap[id] = intr; } InterruptJNI.setInterruptUpSourceEdge(interrupts[interruptMap[id]], risingEdge, fallingEdge); } // returns if timed out public static boolean waitForInterrupt(int id, float timeout, boolean ignorePrevious) { if (interruptMap[id] == null) { throw new RuntimeException("No interrupt allocated for digital input: " + id); } return InterruptJNI.waitForInterrupt(interrupts[interruptMap[id]], timeout, ignorePrevious) == 0; } /** * Returns a pointer to the digital source port on the specified channel. * Will return null if digital source has not been initialized. * * @param channel the digital channel number to access, starting at 0. * @return the C pointer for this digital channel, or null if uninitialized. */ public static long getDigitalSource(int channel) { return digitals[channel]; } public static boolean isDigitalSourceInput(int channel) { return asInputs[channel]; } }