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 theManchester.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:
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, committed 2018-10-14
- 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
--- 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>© 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