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 07:52:15 2017 +0000
Revision:
0:d5c75b0e5708
Child:
1:11292d238e50
Initial issue.

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 0:d5c75b0e5708 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
hudakz 0:d5c75b0e5708 29 #include "Manchester.h"
hudakz 0:d5c75b0e5708 30 #include "ManchesterMsg.h"
hudakz 0:d5c75b0e5708 31
hudakz 0:d5c75b0e5708 32 /**
hudakz 0:d5c75b0e5708 33 * @brief Creates a Manchester object
hudakz 0:d5c75b0e5708 34 * @note
hudakz 0:d5c75b0e5708 35 * @param txPin Pin name of transmitter line
hudakz 0:d5c75b0e5708 36 * rxPin Pin name of receiver line
hudakz 0:d5c75b0e5708 37 * speed Communication bit rate in bits per second
hudakz 0:d5c75b0e5708 38 * tol Pulse width tolerance in %
hudakz 0:d5c75b0e5708 39 * @retval
hudakz 0:d5c75b0e5708 40 */
hudakz 0:d5c75b0e5708 41 Manchester::Manchester
hudakz 0:d5c75b0e5708 42 (
hudakz 0:d5c75b0e5708 43 PinName txPin,
hudakz 0:d5c75b0e5708 44 PinName rxPin,
hudakz 0:d5c75b0e5708 45 uint32_t speed /* = 1200 bps */,
hudakz 0:d5c75b0e5708 46 uint8_t tol /* = 20% */
hudakz 0:d5c75b0e5708 47 ) :
hudakz 0:d5c75b0e5708 48 _tx(txPin), _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 0:d5c75b0e5708 84 * @note Called by the rxTicker
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 0:d5c75b0e5708 90 static uint32_t byteIndex;
hudakz 0:d5c75b0e5708 91 static uint8_t bitIndex;
hudakz 0:d5c75b0e5708 92
hudakz 0:d5c75b0e5708 93 switch(_state) {
hudakz 0:d5c75b0e5708 94 case SYNCH_START:
hudakz 0:d5c75b0e5708 95 _tx = 0; // pull the line low to start synch pulse
hudakz 0:d5c75b0e5708 96 _state = SYNCH_NEXT;
hudakz 0:d5c75b0e5708 97 break;
hudakz 0:d5c75b0e5708 98
hudakz 0:d5c75b0e5708 99 case SYNCH_NEXT:
hudakz 0:d5c75b0e5708 100 _state = SYNCH_END; // synch pulse needs to be twice the interrupt rate
hudakz 0:d5c75b0e5708 101 break;
hudakz 0:d5c75b0e5708 102
hudakz 0:d5c75b0e5708 103 case SYNCH_END:
hudakz 0:d5c75b0e5708 104 _tx = 1; // bring line hight for end of sych pulse
hudakz 0:d5c75b0e5708 105 byteIndex = 0;
hudakz 0:d5c75b0e5708 106 encodeByte = _data[byteIndex];
hudakz 0:d5c75b0e5708 107 bitIndex = 0;
hudakz 0:d5c75b0e5708 108 _state = SETUP;
hudakz 0:d5c75b0e5708 109 break;
hudakz 0:d5c75b0e5708 110
hudakz 0:d5c75b0e5708 111 case SETUP:
hudakz 0:d5c75b0e5708 112 if(encodeByte & 0x01)
hudakz 0:d5c75b0e5708 113 _tx = (encodeByte & 0x01) | _tx; // next bit to transmit is a "1"
hudakz 0:d5c75b0e5708 114 else
hudakz 0:d5c75b0e5708 115 _tx = (encodeByte & 0x01) & _tx; // next bit to transmit is a "0"
hudakz 0:d5c75b0e5708 116 _state = TRANSITION;
hudakz 0:d5c75b0e5708 117 break;
hudakz 0:d5c75b0e5708 118
hudakz 0:d5c75b0e5708 119 case TRANSITION:
hudakz 0:d5c75b0e5708 120 _tx = (encodeByte & 0x01) ^ 0x01; // set line appropriately for transition
hudakz 0:d5c75b0e5708 121 if(++bitIndex < 8) {
hudakz 0:d5c75b0e5708 122 encodeByte = (encodeByte >> 1);
hudakz 0:d5c75b0e5708 123 _state = SETUP;
hudakz 0:d5c75b0e5708 124 }
hudakz 0:d5c75b0e5708 125 else {
hudakz 0:d5c75b0e5708 126 if(++byteIndex < _len) {
hudakz 0:d5c75b0e5708 127 encodeByte = _data[byteIndex];
hudakz 0:d5c75b0e5708 128 _state = SETUP;
hudakz 0:d5c75b0e5708 129 bitIndex = 0;
hudakz 0:d5c75b0e5708 130 }
hudakz 0:d5c75b0e5708 131 else
hudakz 0:d5c75b0e5708 132 _state = COMPLETE;
hudakz 0:d5c75b0e5708 133 }
hudakz 0:d5c75b0e5708 134 break;
hudakz 0:d5c75b0e5708 135
hudakz 0:d5c75b0e5708 136 case COMPLETE:
hudakz 0:d5c75b0e5708 137 _tx = 1; // transition is complete, bring line high
hudakz 0:d5c75b0e5708 138 _state = IDLE;
hudakz 0:d5c75b0e5708 139 break;
hudakz 0:d5c75b0e5708 140
hudakz 0:d5c75b0e5708 141 case IDLE:
hudakz 0:d5c75b0e5708 142 default:
hudakz 0:d5c75b0e5708 143 return;
hudakz 0:d5c75b0e5708 144 }
hudakz 0:d5c75b0e5708 145 }
hudakz 0:d5c75b0e5708 146
hudakz 0:d5c75b0e5708 147 /**
hudakz 0:d5c75b0e5708 148 * @brief Receives message
hudakz 0:d5c75b0e5708 149 * @note
hudakz 0:d5c75b0e5708 150 * @param msg A container to store the received message
hudakz 0:d5c75b0e5708 151 * @retval true On success
hudakz 0:d5c75b0e5708 152 * false Otherwise
hudakz 0:d5c75b0e5708 153 */
hudakz 0:d5c75b0e5708 154 bool Manchester::receive(ManchesterMsg& msg) {
hudakz 0:d5c75b0e5708 155 bool rxFinished;
hudakz 0:d5c75b0e5708 156 uint32_t now = us_ticker_read();
hudakz 0:d5c75b0e5708 157
hudakz 0:d5c75b0e5708 158 _data = msg.data;
hudakz 0:d5c75b0e5708 159 _maxLen = msg.maxLen();
hudakz 0:d5c75b0e5708 160 _state = LISTEN;
hudakz 0:d5c75b0e5708 161
hudakz 0:d5c75b0e5708 162 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 163 _rx.enable_irq();
hudakz 0:d5c75b0e5708 164 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 165
hudakz 0:d5c75b0e5708 166 do
hudakz 0:d5c75b0e5708 167 {
hudakz 0:d5c75b0e5708 168 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 169 rxFinished = ((_state == IDLE) || (_state == ERROR));
hudakz 0:d5c75b0e5708 170 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 171 } while(!rxFinished);
hudakz 0:d5c75b0e5708 172
hudakz 0:d5c75b0e5708 173 core_util_critical_section_enter();
hudakz 0:d5c75b0e5708 174 _rx.disable_irq();
hudakz 0:d5c75b0e5708 175 core_util_critical_section_exit();
hudakz 0:d5c75b0e5708 176
hudakz 0:d5c75b0e5708 177 if(_state == ERROR) {
hudakz 0:d5c75b0e5708 178 msg.len = 0;
hudakz 0:d5c75b0e5708 179 _state = IDLE;
hudakz 0:d5c75b0e5708 180 return false;
hudakz 0:d5c75b0e5708 181 }
hudakz 0:d5c75b0e5708 182 else {
hudakz 0:d5c75b0e5708 183 msg.len = _len;
hudakz 0:d5c75b0e5708 184 return true;
hudakz 0:d5c75b0e5708 185 }
hudakz 0:d5c75b0e5708 186 }
hudakz 0:d5c75b0e5708 187
hudakz 0:d5c75b0e5708 188 /**
hudakz 0:d5c75b0e5708 189 * @brief ISR to handle reception
hudakz 0:d5c75b0e5708 190 * @note Called on rise or fall on receiver line
hudakz 0:d5c75b0e5708 191 * @param
hudakz 0:d5c75b0e5708 192 * @retval
hudakz 0:d5c75b0e5708 193 */
hudakz 0:d5c75b0e5708 194 void Manchester::reception(void) {
hudakz 0:d5c75b0e5708 195 uint32_t now = us_ticker_read();
hudakz 0:d5c75b0e5708 196 static uint32_t begin;
hudakz 0:d5c75b0e5708 197 uint32_t pulseWidth;
hudakz 0:d5c75b0e5708 198 static uint8_t decodeByte;
hudakz 0:d5c75b0e5708 199 static uint8_t bitIndex;
hudakz 0:d5c75b0e5708 200
hudakz 0:d5c75b0e5708 201 switch(_state) {
hudakz 0:d5c75b0e5708 202 case LISTEN:
hudakz 0:d5c75b0e5708 203 begin = now;
hudakz 0:d5c75b0e5708 204 if(_rx == 0) {
hudakz 0:d5c75b0e5708 205 _state = SYNCH_START;
hudakz 0:d5c75b0e5708 206 _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
hudakz 0:d5c75b0e5708 207 }
hudakz 0:d5c75b0e5708 208 else
hudakz 0:d5c75b0e5708 209 _state = ERROR;
hudakz 0:d5c75b0e5708 210 break;
hudakz 0:d5c75b0e5708 211
hudakz 0:d5c75b0e5708 212 case SYNCH_START:
hudakz 0:d5c75b0e5708 213 pulseWidth = now - begin;
hudakz 0:d5c75b0e5708 214 if((pulseWidth > _maxPulseWidth) | (_rx == 0))
hudakz 0:d5c75b0e5708 215 _state = ERROR;
hudakz 0:d5c75b0e5708 216 else {
hudakz 0:d5c75b0e5708 217 begin = now;
hudakz 0:d5c75b0e5708 218 decodeByte = 0;
hudakz 0:d5c75b0e5708 219 _len = 0;
hudakz 0:d5c75b0e5708 220 bitIndex = 0;
hudakz 0:d5c75b0e5708 221 _state = DECODE;
hudakz 0:d5c75b0e5708 222 _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
hudakz 0:d5c75b0e5708 223 }
hudakz 0:d5c75b0e5708 224 break;
hudakz 0:d5c75b0e5708 225
hudakz 0:d5c75b0e5708 226 case DECODE:
hudakz 0:d5c75b0e5708 227 pulseWidth = now - begin;
hudakz 0:d5c75b0e5708 228 if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth)) {
hudakz 0:d5c75b0e5708 229 begin = now;
hudakz 0:d5c75b0e5708 230 decodeByte |= (((_rx == 0) & 0x01) << bitIndex++);
hudakz 0:d5c75b0e5708 231 if(bitIndex > 7) {
hudakz 0:d5c75b0e5708 232 _data[_len++] = decodeByte;
hudakz 0:d5c75b0e5708 233 if(_len > _maxLen - 1)
hudakz 0:d5c75b0e5708 234 _state = ERROR;
hudakz 0:d5c75b0e5708 235 else {
hudakz 0:d5c75b0e5708 236 decodeByte = 0;
hudakz 0:d5c75b0e5708 237 bitIndex = 0;
hudakz 0:d5c75b0e5708 238 }
hudakz 0:d5c75b0e5708 239 }
hudakz 0:d5c75b0e5708 240 }
hudakz 0:d5c75b0e5708 241
hudakz 0:d5c75b0e5708 242 if(pulseWidth > _maxPulseWidth) {
hudakz 0:d5c75b0e5708 243 _state = ERROR;
hudakz 0:d5c75b0e5708 244 }
hudakz 0:d5c75b0e5708 245 else
hudakz 0:d5c75b0e5708 246 _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
hudakz 0:d5c75b0e5708 247
hudakz 0:d5c75b0e5708 248 break;
hudakz 0:d5c75b0e5708 249
hudakz 0:d5c75b0e5708 250 case IDLE:
hudakz 0:d5c75b0e5708 251 case ERROR:
hudakz 0:d5c75b0e5708 252 default:
hudakz 0:d5c75b0e5708 253 break;
hudakz 0:d5c75b0e5708 254 }
hudakz 0:d5c75b0e5708 255 }
hudakz 0:d5c75b0e5708 256
hudakz 0:d5c75b0e5708 257 /**
hudakz 0:d5c75b0e5708 258 * @brief ISR to handle receive timeout
hudakz 0:d5c75b0e5708 259 * @note Signals end of transmission by setting state to IDLE
hudakz 0:d5c75b0e5708 260 * or timeout error by setting state to ERROR.
hudakz 0:d5c75b0e5708 261 * @param None
hudakz 0:d5c75b0e5708 262 * @retval None
hudakz 0:d5c75b0e5708 263 */
hudakz 0:d5c75b0e5708 264 void Manchester::rxTimeout(void) {
hudakz 0:d5c75b0e5708 265 _rxTimeout.detach();
hudakz 0:d5c75b0e5708 266
hudakz 0:d5c75b0e5708 267 if(_state == DECODE)
hudakz 0:d5c75b0e5708 268 _state = IDLE; // End of transmission
hudakz 0:d5c75b0e5708 269 else
hudakz 0:d5c75b0e5708 270 _state = ERROR; // Incomplete transmission
hudakz 0:d5c75b0e5708 271 }
hudakz 0:d5c75b0e5708 272