Manchester code (phase encoding) library.

Dependents:   Manchester_Transmitter Manchester_Receiver

Manchester code (phase encoding) library

It implements Manchester code according to both IEEE 802.3 and G.E. Thomas' conventions.

  • A '0' is expressed by a high-to-low transition, a '1' by low-to-high transition in the IEEE 802.3 convention. The reverse is true in the G.E. Thomas' convention.
  • The transitions which signify '0' or '1' occur at the midpoint of a period.
  • Transitions at the start of a period are overhead and don't signify data.
  • Least significant bit is sent first
  • There are synchronization pulses (the number can be set) at the begin of transmission

    Select a convention to be used by commenting or uncommenting the line below in the Manchester.h header file.

Manchester.h

#define G_E_THOMAS 1

The IEEE 802.3 convention is used by default.

A Manchester encoded message (using G.E. Thomas' convention), with one sync pulse in the preamble, carrying four bytes:

/media/uploads/hudakz/manchester01.png

ACKNOWLEDGEMENT: The code in this library was based on this article published by Robert Guastella.

Import programManchester_Transmitter

Manchester transmitter demo.


Import programManchester_Receiver

Manchester receiver demo.

NOTE: To perform a simple test (without radio modules) connect the txPin on transmitter board to the rxPin on the receiver board and make sure that grounds are also connected one another.

Committer:
hudakz
Date:
Thu May 18 13:37:21 2017 +0000
Revision:
4:f2c392191c74
Parent:
3:03109c995123
Child:
5:3b2c7e9fda3f
Updated.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:d5c75b0e5708 1 /*
hudakz 0:d5c75b0e5708 2 ******************************************************************************
hudakz 0:d5c75b0e5708 3 * @file Manchester.cpp
hudakz 0:d5c75b0e5708 4 * @author Zoltan Hudak
hudakz 2:de778df5892c 5 * @version
hudakz 0:d5c75b0e5708 6 * @date 16-May-2017
hudakz 0:d5c75b0e5708 7 * @brief Manchester code for mbed
hudakz 0:d5c75b0e5708 8 ******************************************************************************
hudakz 0:d5c75b0e5708 9 * @attention
hudakz 0:d5c75b0e5708 10 *
hudakz 0:d5c75b0e5708 11 * <h2><center>&copy; COPYRIGHT(c) 2017 Zoltan Hudak <hudakz@outlook.com>
hudakz 0:d5c75b0e5708 12 *
hudakz 0:d5c75b0e5708 13 * All rights reserved.
hudakz 0:d5c75b0e5708 14
hudakz 0:d5c75b0e5708 15 This program is free software: you can redistribute it and/or modify
hudakz 0:d5c75b0e5708 16 it under the terms of the GNU General Public License as published by
hudakz 0:d5c75b0e5708 17 the Free Software Foundation, either version 3 of the License, or
hudakz 0:d5c75b0e5708 18 (at your option) any later version.
hudakz 0:d5c75b0e5708 19
hudakz 0:d5c75b0e5708 20 This program is distributed in the hope that it will be useful,
hudakz 0:d5c75b0e5708 21 but WITHOUT ANY WARRANTY; without even the implied warranty of
hudakz 0:d5c75b0e5708 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
hudakz 0:d5c75b0e5708 23 GNU General Public License for more details.
hudakz 0:d5c75b0e5708 24
hudakz 0:d5c75b0e5708 25 You should have received a copy of the GNU General Public License
hudakz 0:d5c75b0e5708 26 along with this program. If not, see <http://www.gnu.org/licenses/>.
hudakz 0:d5c75b0e5708 27 */
hudakz 0:d5c75b0e5708 28 #include "Manchester.h"
hudakz 0:d5c75b0e5708 29 #include "ManchesterMsg.h"
hudakz 0:d5c75b0e5708 30
hudakz 0:d5c75b0e5708 31 /**
hudakz 0:d5c75b0e5708 32 * @brief Creates a Manchester object
hudakz 0:d5c75b0e5708 33 * @note
hudakz 0:d5c75b0e5708 34 * @param txPin Pin name of transmitter line
hudakz 0:d5c75b0e5708 35 * rxPin Pin name of receiver line
hudakz 0:d5c75b0e5708 36 * speed Communication bit rate in bits per second
hudakz 3:03109c995123 37 * tol Pulse width tolerance in %
hudakz 0:d5c75b0e5708 38 * @retval
hudakz 0:d5c75b0e5708 39 */
hudakz 3:03109c995123 40 Manchester::Manchester
hudakz 3:03109c995123 41 (
hudakz 3:03109c995123 42 PinName txPin,
hudakz 3:03109c995123 43 PinName rxPin,
hudakz 3:03109c995123 44 uint32_t speed /* = 1200 bps */,
hudakz 4:f2c392191c74 45 uint8_t tol /* = 20% */
hudakz 3:03109c995123 46 ) :
hudakz 3:03109c995123 47 _tx(txPin),
hudakz 2:de778df5892c 48 _rx(rxPin) {
hudakz 0:d5c75b0e5708 49 _state = IDLE;
hudakz 0:d5c75b0e5708 50 _midBitTime = 1000000 / speed / 2; // mid-bit time [us]
hudakz 0:d5c75b0e5708 51 _minPulseWidth = (_midBitTime * 2 * (100 - tol)) / 100; // [us]
hudakz 0:d5c75b0e5708 52 _maxPulseWidth = (_midBitTime * 2 * (100 + tol)) / 100; // [us]
hudakz 0:d5c75b0e5708 53 _rx.disable_irq();
hudakz 0:d5c75b0e5708 54 _rx.rise(callback(this, &Manchester::reception));
hudakz 0:d5c75b0e5708 55 _rx.fall(callback(this, &Manchester::reception));
hudakz 0:d5c75b0e5708 56 }
hudakz 0:d5c75b0e5708 57
hudakz 0:d5c75b0e5708 58 /**
hudakz 0:d5c75b0e5708 59 * @brief Transmits message
hudakz 0:d5c75b0e5708 60 * @note
hudakz 0:d5c75b0e5708 61 * @param msg Message to transmit
hudakz 0:d5c75b0e5708 62 * @retval
hudakz 0:d5c75b0e5708 63 */
hudakz 0:d5c75b0e5708 64 void Manchester::transmit(ManchesterMsg& msg) {
hudakz 0:d5c75b0e5708 65 bool txComplete;
hudakz 0:d5c75b0e5708 66
hudakz 0:d5c75b0e5708 67 _data = msg.data;
hudakz 0:d5c75b0e5708 68 _len = msg.len;
hudakz 0:d5c75b0e5708 69 _state = SYNCH_START;
hudakz 0:d5c75b0e5708 70 _txTicker.attach_us(callback(this, &Manchester::transmission), _midBitTime);
hudakz 0:d5c75b0e5708 71
hudakz 0:d5c75b0e5708 72 do
hudakz 0:d5c75b0e5708 73 {
hudakz 0:d5c75b0e5708 74 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 75 txComplete = (_state == IDLE);
hudakz 0:d5c75b0e5708 76 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 77 } while(!txComplete);
hudakz 0:d5c75b0e5708 78
hudakz 0:d5c75b0e5708 79 _txTicker.detach();
hudakz 0:d5c75b0e5708 80 }
hudakz 0:d5c75b0e5708 81
hudakz 0:d5c75b0e5708 82 /**
hudakz 0:d5c75b0e5708 83 * @brief ISR handling transmission
hudakz 3:03109c995123 84 * @note Called by _txTicker
hudakz 0:d5c75b0e5708 85 * @param
hudakz 0:d5c75b0e5708 86 * @retval
hudakz 0:d5c75b0e5708 87 */
hudakz 0:d5c75b0e5708 88 void Manchester::transmission(void) {
hudakz 0:d5c75b0e5708 89 static uint8_t encodeByte;
hudakz 2:de778df5892c 90 static size_t byteIndex;
hudakz 0:d5c75b0e5708 91 static uint8_t bitIndex;
hudakz 0:d5c75b0e5708 92
hudakz 2:de778df5892c 93 _timeout.attach_us(callback(this, &Manchester::txTimeout), _maxPulseWidth * 4);
hudakz 2:de778df5892c 94
hudakz 0:d5c75b0e5708 95 switch(_state) {
hudakz 0:d5c75b0e5708 96 case SYNCH_START:
hudakz 0:d5c75b0e5708 97 _tx = 0; // pull the line low to start synch pulse
hudakz 0:d5c75b0e5708 98 _state = SYNCH_NEXT;
hudakz 0:d5c75b0e5708 99 break;
hudakz 0:d5c75b0e5708 100
hudakz 0:d5c75b0e5708 101 case SYNCH_NEXT:
hudakz 0:d5c75b0e5708 102 _state = SYNCH_END; // synch pulse needs to be twice the interrupt rate
hudakz 0:d5c75b0e5708 103 break;
hudakz 0:d5c75b0e5708 104
hudakz 0:d5c75b0e5708 105 case SYNCH_END:
hudakz 2:de778df5892c 106 _tx = 1; // bring line high for end of sych pulse
hudakz 0:d5c75b0e5708 107 byteIndex = 0;
hudakz 0:d5c75b0e5708 108 encodeByte = _data[byteIndex];
hudakz 0:d5c75b0e5708 109 bitIndex = 0;
hudakz 0:d5c75b0e5708 110 _state = SETUP;
hudakz 0:d5c75b0e5708 111 break;
hudakz 0:d5c75b0e5708 112
hudakz 0:d5c75b0e5708 113 case SETUP:
hudakz 0:d5c75b0e5708 114 if(encodeByte & 0x01)
hudakz 0:d5c75b0e5708 115 _tx = (encodeByte & 0x01) | _tx; // next bit to transmit is a "1"
hudakz 0:d5c75b0e5708 116 else
hudakz 0:d5c75b0e5708 117 _tx = (encodeByte & 0x01) & _tx; // next bit to transmit is a "0"
hudakz 0:d5c75b0e5708 118 _state = TRANSITION;
hudakz 0:d5c75b0e5708 119 break;
hudakz 0:d5c75b0e5708 120
hudakz 0:d5c75b0e5708 121 case TRANSITION:
hudakz 2:de778df5892c 122 _tx = (encodeByte & 0x01) ^ 0x01; // set line appropriately for transition
hudakz 0:d5c75b0e5708 123 if(++bitIndex < 8) {
hudakz 0:d5c75b0e5708 124 encodeByte = (encodeByte >> 1);
hudakz 0:d5c75b0e5708 125 _state = SETUP;
hudakz 0:d5c75b0e5708 126 }
hudakz 0:d5c75b0e5708 127 else {
hudakz 0:d5c75b0e5708 128 if(++byteIndex < _len) {
hudakz 0:d5c75b0e5708 129 encodeByte = _data[byteIndex];
hudakz 0:d5c75b0e5708 130 _state = SETUP;
hudakz 0:d5c75b0e5708 131 bitIndex = 0;
hudakz 0:d5c75b0e5708 132 }
hudakz 0:d5c75b0e5708 133 else
hudakz 0:d5c75b0e5708 134 _state = COMPLETE;
hudakz 0:d5c75b0e5708 135 }
hudakz 0:d5c75b0e5708 136 break;
hudakz 0:d5c75b0e5708 137
hudakz 0:d5c75b0e5708 138 case COMPLETE:
hudakz 2:de778df5892c 139 _tx = 1; // transmission is complete, bring line high
hudakz 0:d5c75b0e5708 140 _state = IDLE;
hudakz 0:d5c75b0e5708 141 break;
hudakz 0:d5c75b0e5708 142
hudakz 0:d5c75b0e5708 143 case IDLE:
hudakz 0:d5c75b0e5708 144 default:
hudakz 2:de778df5892c 145 _timeout.detach();
hudakz 0:d5c75b0e5708 146 return;
hudakz 0:d5c75b0e5708 147 }
hudakz 0:d5c75b0e5708 148 }
hudakz 0:d5c75b0e5708 149
hudakz 0:d5c75b0e5708 150 /**
hudakz 2:de778df5892c 151 * @brief ISR handling 'transmission timeout'
hudakz 2:de778df5892c 152 * @note Called when transmitter is stuck.
hudakz 2:de778df5892c 153 * Signals 'end of transmission' by setting state to IDLE
hudakz 2:de778df5892c 154 * @param None
hudakz 2:de778df5892c 155 * @retval None
hudakz 2:de778df5892c 156 */
hudakz 2:de778df5892c 157 void Manchester::txTimeout(void) {
hudakz 2:de778df5892c 158 _timeout.detach();
hudakz 2:de778df5892c 159 _state = IDLE;
hudakz 2:de778df5892c 160 }
hudakz 2:de778df5892c 161
hudakz 2:de778df5892c 162 /**
hudakz 0:d5c75b0e5708 163 * @brief Receives message
hudakz 4:f2c392191c74 164 * @note Waits until a message is received or 'receive timeout' occured
hudakz 1:11292d238e50 165 * @param msg Container to store the received message
hudakz 0:d5c75b0e5708 166 * @retval true On success
hudakz 0:d5c75b0e5708 167 * false Otherwise
hudakz 0:d5c75b0e5708 168 */
hudakz 0:d5c75b0e5708 169 bool Manchester::receive(ManchesterMsg& msg) {
hudakz 0:d5c75b0e5708 170 bool rxFinished;
hudakz 0:d5c75b0e5708 171 uint32_t now = us_ticker_read();
hudakz 0:d5c75b0e5708 172
hudakz 0:d5c75b0e5708 173 _data = msg.data;
hudakz 0:d5c75b0e5708 174 _maxLen = msg.maxLen();
hudakz 0:d5c75b0e5708 175 _state = LISTEN;
hudakz 0:d5c75b0e5708 176
hudakz 0:d5c75b0e5708 177 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 178 _rx.enable_irq();
hudakz 0:d5c75b0e5708 179 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 180
hudakz 0:d5c75b0e5708 181 do
hudakz 0:d5c75b0e5708 182 {
hudakz 0:d5c75b0e5708 183 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 184 rxFinished = ((_state == IDLE) || (_state == ERROR));
hudakz 0:d5c75b0e5708 185 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 186 } while(!rxFinished);
hudakz 0:d5c75b0e5708 187
hudakz 0:d5c75b0e5708 188 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 189 _rx.disable_irq();
hudakz 0:d5c75b0e5708 190 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 191
hudakz 0:d5c75b0e5708 192 if(_state == ERROR) {
hudakz 0:d5c75b0e5708 193 msg.len = 0;
hudakz 0:d5c75b0e5708 194 _state = IDLE;
hudakz 0:d5c75b0e5708 195 return false;
hudakz 0:d5c75b0e5708 196 }
hudakz 0:d5c75b0e5708 197 else {
hudakz 0:d5c75b0e5708 198 msg.len = _len;
hudakz 0:d5c75b0e5708 199 return true;
hudakz 0:d5c75b0e5708 200 }
hudakz 0:d5c75b0e5708 201 }
hudakz 0:d5c75b0e5708 202
hudakz 0:d5c75b0e5708 203 /**
hudakz 2:de778df5892c 204 * @brief ISR handling reception
hudakz 2:de778df5892c 205 * @note Called on signal change (rise or fall) on receiver line
hudakz 0:d5c75b0e5708 206 * @param
hudakz 0:d5c75b0e5708 207 * @retval
hudakz 0:d5c75b0e5708 208 */
hudakz 0:d5c75b0e5708 209 void Manchester::reception(void) {
hudakz 0:d5c75b0e5708 210 uint32_t now = us_ticker_read();
hudakz 0:d5c75b0e5708 211 static uint32_t begin;
hudakz 0:d5c75b0e5708 212 uint32_t pulseWidth;
hudakz 0:d5c75b0e5708 213 static uint8_t decodeByte;
hudakz 0:d5c75b0e5708 214 static uint8_t bitIndex;
hudakz 0:d5c75b0e5708 215
hudakz 2:de778df5892c 216 _timeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 4);
hudakz 2:de778df5892c 217
hudakz 0:d5c75b0e5708 218 switch(_state) {
hudakz 0:d5c75b0e5708 219 case LISTEN:
hudakz 0:d5c75b0e5708 220 begin = now;
hudakz 2:de778df5892c 221 if(_rx == 0)
hudakz 0:d5c75b0e5708 222 _state = SYNCH_START;
hudakz 0:d5c75b0e5708 223 else
hudakz 3:03109c995123 224 _state = ERROR; // It isn't a synch pulse => error
hudakz 0:d5c75b0e5708 225 break;
hudakz 0:d5c75b0e5708 226
hudakz 0:d5c75b0e5708 227 case SYNCH_START:
hudakz 0:d5c75b0e5708 228 pulseWidth = now - begin;
hudakz 2:de778df5892c 229 if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth) && (_rx == 1)) {
hudakz 0:d5c75b0e5708 230 begin = now;
hudakz 0:d5c75b0e5708 231 decodeByte = 0;
hudakz 2:de778df5892c 232 bitIndex = 0;
hudakz 0:d5c75b0e5708 233 _len = 0;
hudakz 0:d5c75b0e5708 234 _state = DECODE;
hudakz 0:d5c75b0e5708 235 }
hudakz 2:de778df5892c 236 else
hudakz 2:de778df5892c 237 _state = ERROR; // It isn't a synch pulse => error
hudakz 0:d5c75b0e5708 238 break;
hudakz 0:d5c75b0e5708 239
hudakz 0:d5c75b0e5708 240 case DECODE:
hudakz 0:d5c75b0e5708 241 pulseWidth = now - begin;
hudakz 0:d5c75b0e5708 242 if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth)) {
hudakz 0:d5c75b0e5708 243 begin = now;
hudakz 0:d5c75b0e5708 244 decodeByte |= (((_rx == 0) & 0x01) << bitIndex++);
hudakz 0:d5c75b0e5708 245 if(bitIndex > 7) {
hudakz 0:d5c75b0e5708 246 _data[_len++] = decodeByte;
hudakz 0:d5c75b0e5708 247 if(_len > _maxLen - 1)
hudakz 0:d5c75b0e5708 248 _state = ERROR;
hudakz 0:d5c75b0e5708 249 else {
hudakz 0:d5c75b0e5708 250 decodeByte = 0;
hudakz 0:d5c75b0e5708 251 bitIndex = 0;
hudakz 0:d5c75b0e5708 252 }
hudakz 0:d5c75b0e5708 253 }
hudakz 0:d5c75b0e5708 254 }
hudakz 0:d5c75b0e5708 255
hudakz 2:de778df5892c 256 if(pulseWidth > _maxPulseWidth)
hudakz 2:de778df5892c 257 _state = ERROR; // Pulse width out of limit => error
hudakz 0:d5c75b0e5708 258
hudakz 0:d5c75b0e5708 259 break;
hudakz 0:d5c75b0e5708 260
hudakz 0:d5c75b0e5708 261 case IDLE:
hudakz 0:d5c75b0e5708 262 case ERROR:
hudakz 0:d5c75b0e5708 263 default:
hudakz 2:de778df5892c 264 _timeout.detach();
hudakz 0:d5c75b0e5708 265 break;
hudakz 0:d5c75b0e5708 266 }
hudakz 0:d5c75b0e5708 267 }
hudakz 0:d5c75b0e5708 268
hudakz 0:d5c75b0e5708 269 /**
hudakz 2:de778df5892c 270 * @brief ISR handling 'receive timeout'
hudakz 3:03109c995123 271 * @note Called when receiver line is idle longer than limit.
hudakz 2:de778df5892c 272 * Signals 'end of transmission' by setting state to IDLE
hudakz 2:de778df5892c 273 * or 'timeout error' by setting state to ERROR.
hudakz 0:d5c75b0e5708 274 * @param None
hudakz 0:d5c75b0e5708 275 * @retval None
hudakz 0:d5c75b0e5708 276 */
hudakz 0:d5c75b0e5708 277 void Manchester::rxTimeout(void) {
hudakz 2:de778df5892c 278 _timeout.detach();
hudakz 0:d5c75b0e5708 279
hudakz 2:de778df5892c 280 if((_state == DECODE) && (_rx == 1))
hudakz 0:d5c75b0e5708 281 _state = IDLE; // End of transmission
hudakz 0:d5c75b0e5708 282 else
hudakz 0:d5c75b0e5708 283 _state = ERROR; // Incomplete transmission
hudakz 0:d5c75b0e5708 284 }