diff options
author | michael-west <michael.west@ettus.com> | 2014-05-10 19:40:15 -0700 |
---|---|---|
committer | Ben Hilburn <ben.hilburn@ettus.com> | 2014-07-17 18:16:04 -0700 |
commit | 8f6e2ac9972151318bf6883d45ee099a5013ae1e (patch) | |
tree | 7a600c625e9111387386874bc8ea9505466576d7 /host/lib/usrp/x300/x300_fw_uart.cpp | |
parent | 0efddecd45ff4756b046e5ebeb8626e54ffb19ff (diff) | |
download | uhd-8f6e2ac9972151318bf6883d45ee099a5013ae1e.tar.gz uhd-8f6e2ac9972151318bf6883d45ee099a5013ae1e.tar.bz2 uhd-8f6e2ac9972151318bf6883d45ee099a5013ae1e.zip |
Fix for BUG #469: Bad/Empty GPS NMEA strings returned when the queries are made in a random wait iterative fashion
Fix for BUG #460: X300: GPGGA sensor most often empty, while RMC is usually OK
- Added checksum verification of NMEA strings
- Improved handling of short or malformed strings
- Fixed GPSDO data synchronization between X300 firmware and host
Diffstat (limited to 'host/lib/usrp/x300/x300_fw_uart.cpp')
-rw-r--r-- | host/lib/usrp/x300/x300_fw_uart.cpp | 89 |
1 files changed, 74 insertions, 15 deletions
diff --git a/host/lib/usrp/x300/x300_fw_uart.cpp b/host/lib/usrp/x300/x300_fw_uart.cpp index 943b2d9fa..4bf103c5a 100644 --- a/host/lib/usrp/x300/x300_fw_uart.cpp +++ b/host/lib/usrp/x300/x300_fw_uart.cpp @@ -38,6 +38,8 @@ struct x300_uart_iface : uart_iface rxpool = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_ADDR)); txpool = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_TX_ADDR)); poolsize = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_WORDS32)); + _rxcache.resize(poolsize); + _last_device_rxoffset = rxoffset; //this->write_uart("HELLO UART\n"); //this->read_uart(0.1); } @@ -63,39 +65,96 @@ struct x300_uart_iface : uart_iface int getchar(void) { - if (_iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)) != rxoffset) + if (rxoffset == _last_device_rxoffset) + return -1; + + rxoffset++; + return int(_rxcache[((rxoffset)/4) % poolsize] >> ((rxoffset%4)*8) & 0xFF); + } + + void update_cache(void) + { + uint32_t device_rxoffset = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)); + uint32_t delta = device_rxoffset - rxoffset; + + while (delta) { - const int shift = ((rxoffset%4) * 8); - const char ch = _iface->peek32(SR_ADDR(rxpool, rxoffset/4)) >> shift; - rxoffset = (rxoffset + 1) % (poolsize*4); - return ch; + if (delta >= poolsize*4) + { + // all the data is new - reload the entire cache + for (uint32_t i = 0; i < poolsize; i++) + _rxcache[i] = _iface->peek32(SR_ADDR(rxpool, i)); + + // set rxoffset to the end of the first string + rxoffset = device_rxoffset - (poolsize*4) + 1; + while (uint8_t(_rxcache[(rxoffset/4) % poolsize] >> ((rxoffset % 4) * 8)) != '\n') + ++rxoffset; + + // clear the partial string in the buffer; + _rxbuff.clear(); + } + else if (rxoffset == _last_device_rxoffset) + { + // new data was added - refresh the portion of the cache that was updated + for (uint32_t i = ((_last_device_rxoffset+1)/4) % poolsize; i != (((device_rxoffset)/4)+1) % poolsize; i = (i+1) % poolsize) + { + _rxcache[i] = _iface->peek32(SR_ADDR(rxpool, i)); + } + } else { + // there is new data, but we aren't done with what we have - check back later + break; + } + + _last_device_rxoffset = device_rxoffset; + + // check again to see if anything changed while we were updating the cache + device_rxoffset = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)); + delta = device_rxoffset - rxoffset; } - return -1; } std::string read_uart(double timeout) { const boost::system_time exit_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1e6)); std::string buff; + while (true) { - const int ch = this->getchar(); - if (ch == -1) + // Update cache + this->update_cache(); + + // Get available characters + for (int ch = this->getchar(); ch != -1; ch = this->getchar()) { - if (boost::get_system_time() > exit_time) break; - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - continue; + // skip carriage returns + if (ch == '\r') + continue; + + // store character to buffer + _rxbuff += std::string(1, (char)ch); + + // newline found - return string + if (ch == '\n') + { + buff = _rxbuff; + _rxbuff.clear(); + return buff; + } } - if (ch == '\r') continue; - buff += std::string(1, (char)ch); - if (ch == '\n') break; + + // no more characters - check time + if (boost::get_system_time() > exit_time) + break; } - //UHD_VAR(buff); + return buff; } wb_iface::sptr _iface; boost::uint32_t rxoffset, txoffset, txword32, rxpool, txpool, poolsize; + boost::uint32_t _last_device_rxoffset; + std::vector<uint32_t> _rxcache; + std::string _rxbuff; }; uart_iface::sptr x300_make_uart_iface(wb_iface::sptr iface) |