blob: eab7d823236f37faa8b2d724594c2300ae422e8e [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "hal/AnalogOutput.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <string>
8
Brian Silverman8fce7482020-01-05 13:18:21 -08009#include "AnalogInternal.h"
10#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070011#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080012#include "PortsInternal.h"
13#include "hal/Errors.h"
14#include "hal/handles/HandlesInternal.h"
15#include "hal/handles/IndexedHandleResource.h"
16
17using namespace hal;
18
19namespace {
20
21struct AnalogOutput {
22 uint8_t channel;
Austin Schuh812d0d12021-11-04 20:16:48 -070023 std::string previousAllocation;
Brian Silverman8fce7482020-01-05 13:18:21 -080024};
25
26} // namespace
27
28static IndexedHandleResource<HAL_AnalogOutputHandle, AnalogOutput,
29 kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>*
30 analogOutputHandles;
31
Austin Schuh812d0d12021-11-04 20:16:48 -070032namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080033void InitializeAnalogOutput() {
34 static IndexedHandleResource<HAL_AnalogOutputHandle, AnalogOutput,
35 kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>
36 aoH;
37 analogOutputHandles = &aoH;
38}
Austin Schuh812d0d12021-11-04 20:16:48 -070039} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080040
41extern "C" {
42
Austin Schuh812d0d12021-11-04 20:16:48 -070043HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(
44 HAL_PortHandle portHandle, const char* allocationLocation,
45 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -080046 hal::init::CheckInit();
47 initializeAnalog(status);
48
Austin Schuh812d0d12021-11-04 20:16:48 -070049 if (*status != 0) {
Brian Silverman8fce7482020-01-05 13:18:21 -080050 return HAL_kInvalidHandle;
51 }
52
Austin Schuh812d0d12021-11-04 20:16:48 -070053 int16_t channel = getPortHandleChannel(portHandle);
54 if (channel == InvalidHandleIndex || channel >= kNumAnalogOutputs) {
55 *status = RESOURCE_OUT_OF_RANGE;
56 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Output",
57 0, kNumAnalogOutputs, channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080058 return HAL_kInvalidHandle;
59 }
60
Austin Schuh812d0d12021-11-04 20:16:48 -070061 HAL_AnalogOutputHandle handle;
62 auto port = analogOutputHandles->Allocate(channel, &handle, status);
63
64 if (*status != 0) {
65 if (port) {
66 hal::SetLastErrorPreviouslyAllocated(status, "Analog Output", channel,
67 port->previousAllocation);
68 } else {
69 hal::SetLastErrorIndexOutOfRange(status,
70 "Invalid Index for Analog Output", 0,
71 kNumAnalogOutputs, channel);
72 }
73 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
74 }
75
Brian Silverman8fce7482020-01-05 13:18:21 -080076 port->channel = static_cast<uint8_t>(channel);
Austin Schuh812d0d12021-11-04 20:16:48 -070077 port->previousAllocation = allocationLocation ? allocationLocation : "";
78
Brian Silverman8fce7482020-01-05 13:18:21 -080079 return handle;
80}
81
82void HAL_FreeAnalogOutputPort(HAL_AnalogOutputHandle analogOutputHandle) {
83 // no status, so no need to check for a proper free.
84 analogOutputHandles->Free(analogOutputHandle);
85}
86
87void HAL_SetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
88 double voltage, int32_t* status) {
89 auto port = analogOutputHandles->Get(analogOutputHandle);
90 if (port == nullptr) {
91 *status = HAL_HANDLE_ERROR;
92 return;
93 }
94
95 uint16_t rawValue = static_cast<uint16_t>(voltage / 5.0 * 0x1000);
96
Austin Schuh812d0d12021-11-04 20:16:48 -070097 if (voltage < 0.0) {
Brian Silverman8fce7482020-01-05 13:18:21 -080098 rawValue = 0;
Austin Schuh812d0d12021-11-04 20:16:48 -070099 } else if (voltage > 5.0) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800100 rawValue = 0x1000;
Austin Schuh812d0d12021-11-04 20:16:48 -0700101 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800102
103 analogOutputSystem->writeMXP(port->channel, rawValue, status);
104}
105
106double HAL_GetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
107 int32_t* status) {
108 auto port = analogOutputHandles->Get(analogOutputHandle);
109 if (port == nullptr) {
110 *status = HAL_HANDLE_ERROR;
111 return 0.0;
112 }
113
114 uint16_t rawValue = analogOutputSystem->readMXP(port->channel, status);
115
116 return rawValue * 5.0 / 0x1000;
117}
118
119HAL_Bool HAL_CheckAnalogOutputChannel(int32_t channel) {
120 return channel < kNumAnalogOutputs && channel >= 0;
121}
122
123} // extern "C"