Manchester

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Manchester.cpp Source File

Manchester.cpp

00001 /*
00002  ******************************************************************************
00003  * @file    Manchester.cpp
00004  * @author  Zoltan Hudak
00005  * @version
00006  * @date    2017-May-16
00007  * @brief   Manchester code 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 according to both IEEE 802.3
00030    and G.E. Thomas' conventions.
00031    • A '0' is expressed by a high-to-low transition, a '1' by low-to-high transition
00032      in the IEEE 802.3 convention. The reverse is true in the G.E. Thomas' convention.
00033    • The transitions which signify '0' or '1' occur at the midpoint of a period.
00034    • Transitions at the start of a period are overhead and don't signify data.
00035    • Least significant bit is sent first
00036    • There is one synchronization pulse at the begin of transmission
00037 
00038    The IEEE 802.3 convention is used by default.
00039    Select a convention to be used by commenting or uncommenting
00040    the line "#define G_E_THOMAS 1" in the Manchester.h header file.
00041  */
00042 #include "Manchester.h"
00043 #include "mbed-trace/mbed_trace.h"
00044 
00045 #undef TRACE_GROUP
00046 #define TRACE_GROUP  "Manchester"
00047 
00048 /**
00049  * @brief   Creates a Manchester object
00050  * @note
00051  * @param   txPin Pin name of transmitter line
00052  *          rxPin Pin name of receiver line
00053  *          speed Communication bit rate in bits per second
00054  *          tol   Pulse width tolerance in %
00055  * @retval
00056  */
00057 Manchester::Manchester
00058 (
00059     PinName     txPin,
00060     PinName     rxPin,
00061     uint32_t    baudrate,   /* = 1200 bps */
00062     uint8_t     tol,        /* = (+/-)25% */
00063     float       rxTimeout   /* = 5s */
00064 ) :
00065     _tx(txPin),
00066     _rx(rxPin)
00067 {
00068     _state = IDLE;
00069     _midBitTime = 1000000 / baudrate / 2;                   // mid-bit time [us]
00070     _minPulseWidth = (_midBitTime * 2 * (100 - tol)) / 100; // [us]
00071     _maxPulseWidth = (_midBitTime * 2 * (100 + tol)) / 100; // [us]
00072     _rxTimeout = rxTimeout;
00073     _rx.disable_irq();
00074     _rx.rise(callback(this, &Manchester::reception));
00075     _rx.fall(callback(this, &Manchester::reception));
00076     _preamble = 1;                                          // number of synch_start patterns
00077 
00078     tr_debug("_midBitTime    = %d", _midBitTime);
00079     tr_debug("_minPulseWidth = %d", _minPulseWidth);
00080     tr_debug("_maxPulseWidth = %d", _maxPulseWidth);
00081     _tx = 0;
00082 }
00083 
00084 /**
00085  * @brief   Transmits message
00086  * @note
00087  * @param   msg Message to transmit
00088  * @retval
00089  */
00090 void Manchester::transmit(uint8_t* msg, uint8_t len)
00091 {
00092     bool    txFinished;
00093 
00094     _data = (char*)msg;
00095     _len = len;
00096     _state = SYNCH_START;
00097     _txTicker.attach_us(callback(this, &Manchester::transmission), _midBitTime);
00098 
00099     do {
00100         core_util_critical_section_enter();
00101         txFinished = (_state == IDLE);
00102         core_util_critical_section_exit();
00103     } while (!txFinished);
00104 
00105     _txTicker.detach();
00106 }
00107 
00108 /**
00109  * @brief   ISR handling transmission
00110  * @note    Called by _txTicker
00111  * @param
00112  * @retval
00113  */
00114 void Manchester::transmission(void)
00115 {
00116     static uint8_t  encodeByte;
00117     static size_t   byteIndex;
00118     static uint8_t  bitIndex;
00119     static uint8_t  counter;
00120 
00121     _timeout.attach_us(callback(this, &Manchester::onTxTimeout), _maxPulseWidth * 4);
00122 
00123     switch (_state)
00124     {
00125         case SYNCH_START:
00126             if (_preamble == 0)
00127             {
00128                 byteIndex = 0;
00129                 encodeByte = _data[byteIndex];
00130                 bitIndex = 0;
00131                 _state = SETUP;
00132                 break;
00133             }
00134 
00135             _tx = 1;                    // bring line high to start synch pulse
00136             
00137             counter = 0;
00138             _state = SYNCH_NEXT;
00139             break;
00140 
00141         case SYNCH_NEXT:
00142             counter++;
00143             _tx = !_tx;
00144             byteIndex = 0;
00145             encodeByte = _data[byteIndex];
00146             bitIndex = 0;
00147             _state = SETUP;
00148             break;
00149 
00150         case SETUP:
00151             _tx = ((encodeByte >> 7) & 0x01); // setup for next bit to transmit
00152             _state = TRANSITION;
00153             break;
00154 
00155         case TRANSITION:
00156             _tx = !((encodeByte >> 7) & 0x01);    // set line appropriately for transition
00157             
00158             if (++bitIndex < 8)
00159             {
00160                 encodeByte = (encodeByte << 1);
00161                 _state = SETUP;
00162             }
00163             else
00164             {
00165                 if (++byteIndex < _len)
00166                 {
00167                     encodeByte = _data[byteIndex];
00168                     _state = SETUP;
00169                     bitIndex = 0;
00170                 }
00171                 else
00172                 {
00173                     counter = 0;
00174                     _state = STOP;
00175                 }
00176             }
00177             break;
00178 
00179         case STOP:
00180             counter++;
00181             _tx = 0;
00182 
00183             if (counter == 4)
00184                 _state = COMPLETE;
00185             break;
00186 
00187         case COMPLETE:
00188             _tx = 0;
00189             _state = IDLE;
00190             break;
00191 
00192         case IDLE:
00193         default:
00194             _timeout.detach();
00195             return;
00196     }
00197 }
00198 
00199 /**
00200  * @brief   ISR handling 'transmission timeout'
00201  * @note    Called when transmitter is stuck.
00202  *          Signals 'end of transmission' by setting state to IDLE
00203  * @param
00204  * @retval
00205  */
00206 void Manchester::onTxTimeout(void)
00207 {
00208     _timeout.detach();
00209     _state = IDLE;
00210 }
00211 
00212 /**
00213  * @brief   Receives message
00214  * @note    Waits until a message is received or 'reception timeout' occured
00215  * @param   msg   Container to store the received message
00216  * @retval  true  On success
00217  *          false Otherwise
00218  */
00219 bool Manchester::receive(uint8_t *msg, uint8_t *len)
00220 {
00221     bool    rxFinished;
00222 
00223     _data = (char*)msg;
00224     _maxLen = *len;
00225     _state = LISTEN;
00226     _timeout.attach(callback(this, &Manchester::onRxTimeout), _rxTimeout);
00227     _rx.enable_irq();
00228 
00229     do {
00230         core_util_critical_section_enter();
00231         rxFinished = ((_state == IDLE) || (_state == ERROR));
00232         core_util_critical_section_exit();
00233     } while (!rxFinished);
00234 
00235     _rx.disable_irq();
00236     _timer.stop();
00237     _timeout.detach();
00238 
00239     if (_state == ERROR)
00240     {
00241         len = 0;
00242         _state = IDLE;
00243         return false;
00244     }
00245     else
00246     {
00247         *len = _len;
00248         return true;
00249     }
00250 }
00251 
00252 /**
00253  * @brief   ISR handling reception
00254  * @note    Called on signal change (rise or fall) on receiver line
00255  * @param
00256  * @retval
00257  */
00258 void Manchester::reception(void)
00259 {
00260     uint32_t        now = us_ticker_read();
00261     static uint32_t begin;
00262     uint32_t        pulseWidth;
00263     static uint8_t  decodeByte;
00264     static uint8_t  bitIndex;
00265 
00266     switch (_state)
00267     {
00268         case LISTEN:
00269             begin = now;
00270             if (_rx == 1)
00271             {
00272                 _state = SYNCH_START;
00273             }
00274             else
00275             {
00276                 tr_err("SYNCH_START: Isn't a SYNCH pulse");
00277                 _state = ERROR;
00278             }
00279             break;
00280 
00281         case SYNCH_START:
00282             pulseWidth = now - begin;
00283             //printf("%d <= %d <= %d\r\n", (_midBitTime * 2) + _minPulseWidth, pulseWidth, (_midBitTime * 2) + _maxPulseWidth);
00284             if (((_midBitTime * 2) + _minPulseWidth <= pulseWidth) && (pulseWidth <= (_midBitTime * 2) + _maxPulseWidth))
00285             {
00286                 begin = now;
00287                 _state = SYNCH_NEXT;
00288             }
00289             else
00290             {
00291                 tr_err("SYNCH_START: Isn't a SYNCH pulse");
00292                 _state = ERROR;
00293             }
00294             break;
00295 
00296         case SYNCH_NEXT:
00297             pulseWidth = now - begin;
00298             //printf("%d <= %d <= %d\r\n", (_midBitTime * 2) + _minPulseWidth, pulseWidth, (_midBitTime * 2) + _maxPulseWidth);
00299             if (((_midBitTime * 2) + _minPulseWidth <= pulseWidth) && (pulseWidth <= (_midBitTime * 2) + _maxPulseWidth))
00300             {
00301                 begin = now;
00302                 _state = SYNCH_NEXT;
00303             }
00304             else
00305             if ((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth))
00306             {
00307                 begin = now;
00308                 decodeByte = 0;
00309                 bitIndex = 0;
00310                 _len = 0;
00311                 decodeByte |= (((_rx == 1) & 0x01) << bitIndex++);
00312                 _state = DECODE;
00313             }
00314             break;
00315 
00316         case DECODE:
00317             pulseWidth = now - begin;
00318             if ((_minPulseWidth <= pulseWidth) && (pulseWidth <= _maxPulseWidth))
00319             {
00320                 begin = now;
00321                 decodeByte |= (((_rx == 1) & 0x01) << bitIndex++);
00322                 if (bitIndex > 7)
00323                 {
00324                     _data[_len++] = decodeByte;
00325                     if (_len > _maxLen - 1)
00326                         _state = ERROR;
00327                     else
00328                     {
00329                         decodeByte = 0;
00330                         bitIndex = 0;
00331                     }
00332                 }
00333                 break;
00334             }
00335 
00336             if (pulseWidth > _maxPulseWidth)
00337             {
00338                 if (_rx == 1)
00339                 {
00340                     begin = now;
00341                     _state = COMPLETE;  // End of reception
00342                 }
00343             }
00344             break;
00345 
00346         case COMPLETE:
00347             pulseWidth = now - begin;
00348             if (pulseWidth > _maxPulseWidth)
00349             {
00350                 if (_rx == 0)
00351                 {
00352                     _state = IDLE;  // End of reception
00353                 }
00354             }
00355             break;
00356 
00357         case IDLE:
00358         case ERROR:
00359         default:
00360             _timeout.detach();
00361             break;
00362     }
00363 }
00364 
00365 /**
00366  * @brief   ISR handling 'reception timeout'
00367  * @note    Called when receiver line is idle longer than limit.
00368  *          Signals 'end of reception' by setting state to IDLE
00369  *          or 'timeout error' by setting state to ERROR.
00370  * @param
00371  * @retval
00372  */
00373 void Manchester::onRxTimeout(void)
00374 {
00375     _timeout.detach();
00376 
00377     if ((_state == DECODE) && (_rx == 0))
00378     {
00379         tr_err("rx timeout");
00380         _state = IDLE;  // Reception successful
00381     }
00382     else
00383     {
00384         tr_err("reception error");
00385         _state = ERROR; // Reception incomplete
00386     }
00387 }