@ -50,8 +50,9 @@ private:
# define SPILOG(fn, fmt, ...) do { \
fn ( fmt , # # __VA_ARGS__ ) ; \
fn ( " %d / 0x%x / %d / %d " , \
xfer_count , header . endpoint , header . tx_len , header . max_rx_len ) ; \
fn ( " %d / 0x%x / %d / %d / tx: %s " , \
xfer_count , header . endpoint , header . tx_len , header . max_rx_len , \
util : : hexdump ( tx_buf , std : : min ( ( int ) header . tx_len , 8 ) ) . c_str ( ) ) ; \
} while ( 0 )
PandaSpiHandle : : PandaSpiHandle ( std : : string serial ) : PandaCommsHandle ( serial ) {
@ -238,6 +239,7 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1
// due to full TX buffers
nack_count + = 1 ;
if ( nack_count > 3 ) {
SPILOG ( LOGE , " NACK sleep %d " , nack_count ) ;
usleep ( std : : clamp ( nack_count * 10 , 200 , 2000 ) ) ;
}
}
@ -256,14 +258,14 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout,
if ( timeout = = 0 ) {
timeout = SPI_ACK_TIMEOUT ;
}
timeout = std : : clamp ( timeout , 10 0U, SPI_ACK_TIMEOUT ) ;
timeout = std : : clamp ( timeout , 2 0U, SPI_ACK_TIMEOUT ) ;
spi_ioc_transfer transfer = {
. tx_buf = ( uint64_t ) tx_buf ,
. rx_buf = ( uint64_t ) rx_buf ,
. len = length
. len = length ,
} ;
tx_buf [ 0 ] = tx ;
memset ( tx_buf , tx , length ) ;
while ( true ) {
int ret = lltransfer ( transfer ) ;
@ -275,13 +277,13 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout,
if ( rx_buf [ 0 ] = = ack ) {
break ;
} else if ( rx_buf [ 0 ] = = SPI_NACK ) {
SPILOG ( LOGD , " SPI: got NACK " ) ;
SPILOG ( LOGD , " SPI: got NACK, waiting for 0x%x " , ack ) ;
return SpiError : : NACK ;
}
// handle timeout
if ( millis_since_boot ( ) - start_millis > timeout ) {
SPILOG ( LOGW , " SPI: timed out waiting for ACK " ) ;
SPILOG ( LOGW , " SPI: timed out waiting for ACK, waiting for 0x%x " , ack ) ;
return SpiError : : ACK_TIMEOUT ;
}
}
@ -352,13 +354,13 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
ret = lltransfer ( transfer ) ;
if ( ret < 0 ) {
SPILOG ( LOGE , " SPI: failed to send header " ) ;
return ret ;
goto fail ;
}
// Wait for (N)ACK
ret = wait_for_ack ( SPI_HACK , 0x11 , timeout , 1 ) ;
if ( ret < 0 ) {
return ret ;
goto fail ;
}
// Send data
@ -370,20 +372,20 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
ret = lltransfer ( transfer ) ;
if ( ret < 0 ) {
SPILOG ( LOGE , " SPI: failed to send data " ) ;
return ret ;
goto fail ;
}
// Wait for (N)ACK
ret = wait_for_ack ( SPI_DACK , 0x13 , timeout , 3 ) ;
if ( ret < 0 ) {
return ret ;
goto fail ;
}
// Read data
rx_data_len = * ( uint16_t * ) ( rx_buf + 1 ) ;
if ( rx_data_len > = SPI_BUF_SIZE ) {
SPILOG ( LOGE , " SPI: RX data len larger than buf size %d " , rx_data_len ) ;
return - 1 ;
goto fail ;
}
transfer . len = rx_data_len + 1 ;
@ -391,11 +393,11 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
ret = lltransfer ( transfer ) ;
if ( ret < 0 ) {
SPILOG ( LOGE , " SPI: failed to read rx data " ) ;
return ret ;
goto fail ;
}
if ( ! check_checksum ( rx_buf , rx_data_len + 4 ) ) {
SPILOG ( LOGE , " SPI: bad checksum " ) ;
return - 1 ;
goto fail ;
}
if ( rx_data ! = NULL ) {
@ -403,5 +405,20 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
}
return rx_data_len ;
fail :
// ensure slave is in a consistent state
// and ready for the next transfer
int nack_cnt = 0 ;
while ( nack_cnt < 3 ) {
if ( wait_for_ack ( SPI_NACK , 0x14 , 1 , SPI_BUF_SIZE / 2 ) = = 0 ) {
nack_cnt + = 1 ;
} else {
nack_cnt = 0 ;
}
}
if ( ret > 0 ) ret = - 1 ;
return ret ;
}
# endif