Library for Manchester encoding using UART's hardware.
Dependents: ManchesterUART_Transmitter ManchesterUART_Receiver
Manchester encoding using UART's hardware
This library implements Manchester code using UART. Each data byte is encoded into two bytes representing two nibbles of the original data. UART's hardware is then used to generate the Manchester encoded bit stream. Prior to decoding, the receiver converts the received bit stream to bytes using its UART. Start and stop patterns are sent to identify the boundaries (begin and end) of a data frame.
ACKNOWLEDGEMENT: The library is based on an article published by Adrian Mills.
Import programManchesterUART_Transmitter
Transmitter demo for the Manchester encoding library using UART's hardware.
Import programManchesterUART_Receiver
Receiver demo for the Manchester encoding library using UART's hardware.
NOTE: To perform a simple test (without radio link) connect the txPin on transmitter board to the rxPin on the receiver board and make sure that grounds are also connected one another.
ManchesterUART.cpp@2:8cb6a0a77e56, 2018-10-17 (annotated)
- Committer:
- hudakz
- Date:
- Wed Oct 17 16:16:34 2018 +0000
- Revision:
- 2:8cb6a0a77e56
- Parent:
- 1:b869674fe56e
Number of start patterns in preamble can be set.
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 | } |
hudakz | 2:8cb6a0a77e56 | 225 |