blob: 56435a9bc17adce2f79b515d24efe2fca9d0d0a0 [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "HAL/SerialPort.h"
9#include "SerialPort.h"
10
11#include "HAL/HAL.h"
12
13// static ViStatus _VI_FUNCH ioCompleteHandler (ViSession vi, ViEventType
14// eventType, ViEvent event, ViAddr userHandle);
15
16using namespace frc;
17
18/**
19 * Create an instance of a Serial Port class.
20 *
21 * @param baudRate The baud rate to configure the serial port.
22 * @param port The physical port to use
23 * @param dataBits The number of data bits per transfer. Valid values are
24 * between 5 and 8 bits.
25 * @param parity Select the type of parity checking to use.
26 * @param stopBits The number of stop bits to use as defined by the enum
27 * StopBits.
28 */
29SerialPort::SerialPort(int baudRate, Port port, int dataBits,
30 SerialPort::Parity parity,
31 SerialPort::StopBits stopBits) {
32 int32_t status = 0;
33
34 m_port = port;
35
36 HAL_InitializeSerialPort(static_cast<HAL_SerialPort>(port), &status);
37 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
38 // Don't continue if initialization failed
39 if (status < 0) return;
40 HAL_SetSerialBaudRate(static_cast<HAL_SerialPort>(port), baudRate, &status);
41 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
42 HAL_SetSerialDataBits(static_cast<HAL_SerialPort>(port), dataBits, &status);
43 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
44 HAL_SetSerialParity(static_cast<HAL_SerialPort>(port), parity, &status);
45 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
46 HAL_SetSerialStopBits(static_cast<HAL_SerialPort>(port), stopBits, &status);
47 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
48
49 // Set the default timeout to 5 seconds.
50 SetTimeout(5.0);
51
52 // Don't wait until the buffer is full to transmit.
53 SetWriteBufferMode(kFlushOnAccess);
54
55 EnableTermination();
56
57 // viInstallHandler(m_portHandle, VI_EVENT_IO_COMPLETION, ioCompleteHandler,
58 // this);
59 // viEnableEvent(m_portHandle, VI_EVENT_IO_COMPLETION, VI_HNDLR, VI_NULL);
60
61 HAL_Report(HALUsageReporting::kResourceType_SerialPort, 0);
62}
63
64/**
65 * Destructor.
66 */
67SerialPort::~SerialPort() {
68 int32_t status = 0;
69 HAL_CloseSerial(static_cast<HAL_SerialPort>(m_port), &status);
70 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
71}
72
73/**
74 * Set the type of flow control to enable on this port.
75 *
76 * By default, flow control is disabled.
77 */
78void SerialPort::SetFlowControl(SerialPort::FlowControl flowControl) {
79 int32_t status = 0;
80 HAL_SetSerialFlowControl(static_cast<HAL_SerialPort>(m_port), flowControl,
81 &status);
82 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
83}
84
85/**
86 * Enable termination and specify the termination character.
87 *
88 * Termination is currently only implemented for receive.
89 * When the the terminator is recieved, the Read() or Scanf() will return
90 * fewer bytes than requested, stopping after the terminator.
91 *
92 * @param terminator The character to use for termination.
93 */
94void SerialPort::EnableTermination(char terminator) {
95 int32_t status = 0;
96 HAL_EnableSerialTermination(static_cast<HAL_SerialPort>(m_port), terminator,
97 &status);
98 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
99}
100
101/**
102 * Disable termination behavior.
103 */
104void SerialPort::DisableTermination() {
105 int32_t status = 0;
106 HAL_DisableSerialTermination(static_cast<HAL_SerialPort>(m_port), &status);
107 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
108}
109
110/**
111 * Get the number of bytes currently available to read from the serial port.
112 *
113 * @return The number of bytes available to read
114 */
115int SerialPort::GetBytesReceived() {
116 int32_t status = 0;
117 int retVal =
118 HAL_GetSerialBytesReceived(static_cast<HAL_SerialPort>(m_port), &status);
119 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
120 return retVal;
121}
122
123/**
124 * Read raw bytes out of the buffer.
125 *
126 * @param buffer Pointer to the buffer to store the bytes in.
127 * @param count The maximum number of bytes to read.
128 * @return The number of bytes actually read into the buffer.
129 */
130int SerialPort::Read(char* buffer, int count) {
131 int32_t status = 0;
132 int retVal = HAL_ReadSerial(static_cast<HAL_SerialPort>(m_port), buffer,
133 count, &status);
134 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
135 return retVal;
136}
137
138/**
139 * Write raw bytes to the buffer. Deprecated, please use StringRef overload. Use
140 * Write({data, len}) to get a buffer that is shorter then the length of the
141 * std::string.
142 *
143 * @param buffer Pointer to the buffer to read the bytes from. If string.size()
144 * is less then count, only the length of string.size() will be sent.
145 * @param count The maximum number of bytes to write.
146 * @return The number of bytes actually written into the port.
147 */
148int SerialPort::Write(const std::string& buffer, int count) {
149 return Write(llvm::StringRef(
150 buffer.data(), std::min(static_cast<int>(buffer.size()), count)));
151}
152
153/**
154 * Write raw bytes to the buffer.
155 *
156 * @param buffer Pointer to the buffer to read the bytes from.
157 * @param count The maximum number of bytes to write.
158 * @return The number of bytes actually written into the port.
159 */
160int SerialPort::Write(const char* buffer, int count) {
161 return Write(llvm::StringRef(buffer, static_cast<size_t>(count)));
162}
163
164/**
165 * Write raw bytes to the buffer.
166 *
167 * @param buffer StringRef to the buffer to read the bytes from.
168 * @return The number of bytes actually written into the port.
169 */
170int SerialPort::Write(llvm::StringRef buffer) {
171 int32_t status = 0;
172 int retVal = HAL_WriteSerial(static_cast<HAL_SerialPort>(m_port),
173 buffer.data(), buffer.size(), &status);
174 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
175 return retVal;
176}
177
178/**
179 * Configure the timeout of the serial port.
180 *
181 * This defines the timeout for transactions with the hardware.
182 * It will affect reads and very large writes.
183 *
184 * @param timeout The number of seconds to to wait for I/O.
185 */
186void SerialPort::SetTimeout(double timeout) {
187 int32_t status = 0;
188 HAL_SetSerialTimeout(static_cast<HAL_SerialPort>(m_port), timeout, &status);
189 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
190}
191
192/**
193 * Specify the size of the input buffer.
194 *
195 * Specify the amount of data that can be stored before data
196 * from the device is returned to Read or Scanf. If you want
197 * data that is recieved to be returned immediately, set this to 1.
198 *
199 * It the buffer is not filled before the read timeout expires, all
200 * data that has been received so far will be returned.
201 *
202 * @param size The read buffer size.
203 */
204void SerialPort::SetReadBufferSize(int size) {
205 int32_t status = 0;
206 HAL_SetSerialReadBufferSize(static_cast<HAL_SerialPort>(m_port), size,
207 &status);
208 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
209}
210
211/**
212 * Specify the size of the output buffer.
213 *
214 * Specify the amount of data that can be stored before being
215 * transmitted to the device.
216 *
217 * @param size The write buffer size.
218 */
219void SerialPort::SetWriteBufferSize(int size) {
220 int32_t status = 0;
221 HAL_SetSerialWriteBufferSize(static_cast<HAL_SerialPort>(m_port), size,
222 &status);
223 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
224}
225
226/**
227 * Specify the flushing behavior of the output buffer.
228 *
229 * When set to kFlushOnAccess, data is synchronously written to the serial port
230 * after each call to either Printf() or Write().
231 *
232 * When set to kFlushWhenFull, data will only be written to the serial port when
233 * the buffer is full or when Flush() is called.
234 *
235 * @param mode The write buffer mode.
236 */
237void SerialPort::SetWriteBufferMode(SerialPort::WriteBufferMode mode) {
238 int32_t status = 0;
239 HAL_SetSerialWriteMode(static_cast<HAL_SerialPort>(m_port), mode, &status);
240 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
241}
242
243/**
244 * Force the output buffer to be written to the port.
245 *
246 * This is used when SetWriteBufferMode() is set to kFlushWhenFull to force a
247 * flush before the buffer is full.
248 */
249void SerialPort::Flush() {
250 int32_t status = 0;
251 HAL_FlushSerial(static_cast<HAL_SerialPort>(m_port), &status);
252 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
253}
254
255/**
256 * Reset the serial port driver to a known state.
257 *
258 * Empty the transmit and receive buffers in the device and formatted I/O.
259 */
260void SerialPort::Reset() {
261 int32_t status = 0;
262 HAL_ClearSerial(static_cast<HAL_SerialPort>(m_port), &status);
263 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
264}