Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: ManchesterUART_Transmitter ManchesterUART_Receiver
ManchesterUART.cpp@1:b869674fe56e, 2018-07-30 (annotated)
- Committer:
- hudakz
- Date:
- Mon Jul 30 09:38:03 2018 +0000
- Revision:
- 1:b869674fe56e
- Parent:
- 0:e076052bcffd
- Child:
- 2:8cb6a0a77e56
Preamble length can be modified.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| hudakz | 0:e076052bcffd | 1 | /* |
| hudakz | 0:e076052bcffd | 2 | ****************************************************************************** |
| hudakz | 0:e076052bcffd | 3 | * @file ManchesterUART.cpp |
| hudakz | 0:e076052bcffd | 4 | * @author Zoltan Hudak |
| hudakz | 0:e076052bcffd | 5 | * @version |
| hudakz | 0:e076052bcffd | 6 | * @date 2017-Nov-22 |
| hudakz | 0:e076052bcffd | 7 | * @brief Manchester code over UART for mbed |
| hudakz | 0:e076052bcffd | 8 | ****************************************************************************** |
| hudakz | 0:e076052bcffd | 9 | * @attention |
| hudakz | 0:e076052bcffd | 10 | * |
| hudakz | 0:e076052bcffd | 11 | * <h2><center>© COPYRIGHT(c) 2017 Zoltan Hudak <hudakz@outlook.com> |
| hudakz | 0:e076052bcffd | 12 | * |
| hudakz | 0:e076052bcffd | 13 | * All rights reserved. |
| hudakz | 0:e076052bcffd | 14 | |
| hudakz | 0:e076052bcffd | 15 | This program is free software: you can redistribute it and/or modify |
| hudakz | 0:e076052bcffd | 16 | it under the terms of the GNU General Public License as published by |
| hudakz | 0:e076052bcffd | 17 | the Free Software Foundation, either version 3 of the License, or |
| hudakz | 0:e076052bcffd | 18 | (at your option) any later version. |
| hudakz | 0:e076052bcffd | 19 | |
| hudakz | 0:e076052bcffd | 20 | This program is distributed in the hope that it will be useful, |
| hudakz | 0:e076052bcffd | 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| hudakz | 0:e076052bcffd | 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| hudakz | 0:e076052bcffd | 23 | GNU General Public License for more details. |
| hudakz | 0:e076052bcffd | 24 | |
| hudakz | 0:e076052bcffd | 25 | You should have received a copy of the GNU General Public License |
| hudakz | 0:e076052bcffd | 26 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| hudakz | 0:e076052bcffd | 27 | */ |
| hudakz | 0:e076052bcffd | 28 | /* |
| hudakz | 1:b869674fe56e | 29 | * This library implements Manchester code using UART serial connection. Each |
| hudakz | 0:e076052bcffd | 30 | * data byte is encoded into two bytes representing two nibbles of the original |
| hudakz | 1:b869674fe56e | 31 | * data byte. These two bytes are then sent over UART serial link connection. |
| hudakz | 0:e076052bcffd | 32 | * The receiver reconstructs the original data byte from the two bytes received. |
| hudakz | 0:e076052bcffd | 33 | * A start and stop pattern are sent to signify the begin and end of a message. |
| hudakz | 1:b869674fe56e | 34 | * |
| hudakz | 0:e076052bcffd | 35 | * The library is based on the article published by Adrian Mills: |
| hudakz | 1:b869674fe56e | 36 | * http://www.quickbuilder.co.uk/qb/articles/Manchester_encoding_using_RS232.pdf |
| hudakz | 0:e076052bcffd | 37 | */ |
| hudakz | 0:e076052bcffd | 38 | #include "ManchesterUART.h" |
| hudakz | 0:e076052bcffd | 39 | #include "ManchesterMsg.h" |
| hudakz | 0:e076052bcffd | 40 | |
| hudakz | 0:e076052bcffd | 41 | /** |
| hudakz | 0:e076052bcffd | 42 | * @brief Transmits message |
| hudakz | 0:e076052bcffd | 43 | * @note |
| hudakz | 0:e076052bcffd | 44 | * @param msg Message to transmit |
| hudakz | 0:e076052bcffd | 45 | * @retval |
| hudakz | 0:e076052bcffd | 46 | */ |
| hudakz | 1:b869674fe56e | 47 | void ManchesterUART::transmit(ManchesterMsg& msg) |
| hudakz | 1:b869674fe56e | 48 | { |
| hudakz | 0:e076052bcffd | 49 | _data = msg.data; |
| hudakz | 0:e076052bcffd | 50 | _len = msg.len; |
| hudakz | 0:e076052bcffd | 51 | |
| hudakz | 1:b869674fe56e | 52 | for (uint8_t i = 0; i < _preamble; i++) |
| hudakz | 1:b869674fe56e | 53 | _serial.putc(START); |
| hudakz | 1:b869674fe56e | 54 | for (uint32_t i = 0; i < _len; i++) |
| hudakz | 1:b869674fe56e | 55 | { |
| hudakz | 0:e076052bcffd | 56 | transmitByte(_data[i]); |
| hudakz | 0:e076052bcffd | 57 | } |
| hudakz | 1:b869674fe56e | 58 | |
| hudakz | 0:e076052bcffd | 59 | _serial.putc(STOP); |
| hudakz | 0:e076052bcffd | 60 | } |
| hudakz | 0:e076052bcffd | 61 | |
| hudakz | 0:e076052bcffd | 62 | /** |
| hudakz | 0:e076052bcffd | 63 | * @brief Transmits a byte |
| hudakz | 0:e076052bcffd | 64 | * @note |
| hudakz | 0:e076052bcffd | 65 | * @param data The byte to transmit |
| hudakz | 0:e076052bcffd | 66 | * @retval |
| hudakz | 0:e076052bcffd | 67 | */ |
| hudakz | 1:b869674fe56e | 68 | void ManchesterUART::transmitByte(uint8_t data) |
| hudakz | 1:b869674fe56e | 69 | { |
| hudakz | 0:e076052bcffd | 70 | uint8_t encoded; |
| hudakz | 0:e076052bcffd | 71 | |
| hudakz | 1:b869674fe56e | 72 | for (uint8_t i = 0; i < 2; i++) |
| hudakz | 1:b869674fe56e | 73 | { |
| hudakz | 1:b869674fe56e | 74 | encoded = 0; // manchester encoded byte |
| hudakz | 1:b869674fe56e | 75 | for (uint8_t j = 0; j < 4; j++) |
| hudakz | 1:b869674fe56e | 76 | { |
| hudakz | 0:e076052bcffd | 77 | encoded >>= 2; |
| hudakz | 0:e076052bcffd | 78 | if (data & 0b00000001) |
| hudakz | 0:e076052bcffd | 79 | encoded |= 0b01000000; // 1->0 |
| hudakz | 0:e076052bcffd | 80 | else |
| hudakz | 0:e076052bcffd | 81 | encoded |= 0b10000000; // 0->1 |
| hudakz | 0:e076052bcffd | 82 | data >>= 1; |
| hudakz | 0:e076052bcffd | 83 | } |
| hudakz | 1:b869674fe56e | 84 | |
| hudakz | 0:e076052bcffd | 85 | _serial.putc(encoded); |
| hudakz | 0:e076052bcffd | 86 | } |
| hudakz | 0:e076052bcffd | 87 | } |
| hudakz | 0:e076052bcffd | 88 | |
| hudakz | 0:e076052bcffd | 89 | /** |
| hudakz | 0:e076052bcffd | 90 | * @brief Receives message |
| hudakz | 0:e076052bcffd | 91 | * @note Waits until a message is received or error occured |
| hudakz | 0:e076052bcffd | 92 | * @param msg Container to store the received message in |
| hudakz | 0:e076052bcffd | 93 | * @retval true On success |
| hudakz | 0:e076052bcffd | 94 | * false Otherwise |
| hudakz | 0:e076052bcffd | 95 | */ |
| hudakz | 1:b869674fe56e | 96 | bool ManchesterUART::receive(ManchesterMsg& msg) |
| hudakz | 1:b869674fe56e | 97 | { |
| hudakz | 1:b869674fe56e | 98 | uint8_t byte1, byte2; |
| hudakz | 1:b869674fe56e | 99 | bool byte1Received; |
| hudakz | 1:b869674fe56e | 100 | |
| hudakz | 0:e076052bcffd | 101 | _error = NO_ERROR; |
| hudakz | 0:e076052bcffd | 102 | _data = msg.data; |
| hudakz | 0:e076052bcffd | 103 | _len = 0; |
| hudakz | 0:e076052bcffd | 104 | _maxLen = msg.maxLen(); |
| hudakz | 1:b869674fe56e | 105 | |
| hudakz | 1:b869674fe56e | 106 | if (!_serial.readable()) |
| hudakz | 1:b869674fe56e | 107 | return false; |
| hudakz | 0:e076052bcffd | 108 | |
| hudakz | 1:b869674fe56e | 109 | _timeout.attach(callback(this, &ManchesterUART::rxTimeout), _rxTimeout); |
| hudakz | 1:b869674fe56e | 110 | |
| hudakz | 1:b869674fe56e | 111 | // |
| hudakz | 1:b869674fe56e | 112 | // wait for START pattern |
| hudakz | 0:e076052bcffd | 113 | do { |
| hudakz | 1:b869674fe56e | 114 | byte1 = _serial.getc(); |
| hudakz | 1:b869674fe56e | 115 | if (_error) |
| hudakz | 1:b869674fe56e | 116 | { |
| hudakz | 1:b869674fe56e | 117 | if (_error != RX_TIMEOUT) |
| hudakz | 1:b869674fe56e | 118 | _timeout.detach(); |
| hudakz | 1:b869674fe56e | 119 | msg.len = 0; |
| hudakz | 1:b869674fe56e | 120 | return false; |
| hudakz | 1:b869674fe56e | 121 | } |
| hudakz | 1:b869674fe56e | 122 | } while (byte1 != START); |
| hudakz | 1:b869674fe56e | 123 | // |
| hudakz | 1:b869674fe56e | 124 | // read START pattern |
| hudakz | 1:b869674fe56e | 125 | do { |
| hudakz | 1:b869674fe56e | 126 | byte1 = _serial.getc(); |
| hudakz | 1:b869674fe56e | 127 | if (_error) |
| hudakz | 1:b869674fe56e | 128 | { |
| hudakz | 0:e076052bcffd | 129 | if (_error != RX_TIMEOUT) |
| hudakz | 0:e076052bcffd | 130 | _timeout.detach(); |
| hudakz | 0:e076052bcffd | 131 | msg.len = 0; |
| hudakz | 0:e076052bcffd | 132 | return false; |
| hudakz | 0:e076052bcffd | 133 | } |
| hudakz | 1:b869674fe56e | 134 | } while (byte1 == START); |
| hudakz | 1:b869674fe56e | 135 | |
| hudakz | 1:b869674fe56e | 136 | byte1Received = true; // byte1 available from the loop above |
| hudakz | 1:b869674fe56e | 137 | |
| hudakz | 1:b869674fe56e | 138 | while (true) |
| hudakz | 1:b869674fe56e | 139 | { |
| hudakz | 1:b869674fe56e | 140 | if (byte1Received) |
| hudakz | 1:b869674fe56e | 141 | byte1Received = false; |
| hudakz | 1:b869674fe56e | 142 | else |
| hudakz | 1:b869674fe56e | 143 | { |
| hudakz | 1:b869674fe56e | 144 | byte1 = _serial.getc(); |
| hudakz | 1:b869674fe56e | 145 | if (byte1 == STOP) |
| hudakz | 1:b869674fe56e | 146 | break; |
| hudakz | 1:b869674fe56e | 147 | if (_len > _maxLen - 1) |
| hudakz | 1:b869674fe56e | 148 | { |
| hudakz | 1:b869674fe56e | 149 | _error = BUF_OVERRUN; |
| hudakz | 1:b869674fe56e | 150 | break; |
| hudakz | 1:b869674fe56e | 151 | } |
| hudakz | 1:b869674fe56e | 152 | } |
| hudakz | 1:b869674fe56e | 153 | |
| hudakz | 1:b869674fe56e | 154 | byte2 = _serial.getc(); |
| hudakz | 1:b869674fe56e | 155 | if (byte2 == STOP) |
| hudakz | 1:b869674fe56e | 156 | { |
| hudakz | 1:b869674fe56e | 157 | _error = ILLEGAL_CODE; |
| hudakz | 0:e076052bcffd | 158 | break; |
| hudakz | 0:e076052bcffd | 159 | } |
| hudakz | 1:b869674fe56e | 160 | |
| hudakz | 1:b869674fe56e | 161 | _data[_len++] = (getNibble(byte1)) | (getNibble(byte2) << 4); |
| hudakz | 1:b869674fe56e | 162 | if (_error) |
| hudakz | 0:e076052bcffd | 163 | break; |
| hudakz | 0:e076052bcffd | 164 | } |
| hudakz | 1:b869674fe56e | 165 | |
| hudakz | 0:e076052bcffd | 166 | if (_error != RX_TIMEOUT) |
| hudakz | 0:e076052bcffd | 167 | _timeout.detach(); |
| hudakz | 0:e076052bcffd | 168 | |
| hudakz | 1:b869674fe56e | 169 | if (_error) |
| hudakz | 1:b869674fe56e | 170 | { |
| hudakz | 0:e076052bcffd | 171 | msg.len = 0; |
| hudakz | 0:e076052bcffd | 172 | return false; |
| hudakz | 0:e076052bcffd | 173 | } |
| hudakz | 1:b869674fe56e | 174 | else |
| hudakz | 1:b869674fe56e | 175 | { |
| hudakz | 0:e076052bcffd | 176 | msg.len = _len; |
| hudakz | 0:e076052bcffd | 177 | return true; |
| hudakz | 0:e076052bcffd | 178 | } |
| hudakz | 0:e076052bcffd | 179 | } |
| hudakz | 0:e076052bcffd | 180 | |
| hudakz | 0:e076052bcffd | 181 | /** |
| hudakz | 0:e076052bcffd | 182 | * @brief ISR handling 'reception timeout' |
| hudakz | 0:e076052bcffd | 183 | * @note Called when receiving a message takes longer than limit. |
| hudakz | 0:e076052bcffd | 184 | * Signals 'timeout error' by setting error flag. |
| hudakz | 0:e076052bcffd | 185 | * @param |
| hudakz | 0:e076052bcffd | 186 | * @retval |
| hudakz | 0:e076052bcffd | 187 | */ |
| hudakz | 1:b869674fe56e | 188 | void ManchesterUART::rxTimeout(void) |
| hudakz | 1:b869674fe56e | 189 | { |
| hudakz | 0:e076052bcffd | 190 | _timeout.detach(); |
| hudakz | 0:e076052bcffd | 191 | _error = RX_TIMEOUT; |
| hudakz | 0:e076052bcffd | 192 | } |
| hudakz | 0:e076052bcffd | 193 | |
| hudakz | 0:e076052bcffd | 194 | /** |
| hudakz | 0:e076052bcffd | 195 | * @brief Gets a nibble of received byte |
| hudakz | 0:e076052bcffd | 196 | * @note Checks for illegal codes/patterns |
| hudakz | 1:b869674fe56e | 197 | * @param nibble A byte received over UART (Manchester encoded nibble) |
| hudakz | 0:e076052bcffd | 198 | * @retval Decoded nibble |
| hudakz | 0:e076052bcffd | 199 | */ |
| hudakz | 1:b869674fe56e | 200 | uint8_t ManchesterUART::getNibble(uint8_t encoded) |
| hudakz | 1:b869674fe56e | 201 | { |
| hudakz | 0:e076052bcffd | 202 | uint8_t decoded, pattern; |
| hudakz | 0:e076052bcffd | 203 | |
| hudakz | 0:e076052bcffd | 204 | decoded = 0; |
| hudakz | 1:b869674fe56e | 205 | for (int i = 0; i < 4; i++) |
| hudakz | 1:b869674fe56e | 206 | { |
| hudakz | 0:e076052bcffd | 207 | decoded >>= 1; |
| hudakz | 1:b869674fe56e | 208 | pattern = encoded & 0b000011; |
| hudakz | 1:b869674fe56e | 209 | if (pattern == 0b00000001) // 1 |
| hudakz | 1:b869674fe56e | 210 | decoded |= (0b00000001 << 3); |
| hudakz | 0:e076052bcffd | 211 | else |
| hudakz | 1:b869674fe56e | 212 | if (pattern == 0b00000010) // 0 |
| hudakz | 1:b869674fe56e | 213 | decoded &= ~(0b00000001 << 3); |
| hudakz | 1:b869674fe56e | 214 | else |
| hudakz | 1:b869674fe56e | 215 | { |
| hudakz | 0:e076052bcffd | 216 | _error = ILLEGAL_CODE; |
| hudakz | 0:e076052bcffd | 217 | break; |
| hudakz | 0:e076052bcffd | 218 | } |
| hudakz | 1:b869674fe56e | 219 | |
| hudakz | 0:e076052bcffd | 220 | encoded >>= 2; |
| hudakz | 0:e076052bcffd | 221 | } |
| hudakz | 1:b869674fe56e | 222 | |
| hudakz | 0:e076052bcffd | 223 | return decoded; |
| hudakz | 0:e076052bcffd | 224 | } |