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