001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.hal;
006
007import java.util.HashMap;
008import java.util.Map;
009
010@SuppressWarnings("AbbreviationAsWordInName")
011public class DMAJNISample {
012  private static final int kEnable_Accumulator0 = 8;
013  private static final int kEnable_Accumulator1 = 9;
014
015  static class BaseStore {
016    public final int m_valueType;
017    public final int m_index;
018
019    BaseStore(int valueType, int index) {
020      this.m_valueType = valueType;
021      this.m_index = index;
022    }
023  }
024
025  private final int[] m_dataBuffer = new int[100];
026  private final int[] m_storage = new int[100];
027  private long m_timeStamp;
028  private Map<Integer, BaseStore> m_propertyMap = new HashMap<>();
029
030  public int update(int dmaHandle, double timeoutSeconds) {
031    m_timeStamp = DMAJNI.readDMA(dmaHandle, timeoutSeconds, m_dataBuffer, m_storage);
032    return m_storage[25];
033  }
034
035  public int getCaptureSize() {
036    return m_storage[22];
037  }
038
039  public int getTriggerChannels() {
040    return m_storage[23];
041  }
042
043  public int getRemaining() {
044    return m_storage[24];
045  }
046
047  public long getTime() {
048    return m_timeStamp;
049  }
050
051  private BaseStore addSensorInternal(int handle) {
052    BaseStore sensorData = DMAJNI.getSensorReadData(handle);
053    m_propertyMap.put(handle, sensorData);
054    return sensorData;
055  }
056
057  public void addSensor(int handle) {
058    addSensorInternal(handle);
059  }
060
061  private int readValue(int valueType, int index) {
062    int offset = m_storage[valueType];
063    if (offset == -1) {
064      throw new RuntimeException("Resource not found in DMA capture");
065    }
066    return m_dataBuffer[offset + index];
067  }
068
069  public int getEncoder(int encoderHandle) {
070    BaseStore data = m_propertyMap.get(encoderHandle);
071    if (data == null) {
072      data = addSensorInternal(encoderHandle);
073    }
074    return readValue(data.m_valueType, data.m_index);
075  }
076
077  public int getEncoderPeriod(int encoderHandle) {
078    BaseStore data = m_propertyMap.get(encoderHandle);
079    if (data == null) {
080      data = addSensorInternal(encoderHandle);
081    }
082    // + 2 Hack, but needed to not have to call into JNI
083    return readValue(data.m_valueType + 2, data.m_index);
084  }
085
086  public int getCounter(int counterHandle) {
087    BaseStore data = m_propertyMap.get(counterHandle);
088    if (data == null) {
089      data = addSensorInternal(counterHandle);
090    }
091    return readValue(data.m_valueType, data.m_index);
092  }
093
094  public int getCounterPeriod(int counterHandle) {
095    BaseStore data = m_propertyMap.get(counterHandle);
096    if (data == null) {
097      data = addSensorInternal(counterHandle);
098    }
099    // Hack, but needed to not have to call into JNI
100    return readValue(data.m_valueType + 2, data.m_index);
101  }
102
103  public boolean getDigitalSource(int digitalSourceHandle) {
104    BaseStore data = m_propertyMap.get(digitalSourceHandle);
105    if (data == null) {
106      data = addSensorInternal(digitalSourceHandle);
107    }
108
109    int value = readValue(data.m_valueType, 0);
110
111    return ((value >> data.m_index) & 0x1) != 0;
112  }
113
114  public int getAnalogInput(int analogInputHandle) {
115    BaseStore data = m_propertyMap.get(analogInputHandle);
116    if (data == null) {
117      data = addSensorInternal(analogInputHandle);
118    }
119
120    int value = readValue(data.m_valueType, data.m_index / 2);
121    if ((data.m_index % 2) != 0) {
122      return (value >>> 16) & 0xFFFF;
123    } else {
124      return value & 0xFFFF;
125    }
126  }
127
128  public int getAnalogInputAveraged(int analogInputHandle) {
129    BaseStore data = m_propertyMap.get(analogInputHandle);
130    if (data == null) {
131      data = addSensorInternal(analogInputHandle);
132    }
133
134    // + 2 Hack, but needed to not have to call into JNI
135    int value = readValue(data.m_valueType + 2, data.m_index);
136    return value;
137  }
138
139  public void getAnalogAccumulator(int analogInputHandle, AccumulatorResult result) {
140    BaseStore data = m_propertyMap.get(analogInputHandle);
141    if (data == null) {
142      data = addSensorInternal(analogInputHandle);
143    }
144
145    if (data.m_index == 0) {
146      int val0 = readValue(kEnable_Accumulator0, 0);
147      int val1 = readValue(kEnable_Accumulator0, 1);
148      int val2 = readValue(kEnable_Accumulator0, 2);
149      result.count = val2;
150      result.value = ((long) val1 << 32) | val0;
151    } else if (data.m_index == 1) {
152      int val0 = readValue(kEnable_Accumulator1, 0);
153      int val1 = readValue(kEnable_Accumulator1, 1);
154      int val2 = readValue(kEnable_Accumulator1, 2);
155      result.count = val2;
156      result.value = ((long) val1 << 32) | val0;
157    } else {
158      throw new RuntimeException("Resource not found in DMA capture");
159    }
160  }
161
162  public int getDutyCycleOutput(int dutyCycleHandle) {
163    BaseStore data = m_propertyMap.get(dutyCycleHandle);
164    if (data == null) {
165      data = addSensorInternal(dutyCycleHandle);
166    }
167    return readValue(data.m_valueType, data.m_index);
168  }
169}