Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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>© 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 }
Generated on Wed Jul 27 2022 00:41:35 by
1.7.2