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.

Files at this revision

API Documentation at this revision

Comitter:
hudakz
Date:
Sun Oct 14 09:38:33 2018 +0000
Parent:
7:afd0ee36dcd1
Commit message:
Number of sync pulses in preamble can be set.

Changed in this revision

Manchester.cpp Show annotated file Show diff for this revision Revisions of this file
Manchester.h Show annotated file Show diff for this revision Revisions of this file
ManchesterMsg.h Show diff for this revision Revisions of this file
--- a/Manchester.cpp	Sun Sep 03 09:04:18 2017 +0000
+++ b/Manchester.cpp	Sun Oct 14 09:38:33 2018 +0000
@@ -25,7 +25,6 @@
  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-
 /*
    This library implements Manchester code according to both IEEE 802.3
    and G.E. Thomas' conventions.
@@ -40,7 +39,6 @@
    Select a convention to be used by commenting or uncommenting
    the line "#define G_E_THOMAS 1" in the Manchester.h header file.
  */
-
 #include "Manchester.h"
 #include "ManchesterMsg.h"
 
@@ -54,21 +52,29 @@
  * @retval
  */
 Manchester::Manchester
-    (
-        PinName     txPin,
-        PinName     rxPin,
-        uint32_t    speed, /* = 1200 bps */
-        uint8_t     tol    /* = (+/-)25% */
-    ) :
+(
+    PinName     txPin,
+    PinName     rxPin,
+    uint32_t    baudrate,   /* = 1200 bps */
+    uint8_t     tol,        /* = (+/-)25% */
+    float       rxTimeout   /* = 5s */
+) :
     _tx(txPin),
-    _rx(rxPin) {
+    _rx(rxPin)
+{
     _state = IDLE;
-    _midBitTime = 1000000 / speed / 2;  // mid-bit time [us]
+    _midBitTime = 1000000 / baudrate / 2;                   // mid-bit time [us]
     _minPulseWidth = (_midBitTime * 2 * (100 - tol)) / 100; // [us]
     _maxPulseWidth = (_midBitTime * 2 * (100 + tol)) / 100; // [us]
+    _rxTimeout = rxTimeout;
     _rx.disable_irq();
     _rx.rise(callback(this, &Manchester::reception));
     _rx.fall(callback(this, &Manchester::reception));
+    _preamble = 8;                                          // number of synch_start patterns
+    _error = "no error";
+    //    printf("_midBitTime    = %d\r\n", _midBitTime);
+    //    printf("_minPulseWidth = %d\r\n", _minPulseWidth);
+    //    printf("_maxPulseWidth = %d\r\n", _maxPulseWidth);
 #ifdef G_E_THOMAS
     _tx = 1;
 #else
@@ -82,7 +88,8 @@
  * @param   msg Message to transmit
  * @retval
  */
-void Manchester::transmit(ManchesterMsg& msg) {
+void Manchester::transmit(ManchesterMsg& msg)
+{
     bool    txFinished;
 
     _data = msg.data;
@@ -94,7 +101,7 @@
         core_util_critical_section_enter();
         txFinished = (_state == IDLE);
         core_util_critical_section_exit();
-    } while(!txFinished);
+    } while (!txFinished);
 
     _txTicker.detach();
 }
@@ -105,82 +112,124 @@
  * @param
  * @retval
  */
-void Manchester::transmission(void) {
+void Manchester::transmission(void)
+{
     static uint8_t  encodeByte;
     static size_t   byteIndex;
     static uint8_t  bitIndex;
+    static uint8_t  counter;
 
-    _timeout.attach_us(callback(this, &Manchester::txTimeout), _maxPulseWidth * 4);
+    _timeout.attach_us(callback(this, &Manchester::onTxTimeout), _maxPulseWidth * 4);
 
-    switch(_state) {
-    case SYNCH_START:
-#ifdef G_E_THOMAS
-        _tx = 0;            // pull line low to start synch pulse
-#else
-        _tx = 1;            // bring line high to start synch pulse
-#endif
-        _state = SYNCH_NEXT;
-        break;
+    switch (_state)
+    {
+        case SYNCH_START:
+            if (_preamble == 0)
+            {
+                byteIndex = 0;
+                encodeByte = _data[byteIndex];
+                bitIndex = 0;
+                _state = SETUP;
+                break;
+            }
 
-    case SYNCH_NEXT:
-        _state = SYNCH_END; // synch pulse needs to be twice the interrupt rate
-        break;
+    #ifdef G_E_THOMAS
+            _tx = 0;                    // pull line low to start synch pulse
+    #else
+            _tx = 1;                    // bring line high to start synch pulse
+    #endif
+            counter = 0;
+            _state = SYNCH_NEXT;
+            break;
 
-    case SYNCH_END:
-#ifdef G_E_THOMAS
-        _tx = 1;            // bring line high for end of sych pulse
-#else
-        _tx = 0;            // pull line low for end of sych pulse
-#endif
-        byteIndex = 0;
-        encodeByte = _data[byteIndex];
-        bitIndex = 0;
-        _state = SETUP;
-        break;
+        case SYNCH_NEXT:
+            counter++;
+            if ((counter % 4) == 0)
+                _tx = !_tx;
+            if (counter < (_preamble * 8))
+                break;
+            else
+            {
+                byteIndex = 0;
+                encodeByte = _data[byteIndex];
+                bitIndex = 0;
+                _state = SETUP;
+                break;
+            }
 
-    case SETUP:
-#ifdef G_E_THOMAS
-        _tx = encodeByte & 0x01;    // setup for next bit to transmit
-#else
-        _tx = !(encodeByte & 0x01); // setup for next bit to transmit
-#endif
-        _state = TRANSITION;
-        break;
+        case SETUP:
+    #ifdef G_E_THOMAS
+            _tx = encodeByte & 0x01;    // setup for next bit to transmit
+    #else
+            _tx = !(encodeByte & 0x01); // setup for next bit to transmit
+    #endif
+            _state = TRANSITION;
+            break;
 
-    case TRANSITION:
-#ifdef G_E_THOMAS
-        _tx = !(encodeByte & 0x01); // set line appropriately for transition
-#else
-        _tx = encodeByte & 0x01;    // set line appropriately for transition
-#endif
-        if(++bitIndex < 8) {
-            encodeByte = (encodeByte >> 1);
-            _state = SETUP;
-        }
-        else {
-            if(++byteIndex < _len) {
-                encodeByte = _data[byteIndex];
+        case TRANSITION:
+    #ifdef G_E_THOMAS
+            _tx = !(encodeByte & 0x01); // set line appropriately for transition
+    #else
+            _tx = encodeByte & 0x01;    // set line appropriately for transition
+    #endif
+            if (++bitIndex < 8)
+            {
+                encodeByte = (encodeByte >> 1);
                 _state = SETUP;
-                bitIndex = 0;
             }
             else
-                _state = COMPLETE;
-        }
-        break;
+            {
+                if (++byteIndex < _len)
+                {
+                    encodeByte = _data[byteIndex];
+                    _state = SETUP;
+                    bitIndex = 0;
+                }
+                else
+                {
+                    counter = 0;
+                    _state = STOP;
+                }
+            }
+            break;
 
-    case COMPLETE:
-#ifdef G_E_THOMAS
-        _tx = 1;    // transmission is complete, bring line high
-#else
-        _tx = 0;    // transmission is complete, pull line low
-#endif
-        _state = IDLE;
-        break;
+        case STOP:
+            counter++;
+            if (counter == 1)
+            {
+    #ifdef G_E_THOMAS
+                _tx = 1;
+    #else
+                _tx = 0;
+    #endif
+            }
+            else
+            if (counter == 5)
+            {
+    #ifdef G_E_THOMAS
+                _tx = 0;
+    #else
+                _tx = 1;
+    #endif
+            }
+            else
+            if (counter == 8)
+                _state = COMPLETE;
+            break;
 
-    case IDLE:
-    default:
-        _timeout.detach();
-        return;
+        case COMPLETE:
+    #ifdef G_E_THOMAS
+            _tx = 1;
+    #else
+            _tx = 0;
+    #endif
+            _state = IDLE;
+            break;
+
+        case IDLE:
+        default:
+            _timeout.detach();
+            return;
     }
 }
 
@@ -191,7 +240,8 @@
  * @param
  * @retval
  */
-void Manchester::txTimeout(void) {
+void Manchester::onTxTimeout(void)
+{
     _timeout.detach();
     _state = IDLE;
 }
@@ -203,29 +253,34 @@
  * @retval  true  On success
  *          false Otherwise
  */
-bool Manchester::receive(ManchesterMsg& msg) {
-    bool        rxFinished;
+bool Manchester::receive(ManchesterMsg& msg)
+{
+    bool    rxFinished;
 
     _data = msg.data;
     _maxLen = msg.maxLen();
     _state = LISTEN;
-
+    _timeout.attach(callback(this, &Manchester::onRxTimeout), _rxTimeout);
     _rx.enable_irq();
 
     do {
         core_util_critical_section_enter();
         rxFinished = ((_state == IDLE) || (_state == ERROR));
         core_util_critical_section_exit();
-    } while(!rxFinished);
+    } while (!rxFinished);
 
     _rx.disable_irq();
+    _timer.stop();
+    _timeout.detach();
 
-    if(_state == ERROR) {
+    if (_state == ERROR)
+    {
         msg.len = 0;
         _state = IDLE;
         return false;
     }
-    else {
+    else
+    {
         msg.len = _len;
         return true;
     }
@@ -237,75 +292,136 @@
  * @param
  * @retval
  */
-void Manchester::reception(void) {
+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;
 
-    _timeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 4);
-
-    switch(_state) {
-    case LISTEN:
-        begin = now;
-#ifdef G_E_THOMAS
-        if(_rx == 0)
-#else
-        if(_rx == 1)
-#endif
-            _state = SYNCH_START;
-        else
-            _state = ERROR;  // It isn't a synch pulse => error
-        break;
-
-    case SYNCH_START:
-        pulseWidth = now - begin;
-#ifdef G_E_THOMAS
-        if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth) && (_rx == 1)) {
-#else
-        if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth) && (_rx == 0)) {
-#endif
+    switch (_state)
+    {
+        case LISTEN:
             begin = now;
-            decodeByte = 0;
-            bitIndex = 0;
-            _len = 0;
-            _state = DECODE;
-        }
-        else
-            _state = ERROR; // It isn't a synch pulse => error
-        break;
+            if (
+    #ifdef G_E_THOMAS
+            _rx == 0
+    #else
+            _rx == 1
+    #endif
+            )
+            {
+                _state = SYNCH_START;
+            }
+            else
+            {
+                _error = "SYNCH_START: Isn't a SYNCH pulse";
+                _state = ERROR;
+            }
+            break;
+
+        case SYNCH_START:
+            pulseWidth = now - begin;
+            //printf("%d <= %d <= %d\r\n", (_midBitTime * 2) + _minPulseWidth, pulseWidth, (_midBitTime * 2) + _maxPulseWidth);
+            if (((_midBitTime * 2) + _minPulseWidth <= pulseWidth) && (pulseWidth <= (_midBitTime * 2) + _maxPulseWidth))
+            {
+                begin = now;
+                _state = SYNCH_NEXT;
+            }
+            else
+            {
+                _error = "SYNCH_START: Isn't a SYNCH pulse";
+                _state = ERROR;
+            }
+            break;
 
-    case DECODE:
-        pulseWidth = now - begin;
-        if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth)) {
-            begin = now;
-#ifdef G_E_THOMAS
-            decodeByte |= (((_rx == 0) & 0x01) << bitIndex++);
-#else
-            decodeByte |= (((_rx == 1) & 0x01) << bitIndex++);
-#endif
-            if(bitIndex > 7) {
-                _data[_len++] = decodeByte;
-                if(_len > _maxLen - 1)
-                    _state = ERROR;
-                else {
-                    decodeByte = 0;
-                    bitIndex = 0;
+        case SYNCH_NEXT:
+            pulseWidth = now - begin;
+            //printf("%d <= %d <= %d\r\n", (_midBitTime * 2) + _minPulseWidth, pulseWidth, (_midBitTime * 2) + _maxPulseWidth);
+            if (((_midBitTime * 2) + _minPulseWidth <= pulseWidth) && (pulseWidth <= (_midBitTime * 2) + _maxPulseWidth))
+            {
+                begin = now;
+                _state = SYNCH_NEXT;
+            }
+            else
+            if ((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth))
+            {
+                begin = now;
+                decodeByte = 0;
+                bitIndex = 0;
+                _len = 0;
+    #ifdef G_E_THOMAS
+                decodeByte |= (((_rx == 0) & 0x01) << bitIndex++);
+    #else
+                decodeByte |= (((_rx == 1) & 0x01) << bitIndex++);
+    #endif
+                _state = DECODE;
+            }
+            break;
+
+        case DECODE:
+            pulseWidth = now - begin;
+            if ((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth))
+            {
+                begin = now;
+    #ifdef G_E_THOMAS
+                decodeByte |= (((_rx == 0) & 0x01) << bitIndex++);
+    #else
+                decodeByte |= (((_rx == 1) & 0x01) << bitIndex++);
+    #endif
+                if (bitIndex > 7)
+                {
+                    _data[_len++] = decodeByte;
+                    if (_len > _maxLen - 1)
+                        _state = ERROR;
+                    else
+                    {
+                        decodeByte = 0;
+                        bitIndex = 0;
+                    }
+                }
+                break;
+            }
+
+            if (pulseWidth > _maxPulseWidth)
+            {
+                if (
+    #ifdef G_E_THOMAS
+                _rx == 0
+    #else
+                _rx == 1
+    #endif
+                )
+                {
+                    begin = now;
+                    _state = COMPLETE;  // End of reception
                 }
             }
-        }
-
-        if(pulseWidth > _maxPulseWidth)
-            _state = ERROR; // Pulse width out of limit => error
+            break;
 
-        break;
+        case COMPLETE:
+            pulseWidth = now - begin;
+            if (pulseWidth > _maxPulseWidth)
+            {
+                if (
+    #ifdef G_E_THOMAS
+                _rx == 1
+    #else
+                _rx == 0
+    #endif
+                )
+                {
+                    _state = IDLE;  // End of reception
+                }
+            }
+            break;
 
-    case IDLE:
-    case ERROR:
-    default:
-        _timeout.detach();
-        break;
+        case IDLE:
+        case ERROR:
+        default:
+            _timeout.detach();
+            break;
     }
 }
 
@@ -317,15 +433,22 @@
  * @param
  * @retval
  */
-void Manchester::rxTimeout(void) {
+void Manchester::onRxTimeout(void)
+{
     _timeout.detach();
 
 #ifdef G_E_THOMAS
-    if((_state == DECODE) && (_rx == 1))
+    if ((_state == DECODE) && (_rx == 1))
 #else
-    if((_state == DECODE) && (_rx == 0))
+        if ((_state == DECODE) && (_rx == 0))
 #endif
-        _state = IDLE;  // Reception successful
-    else
-        _state = ERROR; // Reception incomplete
+        {
+            _error = "rx timeout";
+            _state = IDLE;  // Reception successful
+        }
+        else
+        {
+            _error = "reception error";
+            _state = ERROR; // Reception incomplete
+        }
 }
--- a/Manchester.h	Sun Sep 03 09:04:18 2017 +0000
+++ b/Manchester.h	Sun Oct 14 09:38:33 2018 +0000
@@ -25,7 +25,6 @@
  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-
 /*
    This library implements Manchester code according to both IEEE 802.3 
    and G.E. Thomas' conventions. 
@@ -40,15 +39,14 @@
    Select a convention to be used by commenting or uncommenting 
    the line "#define G_E_THOMAS 1" below. 
 */
-
 #ifndef MANCHESTER_H
 #define MANCHESTER_H
 
 #include "mbed.h"
 #include "ManchesterMsg.h"
 
+//Uncomment the following line to use G.E.Thomas' convention
 
-//Uncomment the following line to use G.E.Thomas' convention
 //#define G_E_THOMAS 1
 
 class   Manchester
@@ -63,40 +61,46 @@
         TRANSITION,
         COMPLETE,
         LISTEN,
+        DECODE_START,
         DECODE,
+        STOP,
         ERROR
     };
-
 public:
     Manchester
     (
         PinName     txPin,          /* transmitter pin name */
         PinName     rxPin,          /* receiver pin name */
         uint32_t    speed = 1200,   /* speed in bits per second */
-        uint8_t     tol   = 25      /* pulse width tolerance (+/-) in % */
+        uint8_t     tol = 25,       /* pulse width tolerance (+/-) in % */
+        float       rxTimeout = 5   /* receive timeout */
     );
-    ~Manchester(void) { }
+    ~       Manchester(void)    { }
     void    transmit(ManchesterMsg& msg);
     bool    receive(ManchesterMsg& msg);
-
+    void    setPreamble(uint8_t preamble)   { _preamble = preamble; }
+    void    setRxTimeout(float seconds)     { _rxTimeout = seconds; }
+    char*   lastError()                     { return _error; }
 private:
-    DigitalOut  _tx;            // transmitter line
-    InterruptIn _rx;            // receiver line
-    Ticker      _txTicker;      // transmitter ticker
-    Timeout     _timeout;       // timeout (watchdog)
-    uint32_t    _midBitTime;    // mid-bit time [us]
-    uint32_t    _minPulseWidth; // minimum pulse width [us]
-    uint32_t    _maxPulseWidth; // maximum pulse width [us]
-    State       _state;         // state
-    char*       _data;          // data array
-    size_t      _len;           // data length in bytes
-    size_t      _maxLen;        // maximum length
-
+    DigitalOut  _tx;                // transmitter line
+    InterruptIn _rx;                // receiver line
+    Ticker      _txTicker;          // transmitter ticker
+    Timeout     _timeout;           // timeout (watchdog)
+    Timer       _timer;
+    uint32_t    _midBitTime;        // mid-bit time [us]
+    uint32_t    _minPulseWidth;     // minimum pulse width [us]
+    uint32_t    _maxPulseWidth;     // maximum pulse width [us]
+    uint32_t    _tol;
+    float       _rxTimeout;         // reception timeout [s]
+    State       _state;             // state
+    char*       _data;              // data array
+    size_t      _len;               // data length in bytes
+    size_t      _maxLen;            // maximum length
+    size_t      _preamble;          // number of start patterns
+    char*       _error;
     void        transmission(void);
     void        reception(void);
-    void        txTimeout(void);
-    void        rxTimeout(void);
+    void        onTxTimeout(void);
+    void        onRxTimeout(void);
 };
 #endif // MANCHESTER_H
-
-
--- a/ManchesterMsg.h	Sun Sep 03 09:04:18 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-/*
- ******************************************************************************
- * @file    ManchesterMsg.h
- * @author  Zoltan Hudak
- * @version
- * @date    2017-May-16
- * @brief   Message container
- ******************************************************************************
- * @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/>.
- */
-#ifndef MANCHESTERMSG_H
-#define MANCHESTERMSG_H
-
-//#define DEBUG 1
-
-/** ManchesterMsg class
- */
-class   ManchesterMsg
-{
-    size_t  _max;   // Max length (capacity) of data field in bytes
-
-public:
-    char*   data;   // Data field
-    size_t  len;    // Length of data in bytes
-
-    /** Creates empty message of specified capacity.
-     */
-    ManchesterMsg(size_t max) : _max(max), data(new char[max]) { len = 0; }
-
-    ~ ManchesterMsg(void)   { delete[] data; }
-
-    /** Copy constructor.
-     */
-    ManchesterMsg(const ManchesterMsg& msg) { len = msg.len; memcpy(data, msg.data, msg.len); }
-
-    /** Returns message maximum length (capacity)
-     */
-    size_t  maxLen(void)    { return _max; }
-
-    /** Clears message content
-     */
-    void    clear(void)     { len = 0; memset(data, 0, _max); }
-
-    /** Inserter operator: Appends data (value) to message
-     */
-    template<class T>
-    ManchesterMsg &operator<<(const T val) {
-        if(len + sizeof(T) <= _max) {
-            *reinterpret_cast < T * > (&data[len]) = val;
-            len += sizeof(T);
-        }
-
-#if DEBUG
-        else {
-            printf("Error: Cannot append data. Exceeding max data length!\r\n");
-        }
-#endif
-        return *this;
-    }
-
-    /** Inserter operator: Appends array of char to message
-     */
-    ManchesterMsg &operator<<(const char* str) {
-        size_t  strLen = strlen(str);
-        if(len + strLen + 1 <= _max) {
-            memcpy(data + len, (char*)str, strLen);
-            len += strLen;
-            data[len++] = '\0';
-        }
-
-#if DEBUG
-        else {
-            printf("Error: Cannot append data. Exceeding max data length!\r\n");
-        }
-#endif
-        return *this;
-    }
-
-    /** Extractor operator: Extracts data (value) from message
-     */
-    template<class T>
-    ManchesterMsg &operator>>(T& val) {
-        if(sizeof(T) <= len) {
-            val = *reinterpret_cast < T * > (&data[0]);
-            len -= sizeof(T);
-            memcpy(data, data + sizeof(T), len);
-        }
-
-#if DEBUG
-        else {
-            printf("Error: Cannot extract data. Exceeding data length!\r\n");
-        }
-#endif
-        return *this;
-    }
-
-    /** Extractor operator: Extracts array of char from message
-     */
-    ManchesterMsg &operator>>(char* str) {
-        size_t  strLen = strlen(data);
-        if(strLen <= len) {
-            memcpy(str, data, strLen + 1);
-            len -= (strLen + 1);
-            memcpy(data, data + strLen + 1, len);
-        }
-
-#if DEBUG
-        else {
-            printf("Error: Cannot extract data. Exceeding data length!\r\n");
-        }
-#endif
-        return *this;
-    }
-};
-#endif // MANCHESTERMSG_H