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.
Diff: Manchester.cpp
- Revision:
- 8:c1b5893191fe
- Parent:
- 7:afd0ee36dcd1
diff -r afd0ee36dcd1 -r c1b5893191fe Manchester.cpp --- 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 + } }