Skip to content

Commit

Permalink
[hal] Digital IO SystemCore implementation (#7621)
Browse files Browse the repository at this point in the history
  • Loading branch information
ThadHouse authored Jan 13, 2025
1 parent 03d9e96 commit 666d163
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 31 deletions.
8 changes: 7 additions & 1 deletion developerRobot/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,18 @@ deploy {
directory = '/home/systemcore'
maxChannels = 4
locations {
ssh(SshDeployLocation) {
mdns(SshDeployLocation) {
address = "limelight.local"
user = 'systemcore'
password = 'systemcore'
ipv6 = false
}
usb(SshDeployLocation) {
address = "172.28.0.1"
user = 'systemcore'
password = 'systemcore'
ipv6 = false
}
}

timeout = 7
Expand Down
109 changes: 97 additions & 12 deletions hal/src/main/native/systemcore/DIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "HALInitializer.h"
#include "HALInternal.h"
#include "PortsInternal.h"
#include "SmartIo.h"
#include "hal/Errors.h"
#include "hal/cpp/fpga_clock.h"
#include "hal/handles/HandlesInternal.h"
Expand All @@ -29,15 +30,69 @@ HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();
*status = HAL_HANDLE_ERROR;
return HAL_kInvalidHandle;

int16_t channel = getPortHandleChannel(portHandle);
if (channel == InvalidHandleIndex || channel >= kNumSmartIo) {
*status = RESOURCE_OUT_OF_RANGE;
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
kNumSmartIo, channel);
return HAL_kInvalidHandle;
}

HAL_DigitalHandle handle;

auto port =
smartIoHandles->Allocate(channel, HAL_HandleEnum::DIO, &handle, status);

if (*status != 0) {
if (port) {
hal::SetLastErrorPreviouslyAllocated(status, "SmartIo", channel,
port->previousAllocation);
} else {
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
kNumSmartIo, channel);
}
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
}

port->channel = channel;

*status = port->InitializeMode(input ? SmartIoMode::DigitalInput
: SmartIoMode::DigitalOutput);
if (*status != 0) {
smartIoHandles->Free(handle, HAL_HandleEnum::DIO);
return HAL_kInvalidHandle;
}

port->previousAllocation = allocationLocation ? allocationLocation : "";

return handle;
}

HAL_Bool HAL_CheckDIOChannel(int32_t channel) {
return channel < kNumDigitalChannels && channel >= 0;
return channel < kNumSmartIo && channel >= 0;
}

void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {}
void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
auto port = smartIoHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
if (port == nullptr) {
return;
}

smartIoHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);

// Wait for no other object to hold this handle.
auto start = hal::fpga_clock::now();
while (port.use_count() != 1) {
auto current = hal::fpga_clock::now();
if (start + std::chrono::seconds(1) < current) {
std::puts("DIO handle free timeout");
std::fflush(stdout);
break;
}
std::this_thread::yield();
}
}

void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
}
Expand Down Expand Up @@ -74,24 +129,54 @@ void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,

void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
int32_t* status) {
*status = HAL_HANDLE_ERROR;
return;
auto port = smartIoHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}

*status = port->SetDigitalOutput(value);
}

void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
int32_t* status) {
*status = HAL_HANDLE_ERROR;
return;
auto port = smartIoHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}

*status = port->SwitchDioDirection(input);
}

HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
*status = HAL_HANDLE_ERROR;
return false;
auto port = smartIoHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}

bool ret = false;
*status = port->GetDigitalInput(&ret);
return ret;
}

HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
*status = HAL_HANDLE_ERROR;
return false;
auto port = smartIoHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}

switch (port->currentMode) {
case SmartIoMode::DigitalInput:
return true;
case SmartIoMode::DigitalOutput:
return false;
default:
*status = INCOMPATIBLE_STATE;
return false;
}
}

void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds,
Expand Down
40 changes: 35 additions & 5 deletions hal/src/main/native/systemcore/PWM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,

port->channel = channel;

*status = port->InitializeMode(SmartIoMode::PWMOutput);
*status = port->InitializeMode(SmartIoMode::PwmOutput);
if (*status != 0) {
smartIoHandles->Free(handle, HAL_HandleEnum::PWM);
return HAL_kInvalidHandle;
Expand Down Expand Up @@ -372,18 +372,48 @@ double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
}

void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
// TODO(thad) figure out what this actually means
return;
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, 0, status);
}

void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
int32_t* status) {
// TODO(thad) not currently supported
return;
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}

switch (squelchMask) {
case 0:
*status = port->SetPwmOutputPeriod(hal::PwmOutputPeriod::k5ms);
break;
case 1:
case 2:
*status = port->SetPwmOutputPeriod(hal::PwmOutputPeriod::k10ms);
break;
case 3:
*status = port->SetPwmOutputPeriod(hal::PwmOutputPeriod::k20ms);
break;
default:
*status = PARAMETER_OUT_OF_RANGE;
return;
}
}

void HAL_SetPWMAlwaysHighMode(HAL_DigitalHandle pwmPortHandle,
int32_t* status) {
// Always high is going to have to use a 2ms period
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}

*status = port->SetPwmOutputPeriod(hal::PwmOutputPeriod::k2ms);
if (*status != 0) {
return;
}

HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, kPwmAlwaysHigh, status);
}

Expand Down
2 changes: 1 addition & 1 deletion hal/src/main/native/systemcore/PortsInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace hal {

constexpr int32_t kNumSmartIo = 4;
constexpr int32_t kNumSmartIo = 5;
constexpr int32_t kNumAccumulators = 0;
constexpr int32_t kNumAnalogTriggers = 0;
constexpr int32_t kNumAnalogInputs = 8;
Expand Down
81 changes: 71 additions & 10 deletions hal/src/main/native/systemcore/SmartIo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,90 @@ int32_t SmartIo::InitializeMode(SmartIoMode mode) {

modePublisher = inst.GetIntegerTopic(subTableString + "type").Publish();
getSubscriber =
inst.GetIntegerTopic(subTableString + "valget").Subscribe(0.0, options);
inst.GetIntegerTopic(subTableString + "valget").Subscribe(0, options);
frequencySubscriber =
inst.GetIntegerTopic(subTableString + "freqget").Subscribe(0, options);
setPublisher =
inst.GetIntegerTopic(subTableString + "valset").Publish(options);
periodPublisher =
inst.GetIntegerTopic(subTableString + "periodset").Publish(options);

currentMode = mode;
switch (mode) {
case SmartIoMode::PWMOutput:
modePublisher.Set(4);
setPublisher =
inst.GetIntegerTopic(subTableString + "valset").Publish(options);
// These need to set a 0 output
case SmartIoMode::DigitalOutput:
case SmartIoMode::PwmOutput:
setPublisher.Set(0);
return 0;
break;

// These don't need to set any value
case SmartIoMode::DigitalInput:
case SmartIoMode::AnalogInput:
case SmartIoMode::PwmInput:
case SmartIoMode::SingleCounterRising:
case SmartIoMode::SingleCounterFalling:
break;

default:

return INCOMPATIBLE_STATE;
}

modePublisher.Set(static_cast<int>(mode));
return 0;
}

int32_t SmartIo::SetPwmMicroseconds(uint16_t microseconds) {
if (currentMode != SmartIoMode::PWMOutput) {
int32_t SmartIo::SwitchDioDirection(bool input) {
if (currentMode != SmartIoMode::DigitalInput &&
currentMode != SmartIoMode::DigitalOutput) {
return INCOMPATIBLE_STATE;
}

modePublisher.Set(input ? 0 : 1);
currentMode = input ? SmartIoMode::DigitalInput : SmartIoMode::DigitalOutput;
return 0;
}

int32_t SmartIo::SetDigitalOutput(bool value) {
if (currentMode != SmartIoMode::DigitalInput &&
currentMode != SmartIoMode::DigitalOutput) {
return INCOMPATIBLE_STATE;
}
setPublisher.Set(value ? 255.0 : 0.0);
return 0;
}

int32_t SmartIo::GetDigitalInput(bool* value) {
if (currentMode != SmartIoMode::DigitalInput &&
currentMode != SmartIoMode::DigitalOutput) {
return INCOMPATIBLE_STATE;
}
*value = getSubscriber.Get() != 0;
return 0;
}

int32_t SmartIo::SetPwmOutputPeriod(PwmOutputPeriod period) {
if (currentMode != SmartIoMode::PwmOutput) {
return INCOMPATIBLE_STATE;
}

// TODO(thad) add support for always on signal
switch (period) {
case PwmOutputPeriod::k20ms:
case PwmOutputPeriod::k10ms:
case PwmOutputPeriod::k5ms:
case PwmOutputPeriod::k2ms:
periodPublisher.Set(static_cast<int>(period));
return 0;

default:
return PARAMETER_OUT_OF_RANGE;
}
}

int32_t SmartIo::SetPwmMicroseconds(uint16_t microseconds) {
if (currentMode != SmartIoMode::PwmOutput) {
return INCOMPATIBLE_STATE;
}

if (microseconds > 4095) {
microseconds = 4095;
Expand All @@ -68,7 +129,7 @@ int32_t SmartIo::SetPwmMicroseconds(uint16_t microseconds) {
}

int32_t SmartIo::GetPwmMicroseconds(uint16_t* microseconds) {
if (currentMode != SmartIoMode::PWMOutput) {
if (currentMode != SmartIoMode::PwmOutput) {
return INCOMPATIBLE_STATE;
}

Expand Down
26 changes: 24 additions & 2 deletions hal/src/main/native/systemcore/SmartIo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,20 @@ constexpr int32_t kPwmDisabled = 0;
constexpr int32_t kPwmAlwaysHigh = 0xFFFF;

enum class SmartIoMode {
DigitalInput,
PWMOutput,
DigitalInput = 0,
DigitalOutput,
AnalogInput,
PwmInput,
PwmOutput,
SingleCounterRising,
SingleCounterFalling,
};

enum class PwmOutputPeriod {
k20ms = 0,
k10ms,
k5ms,
k2ms,
};

struct SmartIo {
Expand All @@ -37,7 +49,17 @@ struct SmartIo {
nt::IntegerPublisher setPublisher;
nt::IntegerSubscriber getSubscriber;

nt::IntegerPublisher periodPublisher;
nt::IntegerSubscriber frequencySubscriber;

int32_t InitializeMode(SmartIoMode mode);
int32_t SwitchDioDirection(bool input);

int32_t SetDigitalOutput(bool value);
int32_t GetDigitalInput(bool* value);

int32_t SetPwmOutputPeriod(PwmOutputPeriod period);

int32_t SetPwmMicroseconds(uint16_t microseconds);
int32_t GetPwmMicroseconds(uint16_t* microseconds);
};
Expand Down

0 comments on commit 666d163

Please sign in to comment.