Switches DigitalPWM to Handles (#121)

This commit is contained in:
Thad House
2016-06-30 23:43:00 -07:00
committed by Peter Johnson
parent f77a976fbb
commit 47694ef810
12 changed files with 169 additions and 137 deletions

View File

@@ -16,11 +16,13 @@ HalDigitalHandle initializeDIOPort(HalPortHandle port_handle, uint8_t input,
int32_t* status);
void freeDIOPort(HalDigitalHandle dio_port_handle);
void* allocatePWM(int32_t* status);
void freePWM(void* pwmGenerator, int32_t* status);
void setPWMRate(double rate, int32_t* status);
void setPWMDutyCycle(void* pwmGenerator, double dutyCycle, int32_t* status);
void setPWMOutputChannel(void* pwmGenerator, uint32_t pin, int32_t* status);
HalDigitalPWMHandle allocateDigitalPWM(int32_t* status);
void freeDigitalPWM(HalDigitalPWMHandle pwmGenerator, int32_t* status);
void setDigitalPWMRate(double rate, int32_t* status);
void setDigitalPWMDutyCycle(HalDigitalPWMHandle pwmGenerator, double dutyCycle,
int32_t* status);
void setDigitalPWMOutputChannel(HalDigitalPWMHandle pwmGenerator, uint32_t pin,
int32_t* status);
void setDIO(HalDigitalHandle dio_port_handle, short value, int32_t* status);
bool getDIO(HalDigitalHandle dio_port_handle, int32_t* status);

View File

@@ -28,3 +28,5 @@ typedef HalHandle HalAnalogTriggerHandle;
typedef HalHandle HalRelayHandle;
typedef HalHandle HalDigitalHandle;
typedef HalHandle HalDigitalPWMHandle;

View File

@@ -11,6 +11,7 @@
#include "DigitalInternal.h"
#include "handles/HandlesInternal.h"
#include "handles/LimitedHandleResource.h"
static_assert(sizeof(uint32_t) <= sizeof(void*),
"This file shoves uint32_ts into pointers.");
@@ -20,6 +21,12 @@ using namespace hal;
// Create a mutex to protect changes to the digital output values
static priority_recursive_mutex digitalDIOMutex;
static LimitedHandleResource<HalDigitalPWMHandle, uint8_t,
tDIO::kNumPWMDutyCycleAElements +
tDIO::kNumPWMDutyCycleBElements,
HalHandleEnum::DigitalPWM>
digitalPWMHandles;
extern "C" {
/**
@@ -94,22 +101,33 @@ void freeDIOPort(HalDigitalHandle dio_port_handle) {
* Allocate a DO PWM Generator.
* Allocate PWM generators so that they are not accidentally reused.
*
* @return PWM Generator refnum
* @return PWM Generator handle
*/
void* allocatePWM(int32_t* status) {
return (void*)DO_PWMGenerators->Allocate("DO_PWM");
HalDigitalPWMHandle allocateDigitalPWM(int32_t* status) {
auto handle = digitalPWMHandles.Allocate();
if (handle == HAL_INVALID_HANDLE) {
*status = NO_AVAILABLE_RESOURCES;
return HAL_INVALID_HANDLE;
}
auto id = digitalPWMHandles.Get(handle);
if (id == nullptr) { // would only occur on thread issue.
*status = PARAMETER_OUT_OF_RANGE;
return HAL_INVALID_HANDLE;
}
*id = static_cast<uint8_t>(getHandleIndex(handle));
return handle;
}
/**
* Free the resource associated with a DO PWM generator.
*
* @param pwmGenerator The pwmGen to free that was allocated with
* AllocateDO_PWM()
* allocateDigitalPWM()
*/
void freePWM(void* pwmGenerator, int32_t* status) {
uint32_t id = (uint32_t)pwmGenerator;
if (id == ~0ul) return;
DO_PWMGenerators->Free(id);
void freeDigitalPWM(HalDigitalPWMHandle pwmGenerator, int32_t* status) {
digitalPWMHandles.Free(pwmGenerator);
}
/**
@@ -120,7 +138,7 @@ void freePWM(void* pwmGenerator, int32_t* status) {
*
* @param rate The frequency to output all digital output PWM signals.
*/
void setPWMRate(double rate, int32_t* status) {
void setDigitalPWMRate(double rate, int32_t* status) {
// Currently rounding in the log rate domain... heavy weight toward picking a
// higher freq.
// TODO: Round in the linear rate domain.
@@ -134,12 +152,17 @@ void setPWMRate(double rate, int32_t* status) {
/**
* Configure the duty-cycle of the PWM generator
*
* @param pwmGenerator The generator index reserved by AllocateDO_PWM()
* @param pwmGenerator The generator index reserved by allocateDigitalPWM()
* @param dutyCycle The percent duty cycle to output [0..1].
*/
void setPWMDutyCycle(void* pwmGenerator, double dutyCycle, int32_t* status) {
uint32_t id = (uint32_t)pwmGenerator;
if (id == ~0ul) return;
void setDigitalPWMDutyCycle(HalDigitalPWMHandle pwmGenerator, double dutyCycle,
int32_t* status) {
auto port = digitalPWMHandles.Get(pwmGenerator);
if (port == nullptr) {
*status = PARAMETER_OUT_OF_RANGE;
return;
}
uint32_t id = *port;
if (dutyCycle > 1.0) dutyCycle = 1.0;
if (dutyCycle < 0.0) dutyCycle = 0.0;
float rawDutyCycle = 256.0 * dutyCycle;
@@ -162,12 +185,17 @@ void setPWMDutyCycle(void* pwmGenerator, double dutyCycle, int32_t* status) {
/**
* Configure which DO channel the PWM signal is output on
*
* @param pwmGenerator The generator index reserved by AllocateDO_PWM()
* @param pwmGenerator The generator index reserved by allocateDigitalPWM()
* @param channel The Digital Output channel to output on
*/
void setPWMOutputChannel(void* pwmGenerator, uint32_t pin, int32_t* status) {
uint32_t id = (uint32_t)pwmGenerator;
if (id > 5) return;
void setDigitalPWMOutputChannel(HalDigitalPWMHandle pwmGenerator, uint32_t pin,
int32_t* status) {
auto port = digitalPWMHandles.Get(pwmGenerator);
if (port == nullptr) {
*status = PARAMETER_OUT_OF_RANGE;
return;
}
uint32_t id = *port;
if (pin >= kNumHeaders) { // if it is on the MXP
pin += kMXPDigitalPWMOffset; // then to write as a digital PWM pin requires
// an offset to write on the correct pin

View File

@@ -60,7 +60,6 @@ extern tDIO* digitalSystem;
extern tRelay* relaySystem;
extern tPWM* pwmSystem;
extern hal::Resource* DIOChannels;
extern hal::Resource* DO_PWMGenerators;
extern hal::Resource* PWMChannels;
extern bool digitalSystemsInitialized;

View File

@@ -35,7 +35,8 @@ enum class HalHandleEnum {
AnalogInput = 6,
AnalogTrigger = 7,
Relay = 8,
PWM = 9
PWM = 9,
DigitalPWM = 10
};
static inline int16_t getHandleIndex(HalHandle handle) {

View File

@@ -10,6 +10,7 @@
#include <memory>
#include "DigitalSource.h"
#include "HAL/Handles.h"
#include "LiveWindow/LiveWindowSendable.h"
#include "tables/ITableListener.h"
@@ -52,7 +53,7 @@ class DigitalOutput : public DigitalSource,
private:
uint32_t m_channel;
HalDigitalHandle m_handle;
void* m_pwmGenerator;
HalDigitalPWMHandle m_pwmGenerator;
std::shared_ptr<ITable> m_table;
};

View File

@@ -25,7 +25,7 @@
DigitalOutput::DigitalOutput(uint32_t channel) {
std::stringstream buf;
m_pwmGenerator = (void*)std::numeric_limits<uint32_t>::max();
m_pwmGenerator = HAL_INVALID_HANDLE;
if (!CheckDigitalChannel(channel)) {
buf << "Digital Channel " << channel;
wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, buf.str());
@@ -122,7 +122,7 @@ void DigitalOutput::SetPWMRate(float rate) {
if (StatusIsFatal()) return;
int32_t status = 0;
setPWMRate(rate, &status);
setDigitalPWMRate(rate, &status);
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
@@ -140,20 +140,20 @@ void DigitalOutput::SetPWMRate(float rate) {
* @param initialDutyCycle The duty-cycle to start generating. [0..1]
*/
void DigitalOutput::EnablePWM(float initialDutyCycle) {
if (m_pwmGenerator != (void*)std::numeric_limits<uint32_t>::max()) return;
if (m_pwmGenerator != HAL_INVALID_HANDLE) return;
int32_t status = 0;
if (StatusIsFatal()) return;
m_pwmGenerator = allocatePWM(&status);
m_pwmGenerator = allocateDigitalPWM(&status);
wpi_setErrorWithContext(status, getHALErrorMessage(status));
if (StatusIsFatal()) return;
setPWMDutyCycle(m_pwmGenerator, initialDutyCycle, &status);
setDigitalPWMDutyCycle(m_pwmGenerator, initialDutyCycle, &status);
wpi_setErrorWithContext(status, getHALErrorMessage(status));
if (StatusIsFatal()) return;
setPWMOutputChannel(m_pwmGenerator, m_channel, &status);
setDigitalPWMOutputChannel(m_pwmGenerator, m_channel, &status);
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
@@ -164,18 +164,18 @@ void DigitalOutput::EnablePWM(float initialDutyCycle) {
*/
void DigitalOutput::DisablePWM() {
if (StatusIsFatal()) return;
if (m_pwmGenerator == (void*)std::numeric_limits<uint32_t>::max()) return;
if (m_pwmGenerator == HAL_INVALID_HANDLE) return;
int32_t status = 0;
// Disable the output by routing to a dead bit.
setPWMOutputChannel(m_pwmGenerator, kDigitalChannels, &status);
setDigitalPWMOutputChannel(m_pwmGenerator, kDigitalChannels, &status);
wpi_setErrorWithContext(status, getHALErrorMessage(status));
freePWM(m_pwmGenerator, &status);
freeDigitalPWM(m_pwmGenerator, &status);
wpi_setErrorWithContext(status, getHALErrorMessage(status));
m_pwmGenerator = (void*)std::numeric_limits<uint32_t>::max();
m_pwmGenerator = HAL_INVALID_HANDLE;
}
/**
@@ -190,7 +190,7 @@ void DigitalOutput::UpdateDutyCycle(float dutyCycle) {
if (StatusIsFatal()) return;
int32_t status = 0;
setPWMDutyCycle(m_pwmGenerator, dutyCycle, &status);
setDigitalPWMDutyCycle(m_pwmGenerator, dutyCycle, &status);
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}

View File

@@ -173,4 +173,84 @@ Java_edu_wpi_first_wpilibj_hal_DIOJNI_getLoopTiming(JNIEnv *env, jclass) {
return returnValue;
}
/*
* Class: edu_wpi_first_wpilibj_hal_DIOJNI
* Method: allocateDigitalPWM
* Signature: ()I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_wpilibj_hal_DIOJNI_allocateDigitalPWM(JNIEnv* env, jclass) {
DIOJNI_LOG(logDEBUG) << "Calling DIOJNI allocateDigitalPWM";
int32_t status = 0;
auto pwm = allocateDigitalPWM(&status);
DIOJNI_LOG(logDEBUG) << "Status = " << status;
DIOJNI_LOG(logDEBUG) << "PWM Handle = " << pwm;
CheckStatus(env, status);
return (jint)pwm;
}
/*
* Class: edu_wpi_first_wpilibj_hal_DIOJNI
* Method: freeDigitalPWM
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_wpilibj_hal_DIOJNI_freeDigitalPWM(JNIEnv* env, jclass, jint id) {
DIOJNI_LOG(logDEBUG) << "Calling DIOJNI freeDigitalPWM";
DIOJNI_LOG(logDEBUG) << "PWM Handle = " << (HalDigitalPWMHandle)id;
int32_t status = 0;
freeDigitalPWM((HalDigitalPWMHandle)id, &status);
DIOJNI_LOG(logDEBUG) << "Status = " << status;
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_wpilibj_hal_DIOJNI
* Method: setDigitalPWMRate
* Signature: (D)V
*/
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_DIOJNI_setDigitalPWMRate(
JNIEnv* env, jclass, jdouble value) {
DIOJNI_LOG(logDEBUG) << "Calling DIOJNI setDigitalPWMRate";
DIOJNI_LOG(logDEBUG) << "Rate= " << value;
int32_t status = 0;
setDigitalPWMRate(value, &status);
DIOJNI_LOG(logDEBUG) << "Status = " << status;
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_wpilibj_hal_DIOJNI
* Method: setDigitalPWMDutyCycle
* Signature: (ID)V
*/
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_DIOJNI_setDigitalPWMDutyCycle(
JNIEnv* env, jclass, jint id, jdouble value) {
DIOJNI_LOG(logDEBUG) << "Calling DIOJNI setDigitalPWMDutyCycle";
DIOJNI_LOG(logDEBUG) << "PWM Handle = " << (HalDigitalPWMHandle)id;
DIOJNI_LOG(logDEBUG) << "DutyCycle= " << value;
int32_t status = 0;
setDigitalPWMDutyCycle((HalDigitalPWMHandle)id, value, &status);
DIOJNI_LOG(logDEBUG) << "Status = " << status;
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_wpilibj_hal_DIOJNI
* Method: setDigitalPWMOutputChannel
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_wpilibj_hal_DIOJNI_setDigitalPWMOutputChannel(
JNIEnv* env, jclass, jint id, jint value) {
DIOJNI_LOG(logDEBUG) << "Calling DIOJNI setDigitalPWMOutputChannel";
DIOJNI_LOG(logDEBUG) << "PWM Handle = " << (HalDigitalPWMHandle)id;
DIOJNI_LOG(logDEBUG) << "Pin= " << value;
int32_t status = 0;
setDigitalPWMOutputChannel((HalDigitalPWMHandle)id, (uint32_t)value, &status);
DIOJNI_LOG(logDEBUG) << "Status = " << status;
CheckStatus(env, status);
}
} // extern "C"

View File

@@ -118,83 +118,4 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_PWMJNI_setPWMPeriodScale(
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_wpilibj_hal_PWMJNI
* Method: allocatePWM
* Signature: ()J
*/
JNIEXPORT jlong JNICALL
Java_edu_wpi_first_wpilibj_hal_PWMJNI_allocatePWM(JNIEnv* env, jclass) {
PWMJNI_LOG(logDEBUG) << "Calling PWMJNI allocatePWM";
int32_t status = 0;
void* pwm = allocatePWM(&status);
PWMJNI_LOG(logDEBUG) << "Status = " << status;
PWMJNI_LOG(logDEBUG) << "PWM Ptr = " << pwm;
CheckStatus(env, status);
return (jlong)pwm;
}
/*
* Class: edu_wpi_first_wpilibj_hal_PWMJNI
* Method: freePWM
* Signature: (J)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_wpilibj_hal_PWMJNI_freePWM(JNIEnv* env, jclass, jlong id) {
PWMJNI_LOG(logDEBUG) << "Calling PWMJNI freePWM";
PWMJNI_LOG(logDEBUG) << "PWM Ptr = " << (void*)id;
int32_t status = 0;
freePWM((void*)id, &status);
PWMJNI_LOG(logDEBUG) << "Status = " << status;
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_wpilibj_hal_PWMJNI
* Method: setPWMRate
* Signature: (D)V
*/
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_PWMJNI_setPWMRate(
JNIEnv* env, jclass, jdouble value) {
PWMJNI_LOG(logDEBUG) << "Calling PWMJNI setPWMRate";
PWMJNI_LOG(logDEBUG) << "Rate= " << value;
int32_t status = 0;
setPWMRate(value, &status);
PWMJNI_LOG(logDEBUG) << "Status = " << status;
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_wpilibj_hal_PWMJNI
* Method: setPWMDutyCycle
* Signature: (JD)V
*/
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_PWMJNI_setPWMDutyCycle(
JNIEnv* env, jclass, jlong id, jdouble value) {
PWMJNI_LOG(logDEBUG) << "Calling PWMJNI setPWMDutyCycle";
PWMJNI_LOG(logDEBUG) << "PWM Ptr = " << (void*)id;
PWMJNI_LOG(logDEBUG) << "DutyCycle= " << value;
int32_t status = 0;
setPWMDutyCycle((void*)id, value, &status);
PWMJNI_LOG(logDEBUG) << "Status = " << status;
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_wpilibj_hal_PWMJNI
* Method: setPWMOutputChannel
* Signature: (JI)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_wpilibj_hal_PWMJNI_setPWMOutputChannel(
JNIEnv* env, jclass, jlong id, jint value) {
PWMJNI_LOG(logDEBUG) << "Calling PWMJNI setPWMOutputChannel";
PWMJNI_LOG(logDEBUG) << "PWM Ptr = " << (void*)id;
PWMJNI_LOG(logDEBUG) << "Pin= " << value;
int32_t status = 0;
setPWMOutputChannel((void*)id, (uint32_t)value, &status);
PWMJNI_LOG(logDEBUG) << "Status = " << status;
CheckStatus(env, status);
}
} // extern "C"

View File

@@ -10,7 +10,6 @@ package edu.wpi.first.wpilibj;
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.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.tables.ITable;
import edu.wpi.first.wpilibj.tables.ITableListener;
@@ -21,10 +20,9 @@ import edu.wpi.first.wpilibj.tables.ITableListener;
*/
public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
private static final long invalidPwmGenerator = 0xffffffff;
private static final int invalidPwmGenerator = 0;
private int m_pwmGenerator = invalidPwmGenerator;
private long m_pwmGenerator = invalidPwmGenerator;
private int m_channel = 0;
private int m_handle = 0;
@@ -118,7 +116,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
* @param rate The frequency to output all digital output PWM signals.
*/
public void setPWMRate(double rate) {
PWMJNI.setPWMRate(rate);
DIOJNI.setDigitalPWMRate(rate);
}
/**
@@ -137,9 +135,9 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
if (m_pwmGenerator != invalidPwmGenerator) {
return;
}
m_pwmGenerator = PWMJNI.allocatePWM();
PWMJNI.setPWMDutyCycle(m_pwmGenerator, initialDutyCycle);
PWMJNI.setPWMOutputChannel(m_pwmGenerator, m_channel);
m_pwmGenerator = DIOJNI.allocateDigitalPWM();
DIOJNI.setDigitalPWMDutyCycle(m_pwmGenerator, initialDutyCycle);
DIOJNI.setDigitalPWMOutputChannel(m_pwmGenerator, m_channel);
}
/**
@@ -152,9 +150,9 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
return;
}
// Disable the output by routing to a dead bit.
PWMJNI.setPWMOutputChannel(m_pwmGenerator, kDigitalChannels);
PWMJNI.freePWM(m_pwmGenerator);
m_pwmGenerator = 0;
DIOJNI.setDigitalPWMOutputChannel(m_pwmGenerator, kDigitalChannels);
DIOJNI.freeDigitalPWM(m_pwmGenerator);
m_pwmGenerator = invalidPwmGenerator;
}
/**
@@ -170,7 +168,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
if (m_pwmGenerator == invalidPwmGenerator) {
return;
}
PWMJNI.setPWMDutyCycle(m_pwmGenerator, dutyCycle);
DIOJNI.setDigitalPWMDutyCycle(m_pwmGenerator, dutyCycle);
}
/**

View File

@@ -26,4 +26,14 @@ public class DIOJNI extends JNIWrapper {
public static native boolean isAnyPulsing();
public static native short getLoopTiming();
public static native int allocateDigitalPWM();
public static native void freeDigitalPWM(int pwmGenerator);
public static native void setDigitalPWMRate(double rate);
public static native void setDigitalPWMDutyCycle(int pwmGenerator, double dutyCycle);
public static native void setDigitalPWMOutputChannel(int pwmGenerator, int pin);
}

View File

@@ -20,14 +20,4 @@ public class PWMJNI extends DIOJNI {
public static native void latchPWMZero(int pwmPortHandle);
public static native void setPWMPeriodScale(int pwmPortHandle, int squelchMask);
public static native long allocatePWM();
public static native void freePWM(long pwmGenerator);
public static native void setPWMRate(double rate);
public static native void setPWMDutyCycle(long pwmGenerator, double dutyCycle);
public static native void setPWMOutputChannel(long pwmGenerator, int pin);
}