Manchester
Embed:
(wiki syntax)
Show/hide line numbers
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