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:
8:c1b5893191fe
Parent:
7:afd0ee36dcd1
--- 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
+        }
 }