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.

Revision:
0:d5c75b0e5708
Child:
1:11292d238e50
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Manchester.cpp	Wed May 17 07:52:15 2017 +0000
@@ -0,0 +1,272 @@
+/*
+ ******************************************************************************
+ * @file    Manchester.cpp
+ * @author  Zoltan Hudak
+ * @version 
+ * @date    16-May-2017
+ * @brief   Manchester code for mbed
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2017 Zoltan Hudak <hudakz@outlook.com>
+ *
+ * All rights reserved.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+  
+#include "Manchester.h"
+#include "ManchesterMsg.h"
+
+/**
+ * @brief   Creates a Manchester object
+ * @note
+ * @param   txPin Pin name of transmitter line
+ *          rxPin Pin name of receiver line
+ *          speed Communication bit rate in bits per second
+ *          tol Pulse width tolerance in %
+ * @retval
+ */
+Manchester::Manchester
+    (
+        PinName     txPin, 
+        PinName     rxPin, 
+        uint32_t    speed   /* = 1200 bps */, 
+        uint8_t     tol     /* = 20% */ 
+    ) :
+    _tx(txPin), _rx(rxPin) {
+    _state = IDLE;
+    _midBitTime = 1000000 / speed / 2;  // mid-bit time [us]
+    _minPulseWidth = (_midBitTime * 2 * (100 - tol)) / 100; // [us]
+    _maxPulseWidth = (_midBitTime * 2 * (100 + tol)) / 100; // [us]
+    _rx.disable_irq();
+    _rx.rise(callback(this, &Manchester::reception));
+    _rx.fall(callback(this, &Manchester::reception));
+}
+
+/**
+ * @brief   Transmits message
+ * @note
+ * @param   msg Message to transmit
+ * @retval
+ */
+void Manchester::transmit(ManchesterMsg& msg) {
+    bool    txComplete;
+
+    _data = msg.data;
+    _len = msg.len;
+    _state = SYNCH_START;
+    _txTicker.attach_us(callback(this, &Manchester::transmission), _midBitTime);
+
+    do
+    {
+        core_util_critical_section_enter();
+        txComplete = (_state == IDLE);
+        core_util_critical_section_exit();
+    } while(!txComplete);
+
+    _txTicker.detach();
+}
+
+/**
+ * @brief   ISR handling transmission
+ * @note    Called by the rxTicker
+ * @param
+ * @retval
+ */
+void Manchester::transmission(void) {
+    static uint8_t  encodeByte;
+    static uint32_t byteIndex;
+    static uint8_t  bitIndex;
+
+    switch(_state) {
+    case SYNCH_START:
+        _tx = 0;            // pull the line low to start synch pulse
+        _state = SYNCH_NEXT;
+        break;
+
+    case SYNCH_NEXT:
+        _state = SYNCH_END; // synch pulse needs to be twice the interrupt rate
+        break;
+
+    case SYNCH_END:
+        _tx = 1;            // bring line hight for end of sych pulse
+        byteIndex = 0;
+        encodeByte = _data[byteIndex];
+        bitIndex = 0;
+        _state = SETUP;
+        break;
+
+    case SETUP:
+        if(encodeByte & 0x01)
+            _tx = (encodeByte & 0x01) | _tx;    // next bit to transmit is a "1"
+        else
+            _tx = (encodeByte & 0x01) & _tx;    // next bit to transmit is a "0"
+        _state = TRANSITION;
+        break;
+
+    case TRANSITION:
+        _tx = (encodeByte & 0x01) ^ 0x01;  // set line appropriately for transition
+        if(++bitIndex < 8) {
+            encodeByte = (encodeByte >> 1);
+            _state = SETUP;
+        }
+        else {
+            if(++byteIndex < _len) {
+                encodeByte = _data[byteIndex];
+                _state = SETUP;
+                bitIndex = 0;
+            }
+            else
+                _state = COMPLETE;
+        }
+        break;
+
+    case COMPLETE:
+        _tx = 1;    // transition is complete, bring line high
+        _state = IDLE;
+        break;
+
+    case IDLE:
+    default:
+        return;
+    }
+}
+
+/**
+ * @brief   Receives message
+ * @note
+ * @param   msg A container to store the received message
+ * @retval  true  On success
+ *          false Otherwise
+ */
+bool Manchester::receive(ManchesterMsg& msg) {
+    bool        rxFinished;
+    uint32_t    now = us_ticker_read();
+
+    _data = msg.data;
+    _maxLen = msg.maxLen();
+    _state = LISTEN;
+
+    core_util_critical_section_enter();
+    _rx.enable_irq();
+    core_util_critical_section_exit();
+
+    do
+    {
+        core_util_critical_section_enter();
+        rxFinished = ((_state == IDLE) || (_state == ERROR));
+        core_util_critical_section_exit();
+    } while(!rxFinished);
+
+    core_util_critical_section_enter();
+    _rx.disable_irq();
+    core_util_critical_section_exit();
+
+    if(_state == ERROR) {
+        msg.len = 0;
+        _state = IDLE;
+        return false;
+    }
+    else {
+        msg.len = _len;
+        return true;
+    }
+}
+
+/**
+ * @brief   ISR to handle reception
+ * @note    Called on rise or fall on receiver line 
+ * @param
+ * @retval
+ */
+void Manchester::reception(void) {
+    uint32_t        now = us_ticker_read();
+    static uint32_t begin;
+    uint32_t        pulseWidth;
+    static uint8_t  decodeByte;
+    static uint8_t  bitIndex;
+
+    switch(_state) {
+    case LISTEN:
+        begin = now;
+        if(_rx == 0) {
+            _state = SYNCH_START;
+            _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
+        }
+        else
+            _state = ERROR;
+        break;
+
+    case SYNCH_START:
+        pulseWidth = now - begin;
+        if((pulseWidth > _maxPulseWidth) | (_rx == 0))
+            _state = ERROR;
+        else {
+            begin = now;
+            decodeByte = 0;
+            _len = 0;
+            bitIndex = 0;
+            _state = DECODE;
+            _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
+        }
+        break;
+
+    case DECODE:
+        pulseWidth = now - begin;
+        if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth)) {
+            begin = now;
+            decodeByte |= (((_rx == 0) & 0x01) << bitIndex++);
+            if(bitIndex > 7) {
+                _data[_len++] = decodeByte;
+                if(_len > _maxLen - 1)
+                    _state = ERROR;
+                else {
+                    decodeByte = 0;
+                    bitIndex = 0;
+                }
+            }
+        }
+
+        if(pulseWidth > _maxPulseWidth) {
+            _state = ERROR;
+        }
+        else
+            _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
+
+        break;
+
+    case IDLE:
+    case ERROR:
+    default:
+        break;
+    }
+}
+
+/**
+ * @brief   ISR to handle receive timeout
+ * @note    Signals end of transmission by setting state to IDLE
+ *          or timeout error by setting state to ERROR.
+ * @param   None
+ * @retval  None
+ */
+void Manchester::rxTimeout(void) {
+    _rxTimeout.detach();
+
+    if(_state == DECODE)
+        _state = IDLE;  // End of transmission
+    else
+        _state = ERROR; // Incomplete transmission
+}
+