Library for Manchester encoding using UART's hardware.

Dependents:   ManchesterUART_Transmitter ManchesterUART_Receiver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ManchesterUART.cpp Source File

ManchesterUART.cpp

00001 /*
00002  ******************************************************************************
00003  * @file    ManchesterUART.cpp
00004  * @author  Zoltan Hudak
00005  * @version
00006  * @date    2017-Nov-22
00007  * @brief   Manchester code over UART for mbed
00008  ******************************************************************************
00009  * @attention
00010  *
00011  * <h2><center>&copy; COPYRIGHT(c) 2017 Zoltan Hudak <hudakz@outlook.com>
00012  *
00013  * All rights reserved.
00014 
00015  This program is free software: you can redistribute it and/or modify
00016  it under the terms of the GNU General Public License as published by
00017  the Free Software Foundation, either version 3 of the License, or
00018  (at your option) any later version.
00019 
00020  This program is distributed in the hope that it will be useful,
00021  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  GNU General Public License for more details.
00024 
00025  You should have received a copy of the GNU General Public License
00026  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00027  */
00028 /*
00029  * This library implements Manchester code using UART serial connection. Each
00030  * data byte is encoded into two bytes representing two nibbles of the original
00031  * data byte. These two bytes are then sent over UART serial link connection.
00032  * The receiver reconstructs the original data byte from the two bytes received.
00033  * A start and stop pattern are sent to signify the begin and end of a message.
00034  *
00035  * The library is based on the article published by Adrian Mills:
00036  * http://www.quickbuilder.co.uk/qb/articles/Manchester_encoding_using_RS232.pdf
00037  */
00038 #include "ManchesterUART.h"
00039 #include "ManchesterMsg.h"
00040 
00041 /**
00042  * @brief   Transmits message
00043  * @note
00044  * @param   msg Message to transmit
00045  * @retval
00046  */
00047 void ManchesterUART::transmit(ManchesterMsg& msg)
00048 {
00049     _data = msg.data;
00050     _len = msg.len;
00051 
00052     for (uint8_t i = 0; i < _preamble; i++)
00053         _serial.putc(START);
00054     for (uint32_t i = 0; i < _len; i++)
00055     {
00056         transmitByte(_data[i]);
00057     }
00058 
00059     _serial.putc(STOP);
00060 }
00061 
00062 /**
00063  * @brief   Transmits a byte
00064  * @note
00065  * @param   data The byte to transmit
00066  * @retval
00067  */
00068 void ManchesterUART::transmitByte(uint8_t data)
00069 {
00070     uint8_t encoded;
00071 
00072     for (uint8_t i = 0; i < 2; i++)
00073     {
00074         encoded = 0;                    // manchester encoded byte
00075         for (uint8_t j = 0; j < 4; j++)
00076         {
00077             encoded >>= 2;
00078             if (data & 0b00000001)
00079                 encoded |= 0b01000000;  // 1->0
00080             else
00081                 encoded |= 0b10000000;  // 0->1
00082             data >>= 1;
00083         }
00084 
00085         _serial.putc(encoded);
00086     }
00087 }
00088 
00089 /**
00090  * @brief   Receives message
00091  * @note    Waits until a message is received or error occured
00092  * @param   msg   Container to store the received message in
00093  * @retval  true  On success
00094  *          false Otherwise
00095  */
00096 bool ManchesterUART::receive(ManchesterMsg& msg)
00097 {
00098     uint8_t byte1, byte2;
00099     bool    byte1Received;
00100     
00101     _error = NO_ERROR;
00102     _data = msg.data;
00103     _len = 0;
00104     _maxLen = msg.maxLen();
00105     
00106     if (!_serial.readable())
00107         return false;
00108 
00109     _timeout.attach(callback(this, &ManchesterUART::rxTimeout), _rxTimeout);
00110     
00111     //
00112     // wait for START pattern
00113     do {
00114         byte1 = _serial.getc();
00115         if (_error)
00116         {
00117             if (_error != RX_TIMEOUT)
00118                 _timeout.detach();
00119             msg.len = 0;
00120             return false;
00121         }
00122     } while (byte1 != START);
00123     //
00124     // read START pattern
00125     do {
00126         byte1 = _serial.getc();
00127         if (_error)
00128         {
00129             if (_error != RX_TIMEOUT)
00130                 _timeout.detach();
00131             msg.len = 0;
00132             return false;
00133         }
00134     } while (byte1 == START);
00135 
00136     byte1Received = true;   // byte1 available from the loop above
00137 
00138     while (true)
00139     {
00140         if (byte1Received)
00141             byte1Received = false;
00142         else
00143         {
00144             byte1 = _serial.getc();
00145             if (byte1 == STOP)
00146                 break;
00147             if (_len > _maxLen - 1)
00148             {
00149                 _error = BUF_OVERRUN;
00150                 break;
00151             }
00152         }
00153 
00154         byte2 = _serial.getc();
00155         if (byte2 == STOP)
00156         {
00157             _error = ILLEGAL_CODE;
00158             break;
00159         }
00160 
00161         _data[_len++] = (getNibble(byte1)) | (getNibble(byte2) << 4);
00162         if (_error)
00163             break;
00164     }
00165 
00166     if (_error != RX_TIMEOUT)
00167         _timeout.detach();
00168 
00169     if (_error)
00170     {
00171         msg.len = 0;
00172         return false;
00173     }
00174     else
00175     {
00176         msg.len = _len;
00177         return true;
00178     }
00179 }
00180 
00181 /**
00182  * @brief   ISR handling 'reception timeout'
00183  * @note    Called when receiving a message takes longer than limit.
00184  *          Signals 'timeout error' by setting error flag.
00185  * @param
00186  * @retval
00187  */
00188 void ManchesterUART::rxTimeout(void)
00189 {
00190     _timeout.detach();
00191     _error = RX_TIMEOUT;
00192 }
00193 
00194 /**
00195  * @brief   Gets a nibble of received byte
00196  * @note    Checks for illegal codes/patterns
00197  * @param   nibble  A byte received over UART (Manchester encoded nibble)
00198  * @retval  Decoded nibble
00199  */
00200 uint8_t ManchesterUART::getNibble(uint8_t encoded)
00201 {
00202     uint8_t decoded, pattern;
00203 
00204     decoded = 0;
00205     for (int i = 0; i < 4; i++)
00206     {
00207         decoded >>= 1;
00208         pattern = encoded & 0b000011;
00209         if (pattern == 0b00000001)  // 1
00210             decoded |= (0b00000001 << 3);
00211         else
00212         if (pattern == 0b00000010)  // 0
00213             decoded &= ~(0b00000001 << 3);
00214         else
00215         {
00216             _error = ILLEGAL_CODE;
00217             break;
00218         }
00219 
00220         encoded >>= 2;
00221     }
00222 
00223     return decoded;
00224 }
00225