Marcus Chang / AsyncSerial
Committer:
marcuschang
Date:
Fri Apr 17 12:13:31 2015 +0000
Revision:
18:9127f9fae61f
Parent:
17:5dd6bcc93a8a
Child:
19:42ffb517d36a
Updated AsyncSerial.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
marcuschang 16:55e6fbfc1e9d 1 /* mbed Microcontroller Library
marcuschang 16:55e6fbfc1e9d 2 * Copyright (c) 2006-2015 ARM Limited
marcuschang 16:55e6fbfc1e9d 3 *
marcuschang 16:55e6fbfc1e9d 4 * Licensed under the Apache License, Version 2.0 (the "License");
marcuschang 16:55e6fbfc1e9d 5 * you may not use this file except in compliance with the License.
marcuschang 16:55e6fbfc1e9d 6 * You may obtain a copy of the License at
marcuschang 16:55e6fbfc1e9d 7 *
marcuschang 16:55e6fbfc1e9d 8 * http://www.apache.org/licenses/LICENSE-2.0
marcuschang 16:55e6fbfc1e9d 9 *
marcuschang 16:55e6fbfc1e9d 10 * Unless required by applicable law or agreed to in writing, software
marcuschang 16:55e6fbfc1e9d 11 * distributed under the License is distributed on an "AS IS" BASIS,
marcuschang 16:55e6fbfc1e9d 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
marcuschang 16:55e6fbfc1e9d 13 * See the License for the specific language governing permissions and
marcuschang 16:55e6fbfc1e9d 14 * limitations under the License.
marcuschang 16:55e6fbfc1e9d 15 */
marcuschang 16:55e6fbfc1e9d 16
marcuschang 0:dfed780dc91a 17 #include "AsyncSerial/AsyncSerial.h"
marcuschang 0:dfed780dc91a 18
marcuschang 0:dfed780dc91a 19 #include "mbed.h"
marcuschang 0:dfed780dc91a 20
marcuschang 9:e183765bd81b 21 #define MINIMUM_TIMEOUT 1
marcuschang 9:e183765bd81b 22
marcuschang 0:dfed780dc91a 23 AsyncSerial::AsyncSerial(PinName tx, PinName rx, PinName rts, PinName cts)
marcuschang 0:dfed780dc91a 24 : SerialBase(tx, rx),
Marcus Chang 1:a3f39ec7d5f2 25
marcuschang 0:dfed780dc91a 26 sendBuffer(NULL),
marcuschang 0:dfed780dc91a 27 sendLength(0),
Marcus Chang 1:a3f39ec7d5f2 28 sendIndex(0),
Marcus Chang 1:a3f39ec7d5f2 29
Marcus Chang 4:e0a0eef4ca18 30 receiveBuffer(NULL),
Marcus Chang 4:e0a0eef4ca18 31 receiveMaxLength(0),
Marcus Chang 4:e0a0eef4ca18 32 receiveIndex(0),
Marcus Chang 10:9d3ae421081b 33 receiveStatus(AsyncSerial::RECEIVE_TIMEOUT),
Marcus Chang 12:b45908320b9c 34 receiveResult(),
marcuschang 13:dbb23efed611 35 timeout(),
Marcus Chang 4:e0a0eef4ca18 36
Marcus Chang 4:e0a0eef4ca18 37 insideCondition(false),
Marcus Chang 4:e0a0eef4ca18 38 conditionStartBuffer(NULL),
Marcus Chang 4:e0a0eef4ca18 39 conditionStartLength(0),
Marcus Chang 4:e0a0eef4ca18 40 conditionEndBuffer(NULL),
Marcus Chang 4:e0a0eef4ca18 41 conditionEndLength(0),
marcuschang 0:dfed780dc91a 42 conditionIndex(0),
Marcus Chang 12:b45908320b9c 43
Marcus Chang 12:b45908320b9c 44 sendHandler(),
Marcus Chang 12:b45908320b9c 45 receiveHandler(),
marcuschang 13:dbb23efed611 46 waitHandler()
Marcus Chang 1:a3f39ec7d5f2 47 {
Marcus Chang 12:b45908320b9c 48 // register ISR for receiving and sending
marcuschang 0:dfed780dc91a 49 SerialBase::attach<AsyncSerial>(this, &AsyncSerial::getReady, SerialBase::RxIrq);
marcuschang 0:dfed780dc91a 50 SerialBase::attach<AsyncSerial>(this, &AsyncSerial::putDone, SerialBase::TxIrq);
Marcus Chang 10:9d3ae421081b 51
Marcus Chang 10:9d3ae421081b 52 #if DEVICE_SERIAL_FC
Marcus Chang 17:5dd6bcc93a8a 53 if ((rts != NC) && (cts != NC))
Marcus Chang 17:5dd6bcc93a8a 54 {
Marcus Chang 17:5dd6bcc93a8a 55 SerialBase::set_flow_control(SerialBase::RTSCTS, rts, cts);
Marcus Chang 17:5dd6bcc93a8a 56 }
Marcus Chang 10:9d3ae421081b 57 #endif
marcuschang 0:dfed780dc91a 58 }
marcuschang 0:dfed780dc91a 59
Marcus Chang 12:b45908320b9c 60 /* Tx ISR
Marcus Chang 12:b45908320b9c 61 */
marcuschang 0:dfed780dc91a 62 void AsyncSerial::putDone()
marcuschang 0:dfed780dc91a 63 {
Marcus Chang 12:b45908320b9c 64 // sendIndex points to the next byte to send
marcuschang 9:e183765bd81b 65 sendIndex++;
Marcus Chang 1:a3f39ec7d5f2 66
marcuschang 9:e183765bd81b 67 if (sendIndex < sendLength)
marcuschang 9:e183765bd81b 68 {
Marcus Chang 12:b45908320b9c 69 // send next character if there is still more to send
marcuschang 9:e183765bd81b 70 SerialBase::_base_putc(sendBuffer[sendIndex]);
marcuschang 9:e183765bd81b 71 }
marcuschang 9:e183765bd81b 72 else
marcuschang 9:e183765bd81b 73 {
marcuschang 18:9127f9fae61f 74 // reset
marcuschang 18:9127f9fae61f 75 sendLength = 0;
marcuschang 18:9127f9fae61f 76
marcuschang 18:9127f9fae61f 77 // signal callback function
Marcus Chang 12:b45908320b9c 78 sendHandler.call();
marcuschang 0:dfed780dc91a 79 }
marcuschang 0:dfed780dc91a 80 }
marcuschang 0:dfed780dc91a 81
Marcus Chang 12:b45908320b9c 82 /* Rx ISR
Marcus Chang 12:b45908320b9c 83 */
marcuschang 0:dfed780dc91a 84 void AsyncSerial::getReady()
Marcus Chang 10:9d3ae421081b 85 {
Marcus Chang 15:4d7d96cacc18 86 // read character from buffer
Marcus Chang 15:4d7d96cacc18 87 uint8_t input = SerialBase::_base_getc();
Marcus Chang 15:4d7d96cacc18 88
Marcus Chang 15:4d7d96cacc18 89 DEBUG("%c", input);
Marcus Chang 15:4d7d96cacc18 90
Marcus Chang 15:4d7d96cacc18 91 // check if start condition has been met
Marcus Chang 15:4d7d96cacc18 92 if (insideCondition)
Marcus Chang 1:a3f39ec7d5f2 93 {
Marcus Chang 15:4d7d96cacc18 94 /* If stop condition has been set, check if the
Marcus Chang 15:4d7d96cacc18 95 character matches. If it does increment counter
Marcus Chang 15:4d7d96cacc18 96 to point to next character in sequence. Otherwise
Marcus Chang 15:4d7d96cacc18 97 reset sequence search.
Marcus Chang 15:4d7d96cacc18 98 */
Marcus Chang 15:4d7d96cacc18 99 if (conditionEndBuffer != NULL)
Marcus Chang 15:4d7d96cacc18 100 {
Marcus Chang 15:4d7d96cacc18 101 if (input == conditionEndBuffer[conditionIndex])
Marcus Chang 15:4d7d96cacc18 102 {
Marcus Chang 15:4d7d96cacc18 103 conditionIndex++;
Marcus Chang 1:a3f39ec7d5f2 104
Marcus Chang 15:4d7d96cacc18 105 /* End condition has been met.
Marcus Chang 15:4d7d96cacc18 106 Set receive status to indicate sequence has been found
Marcus Chang 15:4d7d96cacc18 107 and re-arm timer. The timeout is responsible for
Marcus Chang 15:4d7d96cacc18 108 signaling the callback function and is useful for
Marcus Chang 15:4d7d96cacc18 109 decoupling the callback from the receive ISR.
Marcus Chang 15:4d7d96cacc18 110 */
Marcus Chang 15:4d7d96cacc18 111 if (conditionIndex == conditionEndLength)
Marcus Chang 15:4d7d96cacc18 112 {
Marcus Chang 15:4d7d96cacc18 113 receiveStatus = AsyncSerial::RECEIVE_FOUND;
Marcus Chang 15:4d7d96cacc18 114 timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, MINIMUM_TIMEOUT);
Marcus Chang 15:4d7d96cacc18 115 }
Marcus Chang 15:4d7d96cacc18 116 }
Marcus Chang 15:4d7d96cacc18 117 else
Marcus Chang 15:4d7d96cacc18 118 {
Marcus Chang 15:4d7d96cacc18 119 // Character didn't match sequence. Start over.
Marcus Chang 15:4d7d96cacc18 120 conditionIndex = 0;
Marcus Chang 15:4d7d96cacc18 121 }
Marcus Chang 15:4d7d96cacc18 122 }
marcuschang 7:5ba3a01e13c4 123
Marcus Chang 15:4d7d96cacc18 124 /* A receive buffer is available.
Marcus Chang 15:4d7d96cacc18 125 Store character in buffer and check if buffer is full,
Marcus Chang 15:4d7d96cacc18 126 set receive status and re-arm timeout if it is.
Marcus Chang 15:4d7d96cacc18 127 */
Marcus Chang 15:4d7d96cacc18 128 if (receiveBuffer != NULL)
Marcus Chang 10:9d3ae421081b 129 {
Marcus Chang 15:4d7d96cacc18 130 receiveBuffer[receiveIndex] = input;
Marcus Chang 15:4d7d96cacc18 131 receiveIndex++;
Marcus Chang 15:4d7d96cacc18 132
Marcus Chang 15:4d7d96cacc18 133 /* If end condition has been met we still store the character
Marcus Chang 15:4d7d96cacc18 134 but we do not change the receive status nor re-arm the timer.
Marcus Chang 12:b45908320b9c 135 */
Marcus Chang 15:4d7d96cacc18 136 if ((receiveIndex == receiveMaxLength) && (receiveStatus != AsyncSerial::RECEIVE_FOUND))
marcuschang 0:dfed780dc91a 137 {
Marcus Chang 15:4d7d96cacc18 138 receiveStatus = AsyncSerial::RECEIVE_FULL;
Marcus Chang 15:4d7d96cacc18 139 timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, MINIMUM_TIMEOUT);
Marcus Chang 15:4d7d96cacc18 140 }
Marcus Chang 15:4d7d96cacc18 141 }
Marcus Chang 15:4d7d96cacc18 142 }
Marcus Chang 15:4d7d96cacc18 143 /* Start condition has not been met.
Marcus Chang 15:4d7d96cacc18 144 */
Marcus Chang 15:4d7d96cacc18 145 else
Marcus Chang 15:4d7d96cacc18 146 {
Marcus Chang 15:4d7d96cacc18 147 if (conditionStartBuffer != NULL)
Marcus Chang 15:4d7d96cacc18 148 {
Marcus Chang 15:4d7d96cacc18 149 if (input == conditionStartBuffer[conditionIndex])
Marcus Chang 15:4d7d96cacc18 150 {
Marcus Chang 15:4d7d96cacc18 151 conditionIndex++;
Marcus Chang 4:e0a0eef4ca18 152
Marcus Chang 15:4d7d96cacc18 153 /* Set condition flag and reset index since it is reused.
Marcus Chang 15:4d7d96cacc18 154 */
Marcus Chang 15:4d7d96cacc18 155 if (conditionIndex == conditionStartLength)
Marcus Chang 4:e0a0eef4ca18 156 {
Marcus Chang 15:4d7d96cacc18 157 insideCondition = true;
Marcus Chang 4:e0a0eef4ca18 158 conditionIndex = 0;
Marcus Chang 4:e0a0eef4ca18 159 }
Marcus Chang 4:e0a0eef4ca18 160 }
Marcus Chang 15:4d7d96cacc18 161 else
marcuschang 9:e183765bd81b 162 {
Marcus Chang 15:4d7d96cacc18 163 // Character didn't match sequence. Start over.
Marcus Chang 15:4d7d96cacc18 164 conditionIndex = 0;
marcuschang 0:dfed780dc91a 165 }
marcuschang 0:dfed780dc91a 166 }
marcuschang 0:dfed780dc91a 167 }
marcuschang 0:dfed780dc91a 168 }
marcuschang 0:dfed780dc91a 169
Marcus Chang 12:b45908320b9c 170 /* Common function for signaling receive done handler or wait done handler.
Marcus Chang 12:b45908320b9c 171 */
marcuschang 5:aecd37846dcc 172 void AsyncSerial::getDone(uint8_t status)
Marcus Chang 1:a3f39ec7d5f2 173 {
marcuschang 11:6b99dbf1b65d 174 DEBUG("getDone: %d\r\n", status);
marcuschang 7:5ba3a01e13c4 175
Marcus Chang 12:b45908320b9c 176 /* Check whether to call the wait handler or the receive handler.
Marcus Chang 12:b45908320b9c 177 */
Marcus Chang 12:b45908320b9c 178 if (receiveBuffer == NULL)
marcuschang 0:dfed780dc91a 179 {
marcuschang 11:6b99dbf1b65d 180 waitHandler.call(status);
marcuschang 0:dfed780dc91a 181 }
Marcus Chang 6:9d48f2197243 182 else
Marcus Chang 1:a3f39ec7d5f2 183 {
Marcus Chang 10:9d3ae421081b 184 receiveResult.buffer = receiveBuffer;
Marcus Chang 10:9d3ae421081b 185 receiveResult.length = receiveIndex;
Marcus Chang 10:9d3ae421081b 186 receiveResult.status = status;
Marcus Chang 10:9d3ae421081b 187
Marcus Chang 10:9d3ae421081b 188 receiveHandler.call(&receiveResult);
Marcus Chang 1:a3f39ec7d5f2 189 }
marcuschang 0:dfed780dc91a 190 }
marcuschang 0:dfed780dc91a 191
Marcus Chang 12:b45908320b9c 192 /* Send block of data. Function pointer interface.
Marcus Chang 12:b45908320b9c 193 */
marcuschang 7:5ba3a01e13c4 194 void AsyncSerial::send(send_done_t handler, const char* buffer, uint16_t length)
marcuschang 0:dfed780dc91a 195 {
Marcus Chang 12:b45908320b9c 196 sendHandler.attach(handler);
marcuschang 11:6b99dbf1b65d 197 send(buffer, length);
marcuschang 0:dfed780dc91a 198 }
marcuschang 0:dfed780dc91a 199
Marcus Chang 12:b45908320b9c 200 /* Common send block of data function.
Marcus Chang 12:b45908320b9c 201 */
marcuschang 7:5ba3a01e13c4 202 void AsyncSerial::send(const char* buffer, uint16_t length)
marcuschang 0:dfed780dc91a 203 {
Marcus Chang 12:b45908320b9c 204 /* Signal callback function immediately if there is nothing to send.
Marcus Chang 12:b45908320b9c 205 */
marcuschang 11:6b99dbf1b65d 206 if ((buffer != NULL) && (length != 0))
Marcus Chang 12:b45908320b9c 207 {
Marcus Chang 12:b45908320b9c 208 // Store book keeping variables
marcuschang 11:6b99dbf1b65d 209 sendBuffer = buffer;
marcuschang 11:6b99dbf1b65d 210 sendLength = length;
marcuschang 11:6b99dbf1b65d 211 sendIndex = 0;
Marcus Chang 12:b45908320b9c 212
Marcus Chang 12:b45908320b9c 213 // Send first character. ISR sends the rest.
marcuschang 11:6b99dbf1b65d 214 SerialBase::_base_putc(sendBuffer[sendIndex]);
Marcus Chang 12:b45908320b9c 215
marcuschang 11:6b99dbf1b65d 216 DEBUG("send: %p %d\r\n", buffer, length);
marcuschang 11:6b99dbf1b65d 217 }
marcuschang 11:6b99dbf1b65d 218 else
marcuschang 11:6b99dbf1b65d 219 {
marcuschang 11:6b99dbf1b65d 220 sendHandler.call();
marcuschang 11:6b99dbf1b65d 221 }
marcuschang 0:dfed780dc91a 222 }
marcuschang 0:dfed780dc91a 223
Marcus Chang 12:b45908320b9c 224 /* Receiving block of data. Function pointer interface.
Marcus Chang 12:b45908320b9c 225 */
marcuschang 13:dbb23efed611 226 void AsyncSerial::receive(receive_done_t _handler,
marcuschang 13:dbb23efed611 227 uint8_t* _receiveBuffer, uint16_t _maxLength,
marcuschang 7:5ba3a01e13c4 228 const char* _conditionStartBuffer, uint16_t _conditionStartLength,
marcuschang 7:5ba3a01e13c4 229 const char* _conditionEndBuffer, uint16_t _conditionEndLength,
marcuschang 13:dbb23efed611 230 uint32_t _timeoutMilli)
Marcus Chang 10:9d3ae421081b 231 {
marcuschang 13:dbb23efed611 232 receiveHandler.attach(_handler);
marcuschang 13:dbb23efed611 233
Marcus Chang 12:b45908320b9c 234 /* Signal callback function immediately if buffer and maxLength are invalid.
Marcus Chang 12:b45908320b9c 235 */
marcuschang 13:dbb23efed611 236 if ((_receiveBuffer == NULL) || (_maxLength == 0))
Marcus Chang 12:b45908320b9c 237 {
Marcus Chang 12:b45908320b9c 238 receiveResult.buffer = NULL;
Marcus Chang 12:b45908320b9c 239 receiveResult.length = 0;
Marcus Chang 12:b45908320b9c 240 receiveResult.status = AsyncSerial::RECEIVE_FULL;
Marcus Chang 1:a3f39ec7d5f2 241
Marcus Chang 12:b45908320b9c 242 receiveHandler.call(&receiveResult);
Marcus Chang 4:e0a0eef4ca18 243 }
Marcus Chang 4:e0a0eef4ca18 244 else
Marcus Chang 4:e0a0eef4ca18 245 {
marcuschang 13:dbb23efed611 246 receive(_receiveBuffer, _maxLength,
marcuschang 13:dbb23efed611 247 _conditionStartBuffer, _conditionStartLength,
marcuschang 13:dbb23efed611 248 _conditionEndBuffer, _conditionEndLength,
marcuschang 13:dbb23efed611 249 _timeoutMilli);
marcuschang 13:dbb23efed611 250 }
marcuschang 13:dbb23efed611 251 }
Marcus Chang 4:e0a0eef4ca18 252
marcuschang 13:dbb23efed611 253 /* Common receive function.
marcuschang 13:dbb23efed611 254 */
marcuschang 13:dbb23efed611 255 void AsyncSerial::receive(uint8_t* _receiveBuffer, uint16_t _maxLength,
marcuschang 13:dbb23efed611 256 const char* _conditionStartBuffer, uint16_t _conditionStartLength,
marcuschang 13:dbb23efed611 257 const char* _conditionEndBuffer, uint16_t _conditionEndLength,
marcuschang 13:dbb23efed611 258 uint32_t _timeoutMilli)
marcuschang 13:dbb23efed611 259 {
marcuschang 13:dbb23efed611 260 // Book keeping variables for reception
marcuschang 13:dbb23efed611 261 receiveBuffer = _receiveBuffer;
marcuschang 13:dbb23efed611 262 receiveMaxLength = _maxLength;
marcuschang 13:dbb23efed611 263 receiveIndex = 0;
marcuschang 13:dbb23efed611 264 receiveStatus = AsyncSerial::RECEIVE_TIMEOUT;
Marcus Chang 12:b45908320b9c 265
marcuschang 13:dbb23efed611 266 // Book keeping variables for conditions
marcuschang 13:dbb23efed611 267 conditionStartBuffer = _conditionStartBuffer;
marcuschang 13:dbb23efed611 268 conditionStartLength = _conditionStartLength;
marcuschang 13:dbb23efed611 269 conditionEndBuffer = _conditionEndBuffer;
marcuschang 13:dbb23efed611 270 conditionEndLength = _conditionEndLength;
marcuschang 13:dbb23efed611 271 conditionIndex = 0;
Marcus Chang 12:b45908320b9c 272
marcuschang 13:dbb23efed611 273 // Check if optional start condition is set
marcuschang 13:dbb23efed611 274 if ((_conditionStartBuffer != NULL) && (_conditionStartLength != 0))
marcuschang 13:dbb23efed611 275 {
marcuschang 13:dbb23efed611 276 insideCondition = false;
marcuschang 13:dbb23efed611 277 }
marcuschang 13:dbb23efed611 278 else
marcuschang 13:dbb23efed611 279 {
marcuschang 13:dbb23efed611 280 insideCondition = true;
marcuschang 11:6b99dbf1b65d 281 }
marcuschang 11:6b99dbf1b65d 282
marcuschang 13:dbb23efed611 283 // Clear buffer. This re-arms the rx interrupts.
marcuschang 13:dbb23efed611 284 while (SerialBase::readable())
marcuschang 13:dbb23efed611 285 {
marcuschang 13:dbb23efed611 286 SerialBase::_base_getc();
marcuschang 13:dbb23efed611 287 }
marcuschang 13:dbb23efed611 288
marcuschang 13:dbb23efed611 289 // Arm timer and start receiving.
marcuschang 13:dbb23efed611 290 timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, _timeoutMilli * 1000);
marcuschang 13:dbb23efed611 291
marcuschang 13:dbb23efed611 292 DEBUG("receive: %p\r\n", _receiveBuffer);
marcuschang 0:dfed780dc91a 293 }
marcuschang 0:dfed780dc91a 294
Marcus Chang 12:b45908320b9c 295 /* Wait until timeout or sequence is detected.
Marcus Chang 12:b45908320b9c 296 */
marcuschang 7:5ba3a01e13c4 297 void AsyncSerial::wait(wait_done_t handler,
marcuschang 7:5ba3a01e13c4 298 const char* conditionEndBuffer, uint16_t conditionEndLength,
Marcus Chang 6:9d48f2197243 299 uint32_t timeoutMilli)
Marcus Chang 6:9d48f2197243 300 {
marcuschang 11:6b99dbf1b65d 301 waitHandler.attach(handler);
Marcus Chang 6:9d48f2197243 302
marcuschang 11:6b99dbf1b65d 303 receive(NULL, 0,
marcuschang 11:6b99dbf1b65d 304 NULL, 0,
marcuschang 11:6b99dbf1b65d 305 conditionEndBuffer, conditionEndLength,
marcuschang 11:6b99dbf1b65d 306 timeoutMilli);
Marcus Chang 6:9d48f2197243 307 }
Marcus Chang 6:9d48f2197243 308
Marcus Chang 12:b45908320b9c 309 /* Timeout fired. Call common receive done function.
Marcus Chang 12:b45908320b9c 310 */
marcuschang 5:aecd37846dcc 311 void AsyncSerial::receiveTimeout()
marcuschang 5:aecd37846dcc 312 {
marcuschang 11:6b99dbf1b65d 313 DEBUG("timeout\r\n");
Marcus Chang 10:9d3ae421081b 314
marcuschang 9:e183765bd81b 315 getDone(receiveStatus);
marcuschang 5:aecd37846dcc 316 }
marcuschang 5:aecd37846dcc 317