| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -22,6 +22,12 @@ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#define SPI_NACK 0x1FU | 
					 | 
					 | 
					 | 
					#define SPI_NACK 0x1FU | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#define SPI_CHECKSUM_START 0xABU | 
					 | 
					 | 
					 | 
					#define SPI_CHECKSUM_START 0xABU | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					enum SpiError { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  NACK = -2, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  ACK_TIMEOUT = -3, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					struct __attribute__((packed)) spi_header { | 
					 | 
					 | 
					 | 
					struct __attribute__((packed)) spi_header { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  uint8_t sync; | 
					 | 
					 | 
					 | 
					  uint8_t sync; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  uint8_t endpoint; | 
					 | 
					 | 
					 | 
					  uint8_t endpoint; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -40,8 +46,8 @@ public: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }; | 
					 | 
					 | 
					 | 
					  }; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  ~LockEx() { | 
					 | 
					 | 
					 | 
					  ~LockEx() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    m.unlock(); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    flock(fd, LOCK_UN); | 
					 | 
					 | 
					 | 
					    flock(fd, LOCK_UN); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    m.unlock(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					private: | 
					 | 
					 | 
					 | 
					private: | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -170,7 +176,7 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if (d < 0) { | 
					 | 
					 | 
					 | 
					    if (d < 0) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      LOGE("SPI: bulk transfer failed with %d", d); | 
					 | 
					 | 
					 | 
					      LOGE("SPI: bulk transfer failed with %d", d); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      comms_healthy = false; | 
					 | 
					 | 
					 | 
					      comms_healthy = false; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      return -1; | 
					 | 
					 | 
					 | 
					      return d; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ret += d; | 
					 | 
					 | 
					 | 
					    ret += d; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -210,17 +216,40 @@ bool check_checksum(uint8_t *data, int data_len) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout) { | 
					 | 
					 | 
					 | 
					int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  int ret; | 
					 | 
					 | 
					 | 
					  int ret; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  int count = 0; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  bool timed_out = false; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  double start_time = millis_since_boot(); | 
					 | 
					 | 
					 | 
					  double start_time = millis_since_boot(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  do { | 
					 | 
					 | 
					 | 
					  do { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // TODO: handle error
 | 
					 | 
					 | 
					 | 
					    ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len, timeout); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } while (ret < 0 && connected && ((timeout == 0) || (millis_since_boot() - start_time) < timeout)); | 
					 | 
					 | 
					 | 
					    if (ret < 0) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      timed_out = (timeout != 0) && (count > 5); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      count += ret == SpiError::ACK_TIMEOUT; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      std::this_thread::yield(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  } while (ret < 0 && connected && !timed_out); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  if (ret < 0) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    LOGE("transfer failed, after %d tries, %.2fms", count, millis_since_boot() - start_time); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  return ret; | 
					 | 
					 | 
					 | 
					  return ret; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { | 
					 | 
					 | 
					 | 
					int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  double start_millis = millis_since_boot(); | 
					 | 
					 | 
					 | 
					  double start_millis = millis_since_boot(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  if (timeout <= 0) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    timeout = SPI_ACK_TIMEOUT; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  spi_ioc_transfer transfer = { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    .tx_buf = (uint64_t)tx_buf, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    .rx_buf = (uint64_t)rx_buf, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    .delay_usecs = 5, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    .len = 1 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  }; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  tx_buf[0] = tx; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  while (true) { | 
					 | 
					 | 
					 | 
					  while (true) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    int ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); | 
					 | 
					 | 
					 | 
					    int ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if (ret < 0) { | 
					 | 
					 | 
					 | 
					    if (ret < 0) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -232,20 +261,20 @@ int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      break; | 
					 | 
					 | 
					 | 
					      break; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } else if (rx_buf[0] == SPI_NACK) { | 
					 | 
					 | 
					 | 
					    } else if (rx_buf[0] == SPI_NACK) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      LOGD("SPI: got NACK"); | 
					 | 
					 | 
					 | 
					      LOGD("SPI: got NACK"); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      return -1; | 
					 | 
					 | 
					 | 
					      return SpiError::NACK; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // handle timeout
 | 
					 | 
					 | 
					 | 
					    // handle timeout
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if (millis_since_boot() - start_millis > SPI_ACK_TIMEOUT) { | 
					 | 
					 | 
					 | 
					    if (millis_since_boot() - start_millis > timeout) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      LOGD("SPI: timed out waiting for ACK"); | 
					 | 
					 | 
					 | 
					      LOGD("SPI: timed out waiting for ACK"); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      return -1; | 
					 | 
					 | 
					 | 
					      return SpiError::ACK_TIMEOUT; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  return 0; | 
					 | 
					 | 
					 | 
					  return 0; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { | 
					 | 
					 | 
					 | 
					int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  int ret; | 
					 | 
					 | 
					 | 
					  int ret; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  uint16_t rx_data_len; | 
					 | 
					 | 
					 | 
					  uint16_t rx_data_len; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  LockEx lock(spi_fd, hw_lock); | 
					 | 
					 | 
					 | 
					  LockEx lock(spi_fd, hw_lock); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -277,9 +306,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // Wait for (N)ACK
 | 
					 | 
					 | 
					 | 
					  // Wait for (N)ACK
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  tx_buf[0] = 0x11; | 
					 | 
					 | 
					 | 
					  ret = wait_for_ack(SPI_HACK, 0x11, timeout); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  transfer.len = 1; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  ret = wait_for_ack(transfer, SPI_HACK); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  if (ret < 0) { | 
					 | 
					 | 
					 | 
					  if (ret < 0) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    goto transfer_fail; | 
					 | 
					 | 
					 | 
					    goto transfer_fail; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -297,9 +324,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // Wait for (N)ACK
 | 
					 | 
					 | 
					 | 
					  // Wait for (N)ACK
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  tx_buf[0] = 0x13; | 
					 | 
					 | 
					 | 
					  ret = wait_for_ack(SPI_DACK, 0x13, timeout); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  transfer.len = 1; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  ret = wait_for_ack(transfer, SPI_DACK); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  if (ret < 0) { | 
					 | 
					 | 
					 | 
					  if (ret < 0) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    goto transfer_fail; | 
					 | 
					 | 
					 | 
					    goto transfer_fail; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
  |