Manchester
Revision 8:c1b5893191fe, committed 2018-10-14
- Comitter:
- hudakz
- Date:
- Sun Oct 14 09:38:33 2018 +0000
- Parent:
- 7:afd0ee36dcd1
- Child:
- 9:7a23184aa9ef
- 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