AT command firmware for MultiTech Dot devices.
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 Dec 6 2023 19:34:05 by 1.7.2