Zoltan Hudak / ManchesterUART

Dependents:   ManchesterUART_Transmitter ManchesterUART_Receiver

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?

UserRevisionLine numberNew 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>&copy; 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 }