aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/x300/x300_fw_uart.cpp
diff options
context:
space:
mode:
authormichael-west <michael.west@ettus.com>2014-05-10 19:40:15 -0700
committerBen Hilburn <ben.hilburn@ettus.com>2014-07-17 18:16:04 -0700
commit8f6e2ac9972151318bf6883d45ee099a5013ae1e (patch)
tree7a600c625e9111387386874bc8ea9505466576d7 /host/lib/usrp/x300/x300_fw_uart.cpp
parent0efddecd45ff4756b046e5ebeb8626e54ffb19ff (diff)
downloaduhd-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.cpp89
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)