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.
Fork of mDot_AT_firmware by
ATSerial.cpp
00001 00002 #include "ATSerial.h" 00003 #include "MTSLog.h" 00004 #include "Utils.h" 00005 00006 using namespace mts; 00007 00008 00009 ATSerial::ATSerial(PinName txd, PinName rxd, PinName rts, PinName cts, int baud) 00010 : _serial(txd, rxd, baud), 00011 _tx_irq_enabled(false), 00012 _last_time(0), 00013 _esc_cnt(0), 00014 _esc_ch('+'), 00015 _escaped(false), 00016 _flow(false), // Flow control disabled by default 00017 _rts(rts), 00018 _cts(cts) 00019 { 00020 00021 if (rts != NC && cts != NC) { // RTS and CTS must both be provided for flow control 00022 _flow = true; 00023 _rts = 0; // Start with receive enabled 00024 _cts.fall(callback(this, &ATSerial::startWrite)); // Restart writes when able to send 00025 _hwm = mts_max(AT_SERIAL_RX_BUFFER_SIZE - 10, AT_SERIAL_RX_BUFFER_SIZE * 0.85); 00026 _lwm = AT_SERIAL_RX_BUFFER_SIZE * 0.3; 00027 } 00028 00029 // Receive buffer 00030 _rxbuf = new mbed::CircularBuffer<char, AT_SERIAL_RX_BUFFER_SIZE>(); 00031 // Transmit buffer 00032 _txbuf = new mbed::CircularBuffer<char, AT_SERIAL_TX_BUFFER_SIZE>(); 00033 00034 _timer.start(); 00035 _serial.attach(callback(this, &ATSerial::handleRead), SerialBase::RxIrq); 00036 } 00037 00038 ATSerial::~ATSerial() 00039 { 00040 } 00041 00042 void ATSerial::baud(int baudrate) { 00043 _mutex.lock(); 00044 _serial.baud(baudrate); 00045 _mutex.unlock(); 00046 } 00047 00048 void ATSerial::format(int bits, SerialBase::Parity parity, int stop_bits) { 00049 _mutex.lock(); 00050 _serial.format(bits, parity, stop_bits); 00051 _mutex.unlock(); 00052 } 00053 00054 void ATSerial::flowControl(bool enable) { 00055 if (enable && (_rts != NC) && (_cts != NC)) { // RTS and CTS must both be provided for flow control 00056 _flow = true; 00057 _rts = 0; // Start with receive enabled 00058 _cts.fall(callback(this, &ATSerial::startWrite)); // Restart writes when able to send 00059 _hwm = mts_max(MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE - 10, MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE * 0.85); 00060 _lwm = MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE * 0.3; 00061 } else { 00062 _flow = false; 00063 _rts = 1; 00064 } 00065 } 00066 00067 bool ATSerial::flowControl() { 00068 return _flow; 00069 } 00070 00071 bool ATSerial::readable() { 00072 return !_rxbuf->empty(); 00073 } 00074 00075 bool ATSerial::writeable() { 00076 return !_txbuf->full(); 00077 } 00078 00079 void ATSerial::rxClear() { 00080 _mutex.lock(); 00081 _rxbuf->reset(); 00082 if (_flow) { 00083 _rts = 0; // Allow receiving because receive buffer is now empty 00084 } 00085 _mutex.unlock(); 00086 } 00087 00088 void ATSerial::txClear() { 00089 _mutex.lock(); 00090 _txbuf->reset(); 00091 _mutex.unlock(); 00092 } 00093 00094 bool ATSerial::escaped() { 00095 _mutex.lock(); 00096 std::chrono::milliseconds now = std::chrono::duration_cast<std::chrono::milliseconds>(_timer.elapsed_time()); 00097 std::chrono::milliseconds elapsed_ms = now - _last_time; 00098 00099 // Have we seen three esc chars and 1 sec end guard has passed 00100 if (_escaped || (_esc_cnt == 3 && (elapsed_ms > 1s))) { 00101 _escaped = true; 00102 00103 // Have we seen a couple esc chars but nothing in 500 ms 00104 } else if (_esc_cnt > 0 && _esc_cnt != 3 && elapsed_ms > 500ms) { 00105 // Write seen esc chars 00106 while (_esc_cnt) { 00107 _rxbuf->push(_esc_ch); 00108 _esc_cnt--; 00109 } 00110 _escaped = false; 00111 } 00112 _mutex.unlock(); 00113 00114 return _escaped; 00115 } 00116 00117 void ATSerial::clearEscaped() { 00118 _mutex.lock(); 00119 _esc_cnt = 0; 00120 _escaped = false; 00121 _mutex.unlock(); 00122 } 00123 00124 bool ATSerial::read(char& c) { 00125 return read(&c, 1) == 1; 00126 } 00127 00128 int ATSerial::write(const char *buffer, size_t length) { 00129 _mutex.lock(); 00130 size_t i = 0; 00131 while (i < length) { 00132 if (_txbuf->full()) { 00133 do { 00134 _mutex.unlock(); 00135 thread_sleep_for(1); 00136 _mutex.lock(); 00137 } while (_txbuf->full()); 00138 } 00139 while (i < length && !_txbuf->full()) 00140 { 00141 _txbuf->push(buffer[i]); 00142 i++; 00143 } 00144 startWrite(); // Start writing data in tx buffer 00145 } 00146 _mutex.unlock(); 00147 return i; 00148 } 00149 00150 int ATSerial::writef(const char* format, ... ) { 00151 char buff[256]; 00152 00153 va_list ap; 00154 va_start(ap, format); 00155 int size = vsnprintf(buff, 256, format, ap); 00156 int n = write(buff, size); 00157 va_end(ap); 00158 00159 return n; 00160 } 00161 00162 int ATSerial::read(char *buffer, size_t length) { 00163 _mutex.lock(); 00164 size_t r = 0; 00165 while (r < length) { 00166 if (_rxbuf->pop(buffer[r])) { 00167 r++; 00168 } else { 00169 break; 00170 } 00171 } 00172 if (_flow && _rts && _rxbuf->size() <= _lwm) { 00173 _rts = 0; // RX buffer has room, clear RTS to continue receiving 00174 } 00175 _mutex.unlock(); 00176 return r; 00177 } 00178 00179 void ATSerial::startWrite() 00180 { 00181 core_util_critical_section_enter(); 00182 if (!_tx_irq_enabled) { 00183 // only write to hardware in one place 00184 handleWrite(); 00185 if (!_txbuf->empty()) { 00186 _serial.attach(callback(this, &ATSerial::handleWrite), SerialBase::TxIrq); 00187 _tx_irq_enabled = true; 00188 } 00189 } 00190 core_util_critical_section_exit(); 00191 } 00192 00193 void ATSerial::handleWrite() 00194 { 00195 char c; 00196 while (_serial.writeable()) { 00197 if (_flow && _cts) { 00198 break; // Exit write loop when CTS is set, will resume when it is cleared 00199 } 00200 00201 if (_txbuf->pop(c)) { 00202 _serial.write(&c, 1); 00203 } else { 00204 break; 00205 } 00206 } 00207 00208 // Detach TX IRQ if there's no more data to write or CTS is set 00209 if (_tx_irq_enabled && (_txbuf->empty() || (_flow && _cts))) { 00210 _serial.attach(NULL, SerialBase::TxIrq); 00211 _tx_irq_enabled = false; 00212 } 00213 } 00214 00215 00216 void ATSerial::handleRead() 00217 { 00218 char byte; 00219 if (_serial.read(&byte, 1) < 1) { return; } 00220 00221 std::chrono::milliseconds now = std::chrono::duration_cast<std::chrono::milliseconds>(_timer.elapsed_time()); 00222 std::chrono::milliseconds elapsed_ms = now - _last_time; 00223 _last_time = now; 00224 00225 // Have we seen 3 esc chars but this char is before 1 sec end guard time 00226 if (_esc_cnt == 3 && (elapsed_ms < std::chrono::seconds(1))) { 00227 // Write the three chars we held back 00228 while (_esc_cnt) { 00229 _rxbuf->push(_esc_ch); 00230 _esc_cnt--; 00231 } 00232 } else if (byte == _esc_ch) { 00233 // Has 1 second passed before last char 00234 if (elapsed_ms > std::chrono::seconds(1)) { 00235 _esc_cnt = 1; 00236 // Is this second or third esc char 00237 } else if (_esc_cnt > 0 && _esc_cnt < 3) { 00238 _esc_cnt++; 00239 } 00240 } else if (_esc_cnt > 0) { 00241 // Write any esc chars held back 00242 while (_esc_cnt) { 00243 _rxbuf->push(_esc_ch); 00244 _esc_cnt--; 00245 } 00246 } 00247 00248 if(_esc_cnt == 0) { 00249 if (_flow && !_rts && _rxbuf->size() >= _hwm) { 00250 _rts = 1; // RX buffer too full, set RTS to stop receiving 00251 // Data will still be received until the buffer is full 00252 } 00253 00254 if (_rxbuf->full()) { 00255 // Overflow, drop byte 00256 } else { 00257 _rxbuf->push(byte); 00258 } 00259 } 00260 00261 } 00262 00263 void ATSerial::escapeChar(char esc) { 00264 _esc_ch = esc; 00265 } 00266 00267 char ATSerial::escapeChar() { 00268 return _esc_ch; 00269 } 00270
Generated on Wed Jan 15 2025 16:10:46 by
1.7.2


