mirror of
https://github.com/trc492/FtcTemplate.git
synced 2025-07-01 13:01:24 -07:00
Updated FtcLib.
Added OctoQuad support.
This commit is contained in:
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2022 DigitalChickenLabs
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.qualcomm.hardware.digitalchickenlabs;
|
||||
|
||||
public interface CachingOctoQuad extends OctoQuadBase
|
||||
{
|
||||
/**
|
||||
* Controls how data is cached to reduce the number
|
||||
* of Lynx transactions needed to read the encoder data
|
||||
*/
|
||||
enum CachingMode
|
||||
{
|
||||
/*
|
||||
* No caching at all
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* The cache is only updated when you call {@link #setCachingMode(CachingMode)}
|
||||
*/
|
||||
MANUAL,
|
||||
|
||||
/**
|
||||
* The cache is updated the 2nd time you call {@link #readSinglePosition_Caching(int)} (int)}
|
||||
* or {@link #readSingleVelocity_Caching(int)} (int)} for the same encoder index.
|
||||
*/
|
||||
AUTO
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data caching mode for the OctoQuad
|
||||
* @param mode mode to use
|
||||
*/
|
||||
void setCachingMode(CachingMode mode);
|
||||
|
||||
/**
|
||||
* Manually refresh the position and velocity data cache
|
||||
*/
|
||||
void refreshCache();
|
||||
|
||||
/**
|
||||
* Read a single position from the OctoQuad
|
||||
* Note this call may return cached data based on
|
||||
* the {@link CachingMode} you selected!
|
||||
* Depending on the channel bank configuration, this may
|
||||
* either be quadrature step count, or pulse width.
|
||||
* @param idx the index of the encoder to read
|
||||
* @return the position for the specified encoder
|
||||
*/
|
||||
int readSinglePosition_Caching(int idx);
|
||||
|
||||
/**
|
||||
* Read a single velocity from the OctoQuad
|
||||
* Note this call may return cached data based on
|
||||
* the {@link CachingMode} you selected!
|
||||
* NOTE: if using an absolute pulse width encoder, in order to get sane
|
||||
* velocity data, you must set the channel min/max pulse width parameter.
|
||||
* @param idx the index of the encoder to read
|
||||
* @return the velocity for the specified encoder
|
||||
*/
|
||||
short readSingleVelocity_Caching(int idx);
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2022 DigitalChickenLabs
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.qualcomm.hardware.digitalchickenlabs;
|
||||
|
||||
public interface OctoQuad extends OctoQuadBase
|
||||
{
|
||||
/**
|
||||
* Class to represent an OctoQuad firmware version
|
||||
*/
|
||||
class FirmwareVersion
|
||||
{
|
||||
public final int maj;
|
||||
public final int min;
|
||||
public final int eng;
|
||||
|
||||
public FirmwareVersion(int maj, int min, int eng)
|
||||
{
|
||||
this.maj = maj;
|
||||
this.min = min;
|
||||
this.eng = eng;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%d.%d.%d", maj, min, eng);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the firmware version running on the OctoQuad
|
||||
* @return the firmware version running on the OctoQuad
|
||||
*/
|
||||
FirmwareVersion getFirmwareVersion();
|
||||
|
||||
/**
|
||||
* Read a single position from the OctoQuad
|
||||
* Depending on the channel bank configuration, this may
|
||||
* either be quadrature step count, or pulse width.
|
||||
* @param idx the index of the encoder to read
|
||||
* @return the position for the specified encoder
|
||||
*/
|
||||
int readSinglePosition(int idx);
|
||||
|
||||
/**
|
||||
* Reads all positions from the OctoQuad, writing the data into
|
||||
* an existing int[] object. The previous values are destroyed.
|
||||
* Depending on the channel bank configuration, this may
|
||||
* either be quadrature step count, or pulse width.
|
||||
* @param out the int[] object to fill with new data
|
||||
*/
|
||||
void readAllPositions(int[] out);
|
||||
|
||||
/**
|
||||
* Reads all positions from the OctoQuad
|
||||
* Depending on the channel bank configuration, this may
|
||||
* either be quadrature step count, or pulse width.
|
||||
* @return an int[] object with the new data
|
||||
*/
|
||||
int[] readAllPositions();
|
||||
|
||||
/**
|
||||
* Read a selected range of encoders
|
||||
* Depending on the channel bank configuration, this may
|
||||
* either be quadrature step count, or pulse width.
|
||||
* @param idxFirst the first encoder (inclusive)
|
||||
* @param idxLast the last encoder (inclusive)
|
||||
* @return an array containing the requested encoder positions
|
||||
*/
|
||||
int[] readPositionRange(int idxFirst, int idxLast);
|
||||
|
||||
/*
|
||||
* More Reset methods in Base interface
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reset multiple encoders in the OctoQuad firmware in one command
|
||||
* @param resets the encoders to be reset
|
||||
*/
|
||||
void resetMultiplePositions(boolean[] resets);
|
||||
|
||||
/**
|
||||
* Reset multiple encoders in the OctoQuad firmware in one command
|
||||
* @param indices the indices of the encoders to reset
|
||||
*/
|
||||
void resetMultiplePositions(int... indices);
|
||||
|
||||
/*
|
||||
* More direction methods in Base interface
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set the direction for all encoders
|
||||
* This parameter will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param reverse 8-length direction array
|
||||
*/
|
||||
void setAllEncoderDirections(boolean[] reverse);
|
||||
|
||||
/**
|
||||
* Read a single velocity from the OctoQuad
|
||||
* NOTE: if using an absolute pulse width encoder, in order to get sane
|
||||
* velocity data, you must set the channel min/max pulse width parameter.
|
||||
* @param idx the index of the encoder to read
|
||||
* @return the velocity for the specified encoder
|
||||
*/
|
||||
short readSingleVelocity(int idx);
|
||||
|
||||
/**
|
||||
* Reads all velocities from the OctoQuad, writing the data into
|
||||
* an existing short[] object. The previous values are destroyed.
|
||||
* NOTE: if using an absolute pulse width encoder, in order to get sane
|
||||
* velocity data, you must set the channel min/max pulse width parameter.
|
||||
* @param out the short[] object to fill with new data
|
||||
*/
|
||||
void readAllVelocities(short[] out);
|
||||
|
||||
/**
|
||||
* Reads all velocities from the OctoQuad
|
||||
* NOTE: if using an absolute pulse width encoder, in order to get sane
|
||||
* velocity data, you must set the channel min/max pulse width parameter.
|
||||
* @return a short[] object with the new data
|
||||
*/
|
||||
short[] readAllVelocities();
|
||||
|
||||
/**
|
||||
* Read a selected range of encoder velocities
|
||||
* NOTE: if using an absolute pulse width encoder, in order to get sane
|
||||
* velocity data, you must set the channel min/max pulse width parameter.
|
||||
* @param idxFirst the first encoder (inclusive)
|
||||
* @param idxLast the last encoder (inclusive)
|
||||
* @return an array containing the requested velocities
|
||||
*/
|
||||
short[] readVelocityRange(int idxFirst, int idxLast);
|
||||
|
||||
class EncoderDataBlock
|
||||
{
|
||||
public int[] positions = new int[NUM_ENCODERS];
|
||||
public short[] velocities = new short[NUM_ENCODERS];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all encoder data from the OctoQuad, writing the data into
|
||||
* an existing {@link EncoderDataBlock} object. The previous values are destroyed.
|
||||
* @param out the {@link EncoderDataBlock} object to fill with new data
|
||||
*/
|
||||
void readAllEncoderData(EncoderDataBlock out);
|
||||
|
||||
/**
|
||||
* Reads all encoder data from the OctoQuad
|
||||
* @return a {@link EncoderDataBlock} object with the new data
|
||||
*/
|
||||
EncoderDataBlock readAllEncoderData();
|
||||
|
||||
/*
|
||||
* More velocity sample interval methods in base interface
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set the velocity sample intervals for all encoders
|
||||
* This parameter will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param intvlms the sample intervals in milliseconds
|
||||
*/
|
||||
void setAllVelocitySampleIntervals(int[] intvlms);
|
||||
|
||||
/**
|
||||
* Reads all velocity sample intervals from the OctoQuad
|
||||
* @return all velocity sample intervals from the OctoQuad
|
||||
*/
|
||||
int[] getAllVelocitySampleIntervals();
|
||||
|
||||
class ChannelPulseWidthParams
|
||||
{
|
||||
public int min_length_us;
|
||||
public int max_length_us;
|
||||
|
||||
public ChannelPulseWidthParams() {};
|
||||
|
||||
public ChannelPulseWidthParams(int min_length_us, int max_length_us)
|
||||
{
|
||||
this.min_length_us = min_length_us;
|
||||
this.max_length_us = max_length_us;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the minimum/maximum pulse width reported by an absolute encoder
|
||||
* which is connected to a given channel, to allow the ability to provide
|
||||
* accurate velocity data.
|
||||
* These parameters will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param idx the channel in question
|
||||
* @param params minimum/maximum pulse width
|
||||
*/
|
||||
void setSingleChannelPulseWidthParams(int idx, ChannelPulseWidthParams params);
|
||||
|
||||
/**
|
||||
* Queries the OctoQuad to determine the currently set minimum/maxiumum pulse
|
||||
* width for an encoder channel, to allow sane velocity data.
|
||||
* @param idx the channel in question
|
||||
* @return minimum/maximum pulse width
|
||||
*/
|
||||
ChannelPulseWidthParams getSingleChannelPulseWidthParams(int idx);
|
||||
}
|
||||
|
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2022 DigitalChickenLabs
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.qualcomm.hardware.digitalchickenlabs;
|
||||
|
||||
public interface OctoQuadBase
|
||||
{
|
||||
byte OCTOQUAD_CHIP_ID = 0x51;
|
||||
int SUPPORTED_FW_VERSION_MAJ = 2;
|
||||
int ENCODER_FIRST = 0;
|
||||
int ENCODER_LAST = 7;
|
||||
int NUM_ENCODERS = 8;
|
||||
int MIN_VELOCITY_MEASUREMENT_INTERVAL_MS = 1;
|
||||
int MAX_VELOCITY_MEASUREMENT_INTERVAL_MS = 255;
|
||||
int MIN_PULSE_WIDTH_LENGTH_µS = 1;
|
||||
int MAX_PULSE_WIDTH_LENGTH_µS = 0xFFFF;
|
||||
|
||||
/**
|
||||
* Reads the CHIP_ID register of the OctoQuad
|
||||
* @return the value in the CHIP_ID register of the OctoQuad
|
||||
*/
|
||||
byte getChipId();
|
||||
|
||||
/**
|
||||
* Get the firmware version running on the OctoQuad
|
||||
* @return the firmware version running on the OctoQuad
|
||||
*/
|
||||
String getFirmwareVersionString();
|
||||
|
||||
/**
|
||||
* Reset a single encoder in the OctoQuad firmware
|
||||
* @param idx the index of the encoder to reset
|
||||
*/
|
||||
void resetSinglePosition(int idx);
|
||||
|
||||
/**
|
||||
* Reset all encoder counts in the OctoQuad firmware
|
||||
*/
|
||||
void resetAllPositions();
|
||||
|
||||
enum EncoderDirection
|
||||
{
|
||||
FORWARD,
|
||||
REVERSE
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the direction for a single encoder
|
||||
* This parameter will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param idx the index of the encoder
|
||||
* @param dir direction
|
||||
*/
|
||||
void setSingleEncoderDirection(int idx, EncoderDirection dir);
|
||||
|
||||
/**
|
||||
* Get the direction for a single encoder
|
||||
* @param idx the index of the encoder
|
||||
* @return direction of the encoder in question
|
||||
*/
|
||||
EncoderDirection getSingleEncoderDirection(int idx);
|
||||
|
||||
/**
|
||||
* Set the velocity sample interval for a single encoder
|
||||
* This parameter will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param idx the index of the encoder in question
|
||||
* @param intvlms the sample interval in milliseconds
|
||||
*/
|
||||
void setSingleVelocitySampleInterval(int idx, int intvlms);
|
||||
|
||||
/**
|
||||
* Set the velocity sample interval for all encoders
|
||||
* This parameter will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param intvlms the sample interval in milliseconds
|
||||
*/
|
||||
void setAllVelocitySampleIntervals(int intvlms);
|
||||
|
||||
/**
|
||||
* Read a single velocity sample interval
|
||||
* @param idx the index of the encoder in question
|
||||
* @return the velocity sample interval
|
||||
*/
|
||||
int getSingleVelocitySampleInterval(int idx);
|
||||
|
||||
/**
|
||||
* Configure the minimum/maximum pulse width reported by an absolute encoder
|
||||
* which is connected to a given channel, to allow the ability to provide
|
||||
* accurate velocity data.
|
||||
* These parameters will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param idx the channel in question
|
||||
* @param min_length_us minimum pulse width
|
||||
* @param max_length_us maximum pulse width
|
||||
*/
|
||||
void setSingleChannelPulseWidthParams(int idx, int min_length_us, int max_length_us);
|
||||
|
||||
/**
|
||||
* Run the firmware's internal reset routine
|
||||
*/
|
||||
void resetEverything();
|
||||
|
||||
enum ChannelBankConfig
|
||||
{
|
||||
/**
|
||||
* Both channel banks are configured for Quadrature input
|
||||
*/
|
||||
ALL_QUADRATURE(0),
|
||||
|
||||
/**
|
||||
* Both channel banks are configured for pulse width input
|
||||
*/
|
||||
ALL_PULSE_WIDTH(1),
|
||||
|
||||
/**
|
||||
* Bank 1 (channels 0-3) is configured for Quadrature input;
|
||||
* Bank 2 (channels 4-7) is configured for pulse width input.
|
||||
*/
|
||||
BANK1_QUADRATURE_BANK2_PULSE_WIDTH(2);
|
||||
|
||||
public byte bVal;
|
||||
|
||||
ChannelBankConfig(int bVal)
|
||||
{
|
||||
this.bVal = (byte) bVal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the OctoQuad's channel banks
|
||||
* This parameter will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param config the channel bank configuration to use
|
||||
*/
|
||||
void setChannelBankConfig(ChannelBankConfig config);
|
||||
|
||||
/**
|
||||
* Queries the OctoQuad to determine the current channel bank configuration
|
||||
* @return the current channel bank configuration
|
||||
*/
|
||||
ChannelBankConfig getChannelBankConfig();
|
||||
|
||||
enum I2cRecoveryMode
|
||||
{
|
||||
/**
|
||||
* Does not perform any active attempts to recover a wedged I2C bus
|
||||
*/
|
||||
NONE(0),
|
||||
|
||||
/**
|
||||
* The OctoQuad will reset its I2C peripheral if 50ms elapses between
|
||||
* byte transmissions or between bytes and start/stop conditions
|
||||
*/
|
||||
MODE_1_PERIPH_RST_ON_FRAME_ERR(1),
|
||||
|
||||
/**
|
||||
* Mode 1 actions + the OctoQuad will toggle the clock line briefly,
|
||||
* once, after 1500ms of no communications.
|
||||
*/
|
||||
MODE_2_M1_PLUS_SCL_IDLE_ONESHOT_TGL(2);
|
||||
|
||||
public byte bVal;
|
||||
|
||||
I2cRecoveryMode(int bVal)
|
||||
{
|
||||
this.bVal = (byte) bVal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the OctoQuad to use the specified I2C recovery mode.
|
||||
* This parameter will NOT be retained across power cycles, unless
|
||||
* you call {@link #saveParametersToFlash()} ()}
|
||||
* @param mode the recovery mode to use
|
||||
*/
|
||||
void setI2cRecoveryMode(I2cRecoveryMode mode);
|
||||
|
||||
/**
|
||||
* Queries the OctoQuad to determine the currently configured I2C recovery mode
|
||||
* @return the currently configured I2C recovery mode
|
||||
*/
|
||||
I2cRecoveryMode getI2cRecoveryMode();
|
||||
|
||||
/**
|
||||
* Stores the current state of parameters to flash, to be applied at next boot
|
||||
*/
|
||||
void saveParametersToFlash();
|
||||
}
|
@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Copyright (c) 2022 DigitalChickenLabs
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.qualcomm.hardware.digitalchickenlabs;
|
||||
|
||||
import com.qualcomm.hardware.lynx.LynxI2cDeviceSynch;
|
||||
import com.qualcomm.robotcore.hardware.I2cAddr;
|
||||
import com.qualcomm.robotcore.hardware.I2cDeviceSynch;
|
||||
import com.qualcomm.robotcore.hardware.I2cDeviceSynchDevice;
|
||||
import com.qualcomm.robotcore.hardware.configuration.annotations.DeviceProperties;
|
||||
import com.qualcomm.robotcore.hardware.configuration.annotations.I2cDeviceType;
|
||||
import com.qualcomm.robotcore.util.Range;
|
||||
import com.qualcomm.robotcore.util.RobotLog;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
@I2cDeviceType
|
||||
@DeviceProperties(xmlTag = "OctoQuadFTC", name = "OctoQuadFTC")
|
||||
public class OctoQuadImpl extends I2cDeviceSynchDevice<I2cDeviceSynch> implements OctoQuad, CachingOctoQuad
|
||||
{
|
||||
private static final int I2C_ADDRESS = 0x30;
|
||||
private static final ByteOrder OCTOQUAD_ENDIAN = ByteOrder.LITTLE_ENDIAN;
|
||||
|
||||
private static final byte CMD_SET_PARAM = 1;
|
||||
private static final byte CMD_READ_PARAM = 2;
|
||||
private static final byte CMD_WRITE_PARAMS_TO_FLASH = 3;
|
||||
|
||||
private static final byte CMD_RESET_EVERYTHING = 20;
|
||||
private static final byte CMD_RESET_ENCODERS = 21;
|
||||
|
||||
private static final byte PARAM_ENCODER_DIRECTIONS = 0;
|
||||
private static final byte PARAM_I2C_RECOVERY_MODE = 1;
|
||||
private static final byte PARAM_CHANNEL_BANK_CONFIG = 2;
|
||||
private static final byte PARAM_CHANNEL_VEL_INTVL = 3;
|
||||
private static final byte PARAM_CHANNEL_PULSE_WIDTH_MIN_MAX = 4;
|
||||
|
||||
private byte directionRegisterData = 0;
|
||||
|
||||
private boolean isInitialized = false;
|
||||
|
||||
public class OctoQuadException extends RuntimeException
|
||||
{
|
||||
public OctoQuadException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public OctoQuadImpl(I2cDeviceSynch deviceClient)
|
||||
{
|
||||
super(deviceClient, true);
|
||||
|
||||
this.deviceClient.setI2cAddress(I2cAddr.create7bit(I2C_ADDRESS));
|
||||
super.registerArmingStateCallback(false);
|
||||
this.deviceClient.engage();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doInitialize()
|
||||
{
|
||||
//((LynxI2cDeviceSynch) deviceClient).setBusSpeed(LynxI2cDeviceSynch.BusSpeed.FAST_400K);
|
||||
isInitialized = false;
|
||||
verifyInitialization();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manufacturer getManufacturer()
|
||||
{
|
||||
return Manufacturer.Other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceName()
|
||||
{
|
||||
return "OctoQuadFTC";
|
||||
}
|
||||
|
||||
enum RegisterType
|
||||
{
|
||||
uint8_t(1),
|
||||
int32_t(4),
|
||||
int16_t(2);
|
||||
|
||||
public final int length;
|
||||
|
||||
RegisterType(int length)
|
||||
{
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
|
||||
enum Register
|
||||
{
|
||||
CHIP_ID (0x00, RegisterType.uint8_t),
|
||||
FIRMWARE_VERSION_MAJOR (0x01, RegisterType.uint8_t),
|
||||
FIRMWARE_VERSION_MINOR (0x02, RegisterType.uint8_t),
|
||||
FIRMWARE_VERSION_ENGINEERING (0x03, RegisterType.uint8_t),
|
||||
COMMAND (0x04, RegisterType.uint8_t),
|
||||
COMMAND_DAT_0 (0x05, RegisterType.uint8_t),
|
||||
COMMAND_DAT_1 (0x06, RegisterType.uint8_t),
|
||||
COMMAND_DAT_2 (0x07, RegisterType.uint8_t),
|
||||
COMMAND_DAT_3 (0x08, RegisterType.uint8_t),
|
||||
COMMAND_DAT_4 (0x09, RegisterType.uint8_t),
|
||||
COMMAND_DAT_5 (0x0A, RegisterType.uint8_t),
|
||||
COMMAND_DAT_6 (0x0B, RegisterType.uint8_t),
|
||||
|
||||
ENCODER_0_POSITION (0x0C, RegisterType.int32_t),
|
||||
ENCODER_1_POSITION (0x10, RegisterType.int32_t),
|
||||
ENCODER_2_POSITION (0x14, RegisterType.int32_t),
|
||||
ENCODER_3_POSITION (0x18, RegisterType.int32_t),
|
||||
ENCODER_4_POSITION (0x1C, RegisterType.int32_t),
|
||||
ENCODER_5_POSITION (0x20, RegisterType.int32_t),
|
||||
ENCODER_6_POSITION (0x24, RegisterType.int32_t),
|
||||
ENCODER_7_POSITION (0x28, RegisterType.int32_t),
|
||||
|
||||
ENCODER_0_VELOCITY (0x2C, RegisterType.int16_t),
|
||||
ENCODER_1_VELOCITY (0x2E, RegisterType.int16_t),
|
||||
ENCODER_2_VELOCITY (0x30, RegisterType.int16_t),
|
||||
ENCODER_3_VELOCITY (0x32, RegisterType.int16_t),
|
||||
ENCODER_4_VELOCITY (0x34, RegisterType.int16_t),
|
||||
ENCODER_5_VELOCITY (0x36, RegisterType.int16_t),
|
||||
ENCODER_6_VELOCITY (0x38, RegisterType.int16_t),
|
||||
ENCODER_7_VELOCITY (0x3A, RegisterType.int16_t);
|
||||
|
||||
public final byte addr;
|
||||
public final int length;
|
||||
|
||||
Register(int addr, RegisterType type)
|
||||
{
|
||||
this.addr = (byte) addr;
|
||||
this.length = type.length;
|
||||
}
|
||||
|
||||
public static final Register[] all = Register.values();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------------
|
||||
// PUBLIC OCTOQUAD API
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public byte getChipId()
|
||||
{
|
||||
return readRegister(Register.CHIP_ID)[0];
|
||||
}
|
||||
|
||||
public FirmwareVersion getFirmwareVersion()
|
||||
{
|
||||
byte[] fw = readContiguousRegisters(Register.FIRMWARE_VERSION_MAJOR, Register.FIRMWARE_VERSION_ENGINEERING);
|
||||
|
||||
int maj = fw[0] & 0xFF;
|
||||
int min = fw[1] & 0xFF;
|
||||
int eng = fw[2] & 0xFF;
|
||||
|
||||
return new FirmwareVersion(maj, min, eng);
|
||||
}
|
||||
|
||||
public String getFirmwareVersionString()
|
||||
{
|
||||
return getFirmwareVersion().toString();
|
||||
}
|
||||
|
||||
public int readSinglePosition(int idx)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
Register register = Register.all[Register.ENCODER_0_POSITION.ordinal()+idx];
|
||||
return intFromBytes(readRegister(register));
|
||||
}
|
||||
|
||||
public void readAllPositions(int[] out)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
if(out.length != NUM_ENCODERS)
|
||||
{
|
||||
throw new IllegalArgumentException("out.length != 8");
|
||||
}
|
||||
|
||||
byte[] bytes = readContiguousRegisters(Register.ENCODER_0_POSITION, Register.ENCODER_7_POSITION);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.order(OCTOQUAD_ENDIAN);
|
||||
|
||||
for(int i = 0; i < NUM_ENCODERS; i++)
|
||||
{
|
||||
out[i] = buffer.getInt();
|
||||
}
|
||||
}
|
||||
|
||||
public int[] readAllPositions()
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
int[] block = new int[NUM_ENCODERS];
|
||||
readAllPositions(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
public int[] readPositionRange(int idxFirst, int idxLast)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idxFirst, ENCODER_FIRST, ENCODER_LAST);
|
||||
Range.throwIfRangeIsInvalid(idxLast, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
Register registerFirst = Register.all[Register.ENCODER_0_POSITION.ordinal()+idxFirst];
|
||||
Register registerLast = Register.all[Register.ENCODER_0_POSITION.ordinal()+idxLast];
|
||||
|
||||
byte[] data = readContiguousRegisters(registerFirst, registerLast);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
int numEncodersRead = idxLast-idxFirst+1;
|
||||
int[] encoderCounts = new int[numEncodersRead];
|
||||
|
||||
for(int i = 0; i < numEncodersRead; i++)
|
||||
{
|
||||
encoderCounts[i] = buffer.getInt();
|
||||
}
|
||||
|
||||
return encoderCounts;
|
||||
}
|
||||
|
||||
// ALSO USED BY CACHING API !
|
||||
public void resetSinglePosition(int idx)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
byte dat = (byte) (1 << idx);
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_0, new byte[]{CMD_RESET_ENCODERS, dat});
|
||||
|
||||
if (cachingMode == CachingMode.AUTO)
|
||||
{
|
||||
refreshCache();
|
||||
}
|
||||
}
|
||||
|
||||
// ALSO USED BY CACHING API !
|
||||
public void resetAllPositions()
|
||||
{
|
||||
verifyInitialization();
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_0, new byte[] {CMD_RESET_ENCODERS, (byte)0xFF});
|
||||
|
||||
if (cachingMode == CachingMode.AUTO)
|
||||
{
|
||||
refreshCache();
|
||||
}
|
||||
}
|
||||
|
||||
public void resetMultiplePositions(boolean[] resets)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
if(resets.length != NUM_ENCODERS)
|
||||
{
|
||||
throw new IllegalArgumentException("resets.length != 8");
|
||||
}
|
||||
|
||||
byte dat = 0;
|
||||
|
||||
for(int i = ENCODER_FIRST; i <= ENCODER_LAST; i++)
|
||||
{
|
||||
dat |= resets[i] ? (byte)(1 << i) : 0;
|
||||
}
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_0, new byte[] {CMD_RESET_ENCODERS, dat});
|
||||
}
|
||||
|
||||
public void resetMultiplePositions(int... indices)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
for(int idx : indices)
|
||||
{
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
}
|
||||
|
||||
byte dat = 0;
|
||||
|
||||
for(int idx : indices)
|
||||
{
|
||||
dat |= 1 << idx;
|
||||
}
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_0, new byte[] {CMD_RESET_ENCODERS, dat});
|
||||
}
|
||||
|
||||
public void setSingleEncoderDirection(int idx, EncoderDirection direction)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
if(direction == EncoderDirection.REVERSE)
|
||||
{
|
||||
directionRegisterData |= (byte) (1 << idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
directionRegisterData &= (byte) ~(1 << idx);
|
||||
}
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_1, new byte[]{CMD_SET_PARAM, PARAM_ENCODER_DIRECTIONS, directionRegisterData});
|
||||
}
|
||||
|
||||
public EncoderDirection getSingleEncoderDirection(int idx)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_0, new byte[]{CMD_READ_PARAM, PARAM_ENCODER_DIRECTIONS});
|
||||
byte directions = readRegister(Register.COMMAND_DAT_0)[0];
|
||||
|
||||
boolean reversed = (directions & (1 << idx)) != 0;
|
||||
return reversed ? EncoderDirection.REVERSE : EncoderDirection.FORWARD;
|
||||
}
|
||||
|
||||
public void setAllEncoderDirections(boolean[] reverse)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
if(reverse.length != NUM_ENCODERS)
|
||||
{
|
||||
throw new IllegalArgumentException("reverse.length != 8");
|
||||
}
|
||||
|
||||
directionRegisterData = 0;
|
||||
|
||||
for(int i = ENCODER_FIRST; i <= ENCODER_LAST; i++)
|
||||
{
|
||||
if(reverse[i])
|
||||
{
|
||||
directionRegisterData |= (byte) (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_1, new byte[]{CMD_SET_PARAM, PARAM_ENCODER_DIRECTIONS, directionRegisterData});
|
||||
}
|
||||
|
||||
public short readSingleVelocity(int idx)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
Register register = Register.all[Register.ENCODER_0_VELOCITY.ordinal()+idx];
|
||||
return shortFromBytes(readRegister(register));
|
||||
}
|
||||
|
||||
public void readAllVelocities(short[] out)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
if(out.length != NUM_ENCODERS)
|
||||
{
|
||||
throw new IllegalArgumentException("out.length != 8");
|
||||
}
|
||||
|
||||
byte[] bytes = readContiguousRegisters(Register.ENCODER_0_VELOCITY, Register.ENCODER_7_VELOCITY);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.order(OCTOQUAD_ENDIAN);
|
||||
|
||||
for(int i = 0; i < NUM_ENCODERS; i++)
|
||||
{
|
||||
out[i] = buffer.getShort();
|
||||
}
|
||||
}
|
||||
|
||||
public short[] readAllVelocities()
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
short[] block = new short[NUM_ENCODERS];
|
||||
readAllVelocities(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
public short[] readVelocityRange(int idxFirst, int idxLast)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idxFirst, ENCODER_FIRST, ENCODER_LAST);
|
||||
Range.throwIfRangeIsInvalid(idxLast, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
Register registerFirst = Register.all[Register.ENCODER_0_VELOCITY.ordinal()+idxFirst];
|
||||
Register registerLast = Register.all[Register.ENCODER_0_VELOCITY.ordinal()+idxLast];
|
||||
|
||||
byte[] data = readContiguousRegisters(registerFirst, registerLast);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
int numVelocitiesRead = idxLast-idxFirst+1;
|
||||
short[] velocities = new short[numVelocitiesRead];
|
||||
|
||||
for(int i = 0; i < numVelocitiesRead; i++)
|
||||
{
|
||||
velocities[i] = buffer.getShort();
|
||||
}
|
||||
|
||||
return velocities;
|
||||
}
|
||||
|
||||
public void readAllEncoderData(EncoderDataBlock out)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
if(out.positions.length != NUM_ENCODERS)
|
||||
{
|
||||
throw new IllegalArgumentException("out.counts.length != 8");
|
||||
}
|
||||
|
||||
if(out.velocities.length != NUM_ENCODERS)
|
||||
{
|
||||
throw new IllegalArgumentException("out.velocities.length != 8");
|
||||
}
|
||||
|
||||
byte[] bytes = readContiguousRegisters(Register.ENCODER_0_POSITION, Register.ENCODER_7_VELOCITY);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.order(OCTOQUAD_ENDIAN);
|
||||
|
||||
for(int i = 0; i < NUM_ENCODERS; i++)
|
||||
{
|
||||
out.positions[i] = buffer.getInt();
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_ENCODERS; i++)
|
||||
{
|
||||
out.velocities[i] = buffer.getShort();
|
||||
}
|
||||
}
|
||||
|
||||
public EncoderDataBlock readAllEncoderData()
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
EncoderDataBlock block = new EncoderDataBlock();
|
||||
readAllEncoderData(block);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
public void setSingleVelocitySampleInterval(int idx, int intvlms)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
Range.throwIfRangeIsInvalid(intvlms, MIN_VELOCITY_MEASUREMENT_INTERVAL_MS, MAX_VELOCITY_MEASUREMENT_INTERVAL_MS);
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_2, new byte[]{CMD_SET_PARAM, PARAM_CHANNEL_VEL_INTVL, (byte)idx, (byte)intvlms});
|
||||
}
|
||||
|
||||
public void setAllVelocitySampleIntervals(int intvlms)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(intvlms, MIN_VELOCITY_MEASUREMENT_INTERVAL_MS, MAX_VELOCITY_MEASUREMENT_INTERVAL_MS);
|
||||
|
||||
for(int i = ENCODER_FIRST; i <= ENCODER_LAST; i++)
|
||||
{
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_2, new byte[]{CMD_SET_PARAM, PARAM_CHANNEL_VEL_INTVL, (byte)i, (byte)intvlms});
|
||||
}
|
||||
}
|
||||
|
||||
public void setAllVelocitySampleIntervals(int[] intvlms)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
if(intvlms.length != NUM_ENCODERS)
|
||||
{
|
||||
throw new IllegalArgumentException("intvls.length != 8");
|
||||
}
|
||||
|
||||
for(int i : intvlms)
|
||||
{
|
||||
Range.throwIfRangeIsInvalid(i, MIN_VELOCITY_MEASUREMENT_INTERVAL_MS, MAX_VELOCITY_MEASUREMENT_INTERVAL_MS);
|
||||
}
|
||||
|
||||
for(int i = ENCODER_FIRST; i <= ENCODER_LAST; i++)
|
||||
{
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_2, new byte[]{CMD_SET_PARAM, PARAM_CHANNEL_VEL_INTVL, (byte)i, (byte)intvlms[i]});
|
||||
}
|
||||
}
|
||||
|
||||
public int getSingleVelocitySampleInterval(int idx)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_1, new byte[]{CMD_READ_PARAM, PARAM_CHANNEL_VEL_INTVL, (byte)idx});
|
||||
byte ms = readRegister(Register.COMMAND_DAT_0)[0];
|
||||
return ms & 0xFF;
|
||||
}
|
||||
|
||||
public int[] getAllVelocitySampleIntervals()
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
int[] ret = new int[NUM_ENCODERS];
|
||||
|
||||
for(int i = ENCODER_FIRST; i <= ENCODER_FIRST; i++)
|
||||
{
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_1, new byte[]{CMD_READ_PARAM, PARAM_CHANNEL_VEL_INTVL, (byte)i});
|
||||
byte ms = readRegister(Register.COMMAND_DAT_0)[0];
|
||||
ret[i] = ms & 0xFF;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setSingleChannelPulseWidthParams(int idx, int min, int max)
|
||||
{
|
||||
setSingleChannelPulseWidthParams(idx, new ChannelPulseWidthParams(min, max));
|
||||
}
|
||||
|
||||
public void setSingleChannelPulseWidthParams(int idx, ChannelPulseWidthParams params)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
Range.throwIfRangeIsInvalid(params.min_length_us, MIN_PULSE_WIDTH_LENGTH_µS, MAX_PULSE_WIDTH_LENGTH_µS);
|
||||
Range.throwIfRangeIsInvalid(params.max_length_us, MIN_PULSE_WIDTH_LENGTH_µS, MAX_PULSE_WIDTH_LENGTH_µS);
|
||||
|
||||
if(params.max_length_us <= params.min_length_us)
|
||||
{
|
||||
throw new RuntimeException("params.max_length_us <= params.min_length_us");
|
||||
}
|
||||
|
||||
ByteBuffer outgoing = ByteBuffer.allocate(7);
|
||||
outgoing.order(OCTOQUAD_ENDIAN);
|
||||
outgoing.put(CMD_SET_PARAM);
|
||||
outgoing.put(PARAM_CHANNEL_PULSE_WIDTH_MIN_MAX);
|
||||
outgoing.put((byte)idx);
|
||||
outgoing.putShort((short)params.min_length_us);
|
||||
outgoing.putShort((short)params.max_length_us);
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_5, outgoing.array());
|
||||
}
|
||||
|
||||
public ChannelPulseWidthParams getSingleChannelPulseWidthParams(int idx)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
Range.throwIfRangeIsInvalid(idx, ENCODER_FIRST, ENCODER_LAST);
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_1, new byte[]{CMD_READ_PARAM, PARAM_CHANNEL_PULSE_WIDTH_MIN_MAX, (byte)idx});
|
||||
byte[] result = readContiguousRegisters(Register.COMMAND_DAT_0, Register.COMMAND_DAT_3);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(result);
|
||||
buffer.order(OCTOQUAD_ENDIAN);
|
||||
|
||||
ChannelPulseWidthParams params = new ChannelPulseWidthParams();
|
||||
params.min_length_us = buffer.getShort() & 0xFFFF;
|
||||
params.max_length_us = buffer.getShort() & 0xFFFF;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
public void resetEverything()
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
writeRegister(Register.COMMAND, new byte[]{CMD_RESET_EVERYTHING});
|
||||
}
|
||||
|
||||
public void setChannelBankConfig(ChannelBankConfig config)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_1, new byte[]{CMD_SET_PARAM, PARAM_CHANNEL_BANK_CONFIG, config.bVal});
|
||||
}
|
||||
|
||||
public ChannelBankConfig getChannelBankConfig()
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_0, new byte[]{CMD_READ_PARAM, PARAM_CHANNEL_BANK_CONFIG});
|
||||
byte result = readRegister(Register.COMMAND_DAT_0)[0];
|
||||
|
||||
for(ChannelBankConfig c : ChannelBankConfig.values())
|
||||
{
|
||||
if(c.bVal == result)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
return ChannelBankConfig.ALL_QUADRATURE;
|
||||
}
|
||||
|
||||
public void setI2cRecoveryMode(I2cRecoveryMode mode)
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_1, new byte[]{CMD_SET_PARAM, PARAM_I2C_RECOVERY_MODE, mode.bVal});
|
||||
}
|
||||
|
||||
public I2cRecoveryMode getI2cRecoveryMode()
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
writeContiguousRegisters(Register.COMMAND, Register.COMMAND_DAT_0, new byte[]{CMD_READ_PARAM, PARAM_I2C_RECOVERY_MODE});
|
||||
byte result = readRegister(Register.COMMAND_DAT_0)[0];
|
||||
|
||||
for(I2cRecoveryMode m : I2cRecoveryMode.values())
|
||||
{
|
||||
if(m.bVal == result)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
return I2cRecoveryMode.NONE;
|
||||
}
|
||||
|
||||
public void saveParametersToFlash()
|
||||
{
|
||||
verifyInitialization();
|
||||
|
||||
writeRegister(Register.COMMAND, new byte[] {CMD_WRITE_PARAMS_TO_FLASH});
|
||||
try
|
||||
{
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------------
|
||||
// PUBLIC CACHING OCTOQUAD API
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
protected CachingMode cachingMode = CachingMode.AUTO;
|
||||
protected EncoderDataBlock cachedData = new EncoderDataBlock();
|
||||
protected boolean[] posHasBeenRead = new boolean[NUM_ENCODERS];
|
||||
protected boolean[] velHasBeenRead = new boolean[NUM_ENCODERS];
|
||||
|
||||
public void setCachingMode(CachingMode mode)
|
||||
{
|
||||
this.cachingMode = mode;
|
||||
if (cachingMode != CachingMode.NONE)
|
||||
{
|
||||
refreshCache();
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshCache()
|
||||
{
|
||||
readAllEncoderData(cachedData);
|
||||
Arrays.fill(posHasBeenRead, false);
|
||||
Arrays.fill(velHasBeenRead, false);
|
||||
}
|
||||
|
||||
public int readSinglePosition_Caching(int idx)
|
||||
{
|
||||
// If we're caching we're gonna want to read from the cache
|
||||
if (cachingMode == CachingMode.AUTO || cachingMode == CachingMode.MANUAL)
|
||||
{
|
||||
// Update cache if this is the 2nd read
|
||||
if (cachingMode == CachingMode.AUTO && posHasBeenRead[idx])
|
||||
{
|
||||
refreshCache();
|
||||
}
|
||||
|
||||
posHasBeenRead[idx] = true;
|
||||
return cachedData.positions[idx];
|
||||
}
|
||||
// Not caching; read direct
|
||||
else
|
||||
{
|
||||
return readSinglePosition(idx);
|
||||
}
|
||||
}
|
||||
|
||||
public short readSingleVelocity_Caching(int idx)
|
||||
{
|
||||
// If we're caching we're gonna want to read from the cache
|
||||
if (cachingMode == CachingMode.AUTO || cachingMode == CachingMode.MANUAL)
|
||||
{
|
||||
// Update cache if this is the 2nd read
|
||||
if (cachingMode == CachingMode.AUTO && velHasBeenRead[idx])
|
||||
{
|
||||
refreshCache();
|
||||
}
|
||||
|
||||
velHasBeenRead[idx] = true;
|
||||
return cachedData.velocities[idx];
|
||||
}
|
||||
// Not caching; read direct
|
||||
else
|
||||
{
|
||||
return readSingleVelocity(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------------
|
||||
// INTERNAL
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private void verifyInitialization()
|
||||
{
|
||||
if(!isInitialized)
|
||||
{
|
||||
byte chipId = getChipId();
|
||||
if(chipId != OCTOQUAD_CHIP_ID)
|
||||
{
|
||||
RobotLog.addGlobalWarningMessage("OctoQuad does not report correct CHIP_ID value; (got 0x%X; expected 0x%X) this likely indicates I2C comms are not working", chipId, OCTOQUAD_CHIP_ID);
|
||||
}
|
||||
|
||||
FirmwareVersion fw = getFirmwareVersion();
|
||||
|
||||
if(fw.maj != SUPPORTED_FW_VERSION_MAJ)
|
||||
{
|
||||
RobotLog.addGlobalWarningMessage("OctoQuad is running a different major firmware version than this driver was built for (current=%d; expected=%d) IT IS HIGHLY LIKELY THAT NOTHING WILL WORK!", fw.maj, SUPPORTED_FW_VERSION_MAJ);
|
||||
}
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static int intFromBytes(byte[] bytes)
|
||||
{
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
byteBuffer.order(OCTOQUAD_ENDIAN);
|
||||
return byteBuffer.getInt();
|
||||
}
|
||||
|
||||
private static short shortFromBytes(byte[] bytes)
|
||||
{
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
byteBuffer.order(OCTOQUAD_ENDIAN);
|
||||
return byteBuffer.getShort();
|
||||
}
|
||||
|
||||
private byte[] readRegister(Register reg)
|
||||
{
|
||||
return deviceClient.read(reg.addr, reg.length);
|
||||
}
|
||||
|
||||
private byte[] readContiguousRegisters(Register first, Register last)
|
||||
{
|
||||
int addrStart = first.addr;
|
||||
int addrEnd = last.addr + last.length;
|
||||
int bytesToRead = addrEnd-addrStart;
|
||||
|
||||
return deviceClient.read(addrStart, bytesToRead);
|
||||
}
|
||||
|
||||
private void writeRegister(Register reg, byte[] bytes)
|
||||
{
|
||||
if(reg.length != bytes.length)
|
||||
{
|
||||
throw new IllegalArgumentException("reg.length != bytes.length");
|
||||
}
|
||||
|
||||
deviceClient.write(reg.addr, bytes);
|
||||
}
|
||||
|
||||
private void writeContiguousRegisters(Register first, Register last, byte[] dat)
|
||||
{
|
||||
int addrStart = first.addr;
|
||||
int addrEnd = last.addr + last.length;
|
||||
int bytesToWrite = addrEnd-addrStart;
|
||||
|
||||
if(bytesToWrite != dat.length)
|
||||
{
|
||||
throw new IllegalArgumentException("bytesToWrite != dat.length");
|
||||
}
|
||||
|
||||
deviceClient.write(addrStart, dat);
|
||||
}
|
||||
}
|
||||
|
Submodule TeamCode/src/main/java/ftclib updated: ff5b5322d3...f1b523ca30
Reference in New Issue
Block a user