Manchester
Revision 0:d5c75b0e5708, committed 2017-05-17
- Comitter:
- hudakz
- Date:
- Wed May 17 07:52:15 2017 +0000
- Child:
- 1:11292d238e50
- Commit message:
- Initial issue.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Manchester.cpp Wed May 17 07:52:15 2017 +0000
@@ -0,0 +1,272 @@
+/*
+ ******************************************************************************
+ * @file Manchester.cpp
+ * @author Zoltan Hudak
+ * @version
+ * @date 16-May-2017
+ * @brief Manchester code for mbed
+ ******************************************************************************
+ * @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/>.
+ */
+
+#include "Manchester.h"
+#include "ManchesterMsg.h"
+
+/**
+ * @brief Creates a Manchester object
+ * @note
+ * @param txPin Pin name of transmitter line
+ * rxPin Pin name of receiver line
+ * speed Communication bit rate in bits per second
+ * tol Pulse width tolerance in %
+ * @retval
+ */
+Manchester::Manchester
+ (
+ PinName txPin,
+ PinName rxPin,
+ uint32_t speed /* = 1200 bps */,
+ uint8_t tol /* = 20% */
+ ) :
+ _tx(txPin), _rx(rxPin) {
+ _state = IDLE;
+ _midBitTime = 1000000 / speed / 2; // mid-bit time [us]
+ _minPulseWidth = (_midBitTime * 2 * (100 - tol)) / 100; // [us]
+ _maxPulseWidth = (_midBitTime * 2 * (100 + tol)) / 100; // [us]
+ _rx.disable_irq();
+ _rx.rise(callback(this, &Manchester::reception));
+ _rx.fall(callback(this, &Manchester::reception));
+}
+
+/**
+ * @brief Transmits message
+ * @note
+ * @param msg Message to transmit
+ * @retval
+ */
+void Manchester::transmit(ManchesterMsg& msg) {
+ bool txComplete;
+
+ _data = msg.data;
+ _len = msg.len;
+ _state = SYNCH_START;
+ _txTicker.attach_us(callback(this, &Manchester::transmission), _midBitTime);
+
+ do
+ {
+ core_util_critical_section_enter();
+ txComplete = (_state == IDLE);
+ core_util_critical_section_exit();
+ } while(!txComplete);
+
+ _txTicker.detach();
+}
+
+/**
+ * @brief ISR handling transmission
+ * @note Called by the rxTicker
+ * @param
+ * @retval
+ */
+void Manchester::transmission(void) {
+ static uint8_t encodeByte;
+ static uint32_t byteIndex;
+ static uint8_t bitIndex;
+
+ switch(_state) {
+ case SYNCH_START:
+ _tx = 0; // pull the line low to start synch pulse
+ _state = SYNCH_NEXT;
+ break;
+
+ case SYNCH_NEXT:
+ _state = SYNCH_END; // synch pulse needs to be twice the interrupt rate
+ break;
+
+ case SYNCH_END:
+ _tx = 1; // bring line hight for end of sych pulse
+ byteIndex = 0;
+ encodeByte = _data[byteIndex];
+ bitIndex = 0;
+ _state = SETUP;
+ break;
+
+ case SETUP:
+ if(encodeByte & 0x01)
+ _tx = (encodeByte & 0x01) | _tx; // next bit to transmit is a "1"
+ else
+ _tx = (encodeByte & 0x01) & _tx; // next bit to transmit is a "0"
+ _state = TRANSITION;
+ break;
+
+ case TRANSITION:
+ _tx = (encodeByte & 0x01) ^ 0x01; // set line appropriately for transition
+ if(++bitIndex < 8) {
+ encodeByte = (encodeByte >> 1);
+ _state = SETUP;
+ }
+ else {
+ if(++byteIndex < _len) {
+ encodeByte = _data[byteIndex];
+ _state = SETUP;
+ bitIndex = 0;
+ }
+ else
+ _state = COMPLETE;
+ }
+ break;
+
+ case COMPLETE:
+ _tx = 1; // transition is complete, bring line high
+ _state = IDLE;
+ break;
+
+ case IDLE:
+ default:
+ return;
+ }
+}
+
+/**
+ * @brief Receives message
+ * @note
+ * @param msg A container to store the received message
+ * @retval true On success
+ * false Otherwise
+ */
+bool Manchester::receive(ManchesterMsg& msg) {
+ bool rxFinished;
+ uint32_t now = us_ticker_read();
+
+ _data = msg.data;
+ _maxLen = msg.maxLen();
+ _state = LISTEN;
+
+ core_util_critical_section_enter();
+ _rx.enable_irq();
+ core_util_critical_section_exit();
+
+ do
+ {
+ core_util_critical_section_enter();
+ rxFinished = ((_state == IDLE) || (_state == ERROR));
+ core_util_critical_section_exit();
+ } while(!rxFinished);
+
+ core_util_critical_section_enter();
+ _rx.disable_irq();
+ core_util_critical_section_exit();
+
+ if(_state == ERROR) {
+ msg.len = 0;
+ _state = IDLE;
+ return false;
+ }
+ else {
+ msg.len = _len;
+ return true;
+ }
+}
+
+/**
+ * @brief ISR to handle reception
+ * @note Called on rise or fall on receiver line
+ * @param
+ * @retval
+ */
+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;
+
+ switch(_state) {
+ case LISTEN:
+ begin = now;
+ if(_rx == 0) {
+ _state = SYNCH_START;
+ _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
+ }
+ else
+ _state = ERROR;
+ break;
+
+ case SYNCH_START:
+ pulseWidth = now - begin;
+ if((pulseWidth > _maxPulseWidth) | (_rx == 0))
+ _state = ERROR;
+ else {
+ begin = now;
+ decodeByte = 0;
+ _len = 0;
+ bitIndex = 0;
+ _state = DECODE;
+ _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
+ }
+ break;
+
+ case DECODE:
+ pulseWidth = now - begin;
+ if((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth)) {
+ begin = now;
+ decodeByte |= (((_rx == 0) & 0x01) << bitIndex++);
+ if(bitIndex > 7) {
+ _data[_len++] = decodeByte;
+ if(_len > _maxLen - 1)
+ _state = ERROR;
+ else {
+ decodeByte = 0;
+ bitIndex = 0;
+ }
+ }
+ }
+
+ if(pulseWidth > _maxPulseWidth) {
+ _state = ERROR;
+ }
+ else
+ _rxTimeout.attach_us(callback(this, &Manchester::rxTimeout), _maxPulseWidth * 2);
+
+ break;
+
+ case IDLE:
+ case ERROR:
+ default:
+ break;
+ }
+}
+
+/**
+ * @brief ISR to handle receive timeout
+ * @note Signals end of transmission by setting state to IDLE
+ * or timeout error by setting state to ERROR.
+ * @param None
+ * @retval None
+ */
+void Manchester::rxTimeout(void) {
+ _rxTimeout.detach();
+
+ if(_state == DECODE)
+ _state = IDLE; // End of transmission
+ else
+ _state = ERROR; // Incomplete transmission
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Manchester.h Wed May 17 07:52:15 2017 +0000
@@ -0,0 +1,81 @@
+/*
+ ******************************************************************************
+ * @file Manchester.h
+ * @author Zoltan Hudak
+ * @version
+ * @date 16-May-2017
+ * @brief Manchester code for ARMmbed
+ ******************************************************************************
+ * @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 MANCHESTER_H
+#define MANCHESTER_H
+
+#include "mbed.h"
+#include "ManchesterMsg.h"
+
+class Manchester
+{
+ enum State
+ {
+ IDLE,
+ SYNCH_START,
+ SYNCH_NEXT,
+ SYNCH_END,
+ SETUP,
+ TRANSITION,
+ COMPLETE,
+ LISTEN,
+ DECODE,
+ ERROR
+ };
+
+public:
+ Manchester
+ (
+ PinName txPin, /* transmitter pin name */
+ PinName rxPin, /* receiver pin name */
+ uint32_t speed = 1500 /* speed in bits per second */,
+ uint8_t tol = 20 /* pulse width tolerance (+/-) in % */
+ );
+ ~Manchester(void) { };
+ void transmit(ManchesterMsg& msg);
+ bool receive(ManchesterMsg& msg);
+
+private:
+ DigitalOut _tx; // transmitter line
+ InterruptIn _rx; // receiver line
+ Ticker _txTicker; // transmitter ticker
+ Timeout _rxTimeout; // receiver timeout
+ uint32_t _midBitTime; // mid-bit time [us]
+ uint32_t _minPulseWidth; // minimum pulse width
+ uint32_t _maxPulseWidth; // maximum pulse width
+ State _state; // state
+ char* _data; // data array
+ uint8_t _len; // data length in bytes
+ uint8_t _maxLen; // maximum length
+
+ void transmission(void);
+ void reception(void);
+ void rxTimeout(void);
+};
+#endif // MANCHESTER_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ManchesterMsg.h Wed May 17 07:52:15 2017 +0000
@@ -0,0 +1,138 @@
+/*
+ ******************************************************************************
+ * @file ManchesterMsg.h
+ * @author Zoltan Hudak
+ * @version
+ * @date 16-May-2017
+ * @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
+{
+ unsigned char _max; // Max length (capacity) of data field in bytes
+
+public:
+ char* data; // Data field
+ unsigned char len; // Length of data in bytes
+
+ /** Creates empty Manchester message of specified capacity.
+ */
+ ManchesterMsg(unsigned char 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)
+ */
+ unsigned char maxLen(void) { return _max; }
+
+ /** Clears message content
+ */
+ void clear(void) { len = 0; memset(data, 0, _max); }
+
+ /** Inserter operator: Appends data (value) to Manchester 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 string of char to Manchester message
+ */
+ ManchesterMsg &operator<<(const char* str) {
+ unsigned char 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 CAN 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 string of char from CAN message
+ */
+ ManchesterMsg &operator>>(char* str) {
+ unsigned char 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