Manchester
Diff: Manchester.cpp
- Revision:
- 0:d5c75b0e5708
- Child:
- 1:11292d238e50
--- /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
+}
+