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:
Wed May 17 21:02:49 2017 +0000
Revision:
2:de778df5892c
Parent:
1:11292d238e50
Child:
3:03109c995123
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 2:de778df5892c 37 * tol Pulse width tolerance in %
hudakz 0:d5c75b0e5708 38 * @retval
hudakz 0:d5c75b0e5708 39 */
hudakz 2:de778df5892c 40 Manchester::Manchester(PinName txPin, PinName rxPin, uint32_t speed /* = 1200 bps */, uint8_t tol /* = 20% */ ) :
hudakz 2:de778df5892c 41 _tx(txPin),
hudakz 2:de778df5892c 42 _rx(rxPin) {
hudakz 0:d5c75b0e5708 43 _state = IDLE;
hudakz 0:d5c75b0e5708 44 _midBitTime = 1000000 / speed / 2; // mid-bit time [us]
hudakz 0:d5c75b0e5708 45 _minPulseWidth = (_midBitTime * 2 * (100 - tol)) / 100; // [us]
hudakz 0:d5c75b0e5708 46 _maxPulseWidth = (_midBitTime * 2 * (100 + tol)) / 100; // [us]
hudakz 0:d5c75b0e5708 47 _rx.disable_irq();
hudakz 0:d5c75b0e5708 48 _rx.rise(callback(this, &Manchester::reception));
hudakz 0:d5c75b0e5708 49 _rx.fall(callback(this, &Manchester::reception));
hudakz 0:d5c75b0e5708 50 }
hudakz 0:d5c75b0e5708 51
hudakz 0:d5c75b0e5708 52 /**
hudakz 0:d5c75b0e5708 53 * @brief Transmits message
hudakz 0:d5c75b0e5708 54 * @note
hudakz 0:d5c75b0e5708 55 * @param msg Message to transmit
hudakz 0:d5c75b0e5708 56 * @retval
hudakz 0:d5c75b0e5708 57 */
hudakz 0:d5c75b0e5708 58 void Manchester::transmit(ManchesterMsg& msg) {
hudakz 0:d5c75b0e5708 59 bool txComplete;
hudakz 0:d5c75b0e5708 60
hudakz 0:d5c75b0e5708 61 _data = msg.data;
hudakz 0:d5c75b0e5708 62 _len = msg.len;
hudakz 0:d5c75b0e5708 63 _state = SYNCH_START;
hudakz 0:d5c75b0e5708 64 _txTicker.attach_us(callback(this, &Manchester::transmission), _midBitTime);
hudakz 0:d5c75b0e5708 65
hudakz 0:d5c75b0e5708 66 do
hudakz 0:d5c75b0e5708 67 {
hudakz 0:d5c75b0e5708 68 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 69 txComplete = (_state == IDLE);
hudakz 0:d5c75b0e5708 70 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 71 } while(!txComplete);
hudakz 0:d5c75b0e5708 72
hudakz 0:d5c75b0e5708 73 _txTicker.detach();
hudakz 0:d5c75b0e5708 74 }
hudakz 0:d5c75b0e5708 75
hudakz 0:d5c75b0e5708 76 /**
hudakz 0:d5c75b0e5708 77 * @brief ISR handling transmission
hudakz 0:d5c75b0e5708 78 * @note Called by the rxTicker
hudakz 0:d5c75b0e5708 79 * @param
hudakz 0:d5c75b0e5708 80 * @retval
hudakz 0:d5c75b0e5708 81 */
hudakz 0:d5c75b0e5708 82 void Manchester::transmission(void) {
hudakz 0:d5c75b0e5708 83 static uint8_t encodeByte;
hudakz 2:de778df5892c 84 static size_t byteIndex;
hudakz 0:d5c75b0e5708 85 static uint8_t bitIndex;
hudakz 0:d5c75b0e5708 86
hudakz 2:de778df5892c 87 _timeout.attach_us(callback(this, &Manchester::txTimeout), _maxPulseWidth * 4);
hudakz 2:de778df5892c 88
hudakz 0:d5c75b0e5708 89 switch(_state) {
hudakz 0:d5c75b0e5708 90 case SYNCH_START:
hudakz 0:d5c75b0e5708 91 _tx = 0; // pull the line low to start synch pulse
hudakz 0:d5c75b0e5708 92 _state = SYNCH_NEXT;
hudakz 0:d5c75b0e5708 93 break;
hudakz 0:d5c75b0e5708 94
hudakz 0:d5c75b0e5708 95 case SYNCH_NEXT:
hudakz 0:d5c75b0e5708 96 _state = SYNCH_END; // synch pulse needs to be twice the interrupt rate
hudakz 0:d5c75b0e5708 97 break;
hudakz 0:d5c75b0e5708 98
hudakz 0:d5c75b0e5708 99 case SYNCH_END:
hudakz 2:de778df5892c 100 _tx = 1; // bring line high for end of sych pulse
hudakz 0:d5c75b0e5708 101 byteIndex = 0;
hudakz 0:d5c75b0e5708 102 encodeByte = _data[byteIndex];
hudakz 0:d5c75b0e5708 103 bitIndex = 0;
hudakz 0:d5c75b0e5708 104 _state = SETUP;
hudakz 0:d5c75b0e5708 105 break;
hudakz 0:d5c75b0e5708 106
hudakz 0:d5c75b0e5708 107 case SETUP:
hudakz 0:d5c75b0e5708 108 if(encodeByte & 0x01)
hudakz 0:d5c75b0e5708 109 _tx = (encodeByte & 0x01) | _tx; // next bit to transmit is a "1"
hudakz 0:d5c75b0e5708 110 else
hudakz 0:d5c75b0e5708 111 _tx = (encodeByte & 0x01) & _tx; // next bit to transmit is a "0"
hudakz 0:d5c75b0e5708 112 _state = TRANSITION;
hudakz 0:d5c75b0e5708 113 break;
hudakz 0:d5c75b0e5708 114
hudakz 0:d5c75b0e5708 115 case TRANSITION:
hudakz 2:de778df5892c 116 _tx = (encodeByte & 0x01) ^ 0x01; // set line appropriately for transition
hudakz 0:d5c75b0e5708 117 if(++bitIndex < 8) {
hudakz 0:d5c75b0e5708 118 encodeByte = (encodeByte >> 1);
hudakz 0:d5c75b0e5708 119 _state = SETUP;
hudakz 0:d5c75b0e5708 120 }
hudakz 0:d5c75b0e5708 121 else {
hudakz 0:d5c75b0e5708 122 if(++byteIndex < _len) {
hudakz 0:d5c75b0e5708 123 encodeByte = _data[byteIndex];
hudakz 0:d5c75b0e5708 124 _state = SETUP;
hudakz 0:d5c75b0e5708 125 bitIndex = 0;
hudakz 0:d5c75b0e5708 126 }
hudakz 0:d5c75b0e5708 127 else
hudakz 0:d5c75b0e5708 128 _state = COMPLETE;
hudakz 0:d5c75b0e5708 129 }
hudakz 0:d5c75b0e5708 130 break;
hudakz 0:d5c75b0e5708 131
hudakz 0:d5c75b0e5708 132 case COMPLETE:
hudakz 2:de778df5892c 133 _tx = 1; // transmission is complete, bring line high
hudakz 0:d5c75b0e5708 134 _state = IDLE;
hudakz 0:d5c75b0e5708 135 break;
hudakz 0:d5c75b0e5708 136
hudakz 0:d5c75b0e5708 137 case IDLE:
hudakz 0:d5c75b0e5708 138 default:
hudakz 2:de778df5892c 139 _timeout.detach();
hudakz 0:d5c75b0e5708 140 return;
hudakz 0:d5c75b0e5708 141 }
hudakz 0:d5c75b0e5708 142 }
hudakz 0:d5c75b0e5708 143
hudakz 0:d5c75b0e5708 144 /**
hudakz 2:de778df5892c 145 * @brief ISR handling 'transmission timeout'
hudakz 2:de778df5892c 146 * @note Called when transmitter is stuck.
hudakz 2:de778df5892c 147 * Signals 'end of transmission' by setting state to IDLE
hudakz 2:de778df5892c 148 * @param None
hudakz 2:de778df5892c 149 * @retval None
hudakz 2:de778df5892c 150 */
hudakz 2:de778df5892c 151 void Manchester::txTimeout(void) {
hudakz 2:de778df5892c 152 _timeout.detach();
hudakz 2:de778df5892c 153 _state = IDLE;
hudakz 2:de778df5892c 154 }
hudakz 2:de778df5892c 155
hudakz 2:de778df5892c 156 /**
hudakz 0:d5c75b0e5708 157 * @brief Receives message
hudakz 2:de778df5892c 158 * @note Waits until a message is received
hudakz 2:de778df5892c 159 * or receive timeout occured
hudakz 1:11292d238e50 160 * @param msg Container to store the received message
hudakz 0:d5c75b0e5708 161 * @retval true On success
hudakz 0:d5c75b0e5708 162 * false Otherwise
hudakz 0:d5c75b0e5708 163 */
hudakz 0:d5c75b0e5708 164 bool Manchester::receive(ManchesterMsg& msg) {
hudakz 0:d5c75b0e5708 165 bool rxFinished;
hudakz 0:d5c75b0e5708 166 uint32_t now = us_ticker_read();
hudakz 0:d5c75b0e5708 167
hudakz 0:d5c75b0e5708 168 _data = msg.data;
hudakz 0:d5c75b0e5708 169 _maxLen = msg.maxLen();
hudakz 0:d5c75b0e5708 170 _state = LISTEN;
hudakz 0:d5c75b0e5708 171
hudakz 0:d5c75b0e5708 172 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 173 _rx.enable_irq();
hudakz 0:d5c75b0e5708 174 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 175
hudakz 0:d5c75b0e5708 176 do
hudakz 0:d5c75b0e5708 177 {
hudakz 0:d5c75b0e5708 178 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 179 rxFinished = ((_state == IDLE) || (_state == ERROR));
hudakz 0:d5c75b0e5708 180 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 181 } while(!rxFinished);
hudakz 0:d5c75b0e5708 182
hudakz 0:d5c75b0e5708 183 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 184 _rx.disable_irq();
hudakz 0:d5c75b0e5708 185 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 186
hudakz 0:d5c75b0e5708 187 if(_state == ERROR) {
hudakz 0:d5c75b0e5708 188 msg.len = 0;
hudakz 0:d5c75b0e5708 189 _state = IDLE;
hudakz 0:d5c75b0e5708 190 return false;
hudakz 0:d5c75b0e5708 191 }
hudakz 0:d5c75b0e5708 192 else {
hudakz 0:d5c75b0e5708 193 msg.len = _len;
hudakz 0:d5c75b0e5708 194 return true;
hudakz 0:d5c75b0e5708 195 }
hudakz 0:d5c75b0e5708 196 }
hudakz 0:d5c75b0e5708 197
hudakz 0:d5c75b0e5708 198 /**
hudakz 2:de778df5892c 199 * @brief ISR handling reception
hudakz 2:de778df5892c 200 * @note Called on signal change (rise or fall) on receiver line
hudakz 0:d5c75b0e5708 201 * @param
hudakz 0:d5c75b0e5708 202 * @retval
hudakz 0:d5c75b0e5708 203 */
hudakz 0:d5c75b0e5708 204 void Manchester::reception(void) {
hudakz 0:d5c75b0e5708 205 uint32_t now = us_ticker_read();
hudakz 0:d5c75b0e5708 206 static uint32_t begin;
hudakz 0:d5c75b0e5708 207 uint32_t pulseWidth;
hudakz 0:d5c75b0e5708 208 static uint8_t decodeByte;
hudakz 0:d5c75b0e5708 209 static uint8_t bitIndex;
hudakz 0:d5c75b0e5708 210
hudakz 2:de778df5892c 211 _timeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 4);
hudakz 2:de778df5892c 212
hudakz 0:d5c75b0e5708 213 switch(_state) {
hudakz 0:d5c75b0e5708 214 case LISTEN:
hudakz 0:d5c75b0e5708 215 begin = now;
hudakz 2:de778df5892c 216 if(_rx == 0)
hudakz 0:d5c75b0e5708 217 _state = SYNCH_START;
hudakz 0:d5c75b0e5708 218 else
hudakz 0:d5c75b0e5708 219 _state = ERROR;
hudakz 0:d5c75b0e5708 220 break;
hudakz 0:d5c75b0e5708 221
hudakz 0:d5c75b0e5708 222 case SYNCH_START:
hudakz 0:d5c75b0e5708 223 pulseWidth = now - begin;
hudakz 2:de778df5892c 224 if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth) && (_rx == 1)) {
hudakz 0:d5c75b0e5708 225 begin = now;
hudakz 0:d5c75b0e5708 226 decodeByte = 0;
hudakz 2:de778df5892c 227 bitIndex = 0;
hudakz 0:d5c75b0e5708 228 _len = 0;
hudakz 0:d5c75b0e5708 229 _state = DECODE;
hudakz 0:d5c75b0e5708 230 }
hudakz 2:de778df5892c 231 else
hudakz 2:de778df5892c 232 _state = ERROR; // It isn't a synch pulse => error
hudakz 0:d5c75b0e5708 233 break;
hudakz 0:d5c75b0e5708 234
hudakz 0:d5c75b0e5708 235 case DECODE:
hudakz 0:d5c75b0e5708 236 pulseWidth = now - begin;
hudakz 0:d5c75b0e5708 237 if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth)) {
hudakz 0:d5c75b0e5708 238 begin = now;
hudakz 0:d5c75b0e5708 239 decodeByte |= (((_rx == 0) & 0x01) << bitIndex++);
hudakz 0:d5c75b0e5708 240 if(bitIndex > 7) {
hudakz 0:d5c75b0e5708 241 _data[_len++] = decodeByte;
hudakz 0:d5c75b0e5708 242 if(_len > _maxLen - 1)
hudakz 0:d5c75b0e5708 243 _state = ERROR;
hudakz 0:d5c75b0e5708 244 else {
hudakz 0:d5c75b0e5708 245 decodeByte = 0;
hudakz 0:d5c75b0e5708 246 bitIndex = 0;
hudakz 0:d5c75b0e5708 247 }
hudakz 0:d5c75b0e5708 248 }
hudakz 0:d5c75b0e5708 249 }
hudakz 0:d5c75b0e5708 250
hudakz 2:de778df5892c 251 if(pulseWidth > _maxPulseWidth)
hudakz 2:de778df5892c 252 _state = ERROR; // Pulse width out of limit => error
hudakz 0:d5c75b0e5708 253
hudakz 0:d5c75b0e5708 254 break;
hudakz 0:d5c75b0e5708 255
hudakz 0:d5c75b0e5708 256 case IDLE:
hudakz 0:d5c75b0e5708 257 case ERROR:
hudakz 0:d5c75b0e5708 258 default:
hudakz 2:de778df5892c 259 _timeout.detach();
hudakz 0:d5c75b0e5708 260 break;
hudakz 0:d5c75b0e5708 261 }
hudakz 0:d5c75b0e5708 262 }
hudakz 0:d5c75b0e5708 263
hudakz 0:d5c75b0e5708 264 /**
hudakz 2:de778df5892c 265 * @brief ISR handling 'receive timeout'
hudakz 2:de778df5892c 266 * @note Called when receiver line rxPin is idle longer than limit.
hudakz 2:de778df5892c 267 * Signals 'end of transmission' by setting state to IDLE
hudakz 2:de778df5892c 268 * or 'timeout error' by setting state to ERROR.
hudakz 0:d5c75b0e5708 269 * @param None
hudakz 0:d5c75b0e5708 270 * @retval None
hudakz 0:d5c75b0e5708 271 */
hudakz 0:d5c75b0e5708 272 void Manchester::rxTimeout(void) {
hudakz 2:de778df5892c 273 _timeout.detach();
hudakz 0:d5c75b0e5708 274
hudakz 2:de778df5892c 275 if((_state == DECODE) && (_rx == 1))
hudakz 0:d5c75b0e5708 276 _state = IDLE; // End of transmission
hudakz 0:d5c75b0e5708 277 else
hudakz 0:d5c75b0e5708 278 _state = ERROR; // Incomplete transmission
hudakz 0:d5c75b0e5708 279 }