static void ICACHE_FLASH_ATTR ack_last_message(void) { const uint8_t seq = 0 | (uart_con_last_sequence_number_seen << 4); uint8_t checksum = 0; PEARSON(checksum, UART_CON_HEADER_SIZE); uart_tx(UART_CONNECTION, UART_CON_HEADER_SIZE); PEARSON(checksum, seq); uart_tx(UART_CONNECTION, seq); uart_tx(UART_CONNECTION, checksum); }
static void bricklet_stack_check_message_send_timeout(BrickletStack *bricklet_stack) { // If we are not currently sending a message // and there is still data in the buffer // and the timeout ran out we resend the message if((bricklet_stack->buffer_send_length > SPITFP_PROTOCOL_OVERHEAD) && (bricklet_stack_is_time_elapsed_ms(bricklet_stack->last_send_started, SPITFP_TIMEOUT) || bricklet_stack->ack_to_send)) { // Update sequence number of send buffer. We don't increase the current sequence // number, but if we have seen a new message from the master we insert // the updated "last seen sequence number". // If the number changed we also have to update the checksum. uint8_t new_sequence_byte = bricklet_stack_get_sequence_byte(bricklet_stack, false); if(new_sequence_byte != bricklet_stack->buffer_send[1]) { bricklet_stack->buffer_send[1] = new_sequence_byte; uint8_t checksum = 0; for(uint8_t i = 0; i < bricklet_stack->buffer_send[0]-1; i++) { PEARSON(checksum, bricklet_stack->buffer_send[i]); } bricklet_stack->buffer_send[bricklet_stack->buffer_send[0]-1] = checksum; } bricklet_stack->wait_for_ack = false; bricklet_stack->ack_to_send = false; bricklet_stack->last_send_started = bricklet_stack_get_ms(); } }
uint8_t spi_stack_calculate_pearson(const uint8_t *data, const uint8_t length) { uint8_t checksum = 0; for(uint8_t i = 0; i < length; i++) { PEARSON(checksum, data[i]); } return checksum; }
static void bricklet_stack_send_ack_and_message(BrickletStack *bricklet_stack, uint8_t *data, const uint8_t length) { uint8_t checksum = 0; bricklet_stack->buffer_send_length = length + SPITFP_PROTOCOL_OVERHEAD; bricklet_stack->buffer_send[0] = bricklet_stack->buffer_send_length; PEARSON(checksum, bricklet_stack->buffer_send_length); bricklet_stack->buffer_send[1] = bricklet_stack_get_sequence_byte(bricklet_stack, true); PEARSON(checksum, bricklet_stack->buffer_send[1]); for(uint8_t i = 0; i < length; i++) { bricklet_stack->buffer_send[2+i] = data[i]; PEARSON(checksum, bricklet_stack->buffer_send[2+i]); } bricklet_stack->buffer_send[length + SPITFP_PROTOCOL_OVERHEAD-1] = checksum; bricklet_stack->ack_to_send = false; bricklet_stack->last_send_started = bricklet_stack_get_ms(); }
static void ICACHE_FLASH_ATTR uart_con_loop(os_event_t *events) { com_poll(); // If the uart buffer is empty, we try to get data from tfp ringbuffer if(uart_con_buffer_send_size == 0) { tfp_poll(); } if(uart_con_buffer_recv_wait_for_tfp) { if(tfp_send(&uart_con_buffer_recv[UART_CON_INDEX_TFP_START], uart_con_buffer_recv_expected_length-3)) { uart_con_buffer_recv_index = 0; uart_con_buffer_recv_expected_length = 3; uart_con_buffer_recv_wait_for_tfp = false; } system_os_post(uart_con_prio, 0, 0); return; } while(uart_get_rx_fifo_count(UART_CONNECTION) > 0) { uart_con_buffer_recv[uart_con_buffer_recv_index] = uart_rx(UART_CONNECTION); if(uart_con_buffer_recv_index == UART_CON_INDEX_LENGTH) { // TODO: Sanity-check length uart_con_buffer_recv_expected_length = uart_con_buffer_recv[UART_CON_INDEX_LENGTH]; if(uart_con_buffer_recv_expected_length > UART_CON_BUFFER_SIZE) { logw("Length is malformed: %d > %d\n", uart_con_buffer_recv_expected_length, UART_CON_BUFFER_SIZE); uart_con_clear_rx_dma(); } } uart_con_buffer_recv_index++; if(uart_con_buffer_recv_index >= uart_con_buffer_recv_expected_length) { uint8_t checksum_calculated = 0; for(uint8_t i = 0; i < uart_con_buffer_recv_index-1; i++) { PEARSON(checksum_calculated, uart_con_buffer_recv[i]); } const uint8_t checksum_uart = uart_con_buffer_recv[uart_con_buffer_recv_index-1]; if(checksum_calculated != checksum_uart) { logw("Checksum error: %d (calc) != %d (uart)\n", checksum_calculated, checksum_uart); logw("uart recv data: %d %d [", uart_con_buffer_recv_index, uart_con_buffer_recv_expected_length); for(uint8_t i = 0; i < uart_con_buffer_recv_expected_length; i++) { logwohw("%d ", uart_con_buffer_recv[i]); } logwohw("]\n"); uart_con_clear_rx_dma(); break; } if(uart_con_buffer_recv_expected_length != 3) { const uint8_t seq = uart_con_buffer_recv[UART_CON_INDEX_SEQUENCE] & 0x0F; if(uart_con_last_sequence_number_seen != seq) { if(!tfp_send(&uart_con_buffer_recv[UART_CON_INDEX_TFP_START], uart_con_buffer_recv_expected_length-3)) { uart_con_buffer_recv_wait_for_tfp = true; } uart_con_last_sequence_number_seen = seq; } ack_last_message(); } const uint8_t seq_seen_by_master = uart_con_buffer_recv[UART_CON_INDEX_SEQUENCE] >> 4; if(wait_for_ack) { if(seq_seen_by_master == uart_con_sequence_number) { os_timer_disarm(&timeout_timer); wait_for_ack = false; uart_con_sequence_number++; if(uart_con_sequence_number >= 0x10) { uart_con_sequence_number = 1; } uart_con_buffer_send_size = 0; } } if(!uart_con_buffer_recv_wait_for_tfp) { uart_con_buffer_recv_index = 0; uart_con_buffer_recv_expected_length = 3; } else { // If we have to wait for tfp, we need to break out of the while loop. break; } } }
void SPI_IrqHandler(void) { if(spi_stack_buffer_size_recv != 0) { return; } // Disable SPI interrupt and interrupt controller SPI_DisableIt(SPI, SPI_IER_RDRF); __disable_irq(); uint8_t slave_checksum = 0; uint8_t master_checksum = 0; PEARSON(slave_checksum, spi_stack_buffer_size_send); volatile uint8_t dummy; // Empty read register while((SPI->SPI_SR & SPI_SR_RDRF) == 0); dummy = SPI->SPI_RDR; while((SPI->SPI_SR & SPI_SR_RDRF) == 0); dummy = SPI->SPI_RDR; // Synchronize with master while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = 0xFF; while((SPI->SPI_SR & SPI_SR_RDRF) == 0); dummy = SPI->SPI_RDR; // Write length while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = spi_stack_buffer_size_send; // Write first byte while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = spi_stack_buffer_send[0]; PEARSON(slave_checksum, spi_stack_buffer_send[0]); // Read length from master while((SPI->SPI_SR & SPI_SR_RDRF) == 0); uint8_t master_length = SPI->SPI_RDR; PEARSON(master_checksum, master_length); // If master and slave length are 0, stop communication if(master_length == 0 && spi_stack_buffer_size_send == 0) { // Read dummy while((SPI->SPI_SR & SPI_SR_RDRF) == 0); dummy = SPI->SPI_RDR; // Write 0 (so there is no random 0xFF) SPI->SPI_TDR = 0; SPI_EnableIt(SPI, SPI_IER_RDRF); __enable_irq(); return; } // Length to transceive is maximum of slave and master length uint8_t max_length = MIN(MAX(spi_stack_buffer_size_send, master_length), SPI_STACK_BUFFER_SIZE); // Exchange data for(uint8_t i = 1; i < max_length; i++) { // Write while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = spi_stack_buffer_send[i]; PEARSON(slave_checksum, spi_stack_buffer_send[i]); // Read while((SPI->SPI_SR & SPI_SR_RDRF) == 0); spi_stack_buffer_recv[i-1] = SPI->SPI_RDR; PEARSON(master_checksum, spi_stack_buffer_recv[i-1]); } // Write CRC while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = slave_checksum; // Read last data byte while((SPI->SPI_SR & SPI_SR_RDRF) == 0); spi_stack_buffer_recv[max_length-1] = SPI->SPI_RDR; PEARSON(master_checksum, spi_stack_buffer_recv[max_length-1]); // Read CRC while((SPI->SPI_SR & SPI_SR_RDRF) == 0); uint8_t crc = SPI->SPI_RDR; // CRC correct? uint8_t slave_ack = crc == master_checksum; // Write ACK/NACK while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = slave_ack; // Read ACK/NACK while((SPI->SPI_SR & SPI_SR_RDRF) == 0); uint8_t master_ack = SPI->SPI_RDR; // If everything OK, set sizes accordingly if(master_ack == 1 && slave_ack == 1) { spi_stack_buffer_size_recv = master_length; spi_stack_buffer_size_send = 0; } // Last byte written is 1 or 0 (ack/nack), so there can't be an // accidental 0xFF // Enable SPI interrupt only if no new data is received. // Otherwise the spi_recv function will enable interrupt again. if(spi_stack_buffer_size_recv == 0) { SPI_EnableIt(SPI, SPI_IER_RDRF); } __enable_irq(); }
bool spi_stack_master_transceive(void) { uint8_t master_checksum = 0; uint8_t slave_checksum = 0; uint8_t send_length = spi_stack_buffer_size_send; volatile uint8_t dummy = 0; __disable_irq(); SPI->SPI_SR; SPI->SPI_RDR; uint16_t timeout = SPI_STACK_MASTER_TIMEOUT; // Sync with slave while(dummy != 0xFF && timeout != 0) { while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = 0xFF; while((SPI->SPI_SR & SPI_SR_RDRF) == 0); dummy = SPI->SPI_RDR; timeout--; } if(timeout == 0) { logspise("Timeout, did not receive 0xFF from Slave\n\r"); __enable_irq(); return false; } // Write length while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = send_length; PEARSON(master_checksum, send_length); // Write first byte while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = spi_stack_buffer_send[0]; PEARSON(master_checksum, spi_stack_buffer_send[0]); // Read length while((SPI->SPI_SR & SPI_SR_RDRF) == 0); uint8_t slave_length = SPI->SPI_RDR; PEARSON(slave_checksum, slave_length); // If master and slave length are 0, stop communication if(slave_length == 0 && send_length == 0) { // Read dummy while((SPI->SPI_SR & SPI_SR_RDRF) == 0); dummy = SPI->SPI_RDR; __enable_irq(); return true; } // Length to transceive is maximum of slave and master length uint8_t max_length = MIN(MAX(send_length, slave_length), SPI_STACK_BUFFER_SIZE); // Exchange data for(uint8_t i = 1; i < max_length; i++) { // Write while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = spi_stack_buffer_send[i]; PEARSON(master_checksum, spi_stack_buffer_send[i]); // Read while((SPI->SPI_SR & SPI_SR_RDRF) == 0); spi_stack_buffer_recv[i-1] = SPI->SPI_RDR; PEARSON(slave_checksum, spi_stack_buffer_recv[i-1]); } // Write CRC while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = master_checksum; // Read last data byte while((SPI->SPI_SR & SPI_SR_RDRF) == 0); spi_stack_buffer_recv[max_length-1] = SPI->SPI_RDR; PEARSON(slave_checksum, spi_stack_buffer_recv[max_length-1]); // Read CRC while((SPI->SPI_SR & SPI_SR_RDRF) == 0); uint8_t crc = SPI->SPI_RDR; // Is CRC correct? uint8_t master_ack = crc == slave_checksum; __NOP(); __NOP(); __NOP(); // Write ACK/NACK while((SPI->SPI_SR & SPI_SR_TDRE) == 0); SPI->SPI_TDR = master_ack; // Read ACK/NACK while((SPI->SPI_SR & SPI_SR_RDRF) == 0); uint8_t slave_ack = SPI->SPI_RDR; // If everything is OK, set sizes accordingly if(slave_ack == 1 && master_ack == 1) { spi_stack_buffer_size_recv = slave_length; if(send_length != 0) { spi_stack_buffer_size_send = 0; } } else { if(!master_ack) { logspisw("Checksum: Master(%d) != Slave(%d)\n\r", crc, slave_checksum); } if(!slave_ack) { logspisw("Checksum: Received NACK from Slave\n\r"); } __enable_irq(); return false; } __enable_irq(); return true; }
static void bricklet_stack_check_message(BrickletStack *bricklet_stack) { // If the temporary buffer length is > 0 we still have a message to handle if(bricklet_stack->buffer_recv_tmp_length > 0) { // Try to send message to Bricklet if(bricklet_stack_handle_message_from_bricklet(bricklet_stack, bricklet_stack->buffer_recv_tmp, bricklet_stack->buffer_recv_tmp_length)) { bricklet_stack->buffer_recv_tmp_length = 0; // If we were able to send message to Bricklet, try to send ACK if(bricklet_stack_is_send_possible(bricklet_stack)) { bricklet_stack_send_ack(bricklet_stack); } else { // If we can't send the ack we set a flag here and the ACK is send later on. // If we aren't fast enough the slave may send us a duplicate of the message, // but the duplicate will be thrown away since the sequence number will not // be increased in the meantime. bricklet_stack->ack_to_send = true; } } } // Check if we didn't receive an ACK within the timeout time and resend the message if necessary. bricklet_stack_check_message_send_timeout(bricklet_stack); uint8_t message[TFP_MESSAGE_MAX_LENGTH] = {0}; uint8_t message_position = 0; uint16_t num_to_remove_from_ringbuffer = 0; uint8_t checksum = 0; uint8_t data_sequence_number = 0; uint8_t data_length = 0; SPITFPState state = SPITFP_STATE_START; uint16_t used = ringbuffer_get_used(&bricklet_stack->ringbuffer_recv); uint16_t start = bricklet_stack->ringbuffer_recv.start; for(uint16_t i = start; i < start+used; i++) { const uint16_t index = i & BRICKLET_STACK_SPI_RECEIVE_BUFFER_MASK; const uint8_t data = bricklet_stack->buffer_recv[index]; // Handle "standard case" first (we are sending data and Master has nothing to send) if(state == SPITFP_STATE_START && data == 0) { // equivalent (but faster) to "ringbuffer_remove(&bricklet_stack->ringbuffer_recv, 1);" bricklet_stack->ringbuffer_recv.start = (bricklet_stack->ringbuffer_recv.start + 1) & BRICKLET_STACK_SPI_RECEIVE_BUFFER_MASK; continue; } num_to_remove_from_ringbuffer++; switch(state) { case SPITFP_STATE_START: { checksum = 0; message_position = 0; if(data == SPITFP_PROTOCOL_OVERHEAD) { state = SPITFP_STATE_ACK_SEQUENCE_NUMBER; } else if(data >= SPITFP_MIN_TFP_MESSAGE_LENGTH && data <= SPITFP_MAX_TFP_MESSAGE_LENGTH) { state = SPITFP_STATE_MESSAGE_SEQUENCE_NUMBER; } else if(data == 0) { // equivalent (but faster) to "ringbuffer_remove(&bricklet_stack->ringbuffer_recv, 1);" bricklet_stack->ringbuffer_recv.start = (bricklet_stack->ringbuffer_recv.start + 1) & BRICKLET_STACK_SPI_RECEIVE_BUFFER_MASK; num_to_remove_from_ringbuffer--; break; } else { // If the length is not PROTOCOL_OVERHEAD or within [MIN_TFP_MESSAGE_LENGTH, MAX_TFP_MESSAGE_LENGTH] // or 0, something has gone wrong! bricklet_stack->error_count_frame++; bricklet_stack_handle_protocol_error(bricklet_stack); log_debug("Frame error (count=%u)", bricklet_stack->error_count_frame); return; } data_length = data; if((start+used - i) < data_length) { // There can't be enough data for a whole message, we can return here. return; } PEARSON(checksum, data_length); break; } case SPITFP_STATE_ACK_SEQUENCE_NUMBER: { data_sequence_number = data; PEARSON(checksum, data_sequence_number); state = SPITFP_STATE_ACK_CHECKSUM; break; } case SPITFP_STATE_ACK_CHECKSUM: { // Whatever happens here, we will go to start again and remove // data from ringbuffer state = SPITFP_STATE_START; ringbuffer_remove(&bricklet_stack->ringbuffer_recv, num_to_remove_from_ringbuffer); num_to_remove_from_ringbuffer = 0; if(checksum != data) { bricklet_stack->error_count_ack_checksum++; bricklet_stack_handle_protocol_error(bricklet_stack); log_debug("ACK checksum error (count=%u)", bricklet_stack->error_count_ack_checksum); return; } uint8_t last_sequence_number_seen_by_slave = (data_sequence_number & 0xF0) >> 4; if(last_sequence_number_seen_by_slave == bricklet_stack->current_sequence_number) { bricklet_stack->buffer_send_length = 0; bricklet_stack->wait_for_ack = false; } break; } case SPITFP_STATE_MESSAGE_SEQUENCE_NUMBER: { data_sequence_number = data; PEARSON(checksum, data_sequence_number); state = SPITFP_STATE_MESSAGE_DATA; break; } case SPITFP_STATE_MESSAGE_DATA: { message[message_position] = data; message_position++; PEARSON(checksum, data); if(message_position == data_length - SPITFP_PROTOCOL_OVERHEAD) { state = SPITFP_STATE_MESSAGE_CHECKSUM; } break; } case SPITFP_STATE_MESSAGE_CHECKSUM: { // Whatever happens here, we will go to start again state = SPITFP_STATE_START; // Remove data from ringbuffer. If we can't send it we can't handle // it at the moment we will wait for the SPI master to re-send it. ringbuffer_remove(&bricklet_stack->ringbuffer_recv, num_to_remove_from_ringbuffer); num_to_remove_from_ringbuffer = 0; if(checksum != data) { bricklet_stack->error_count_message_checksum++; bricklet_stack_handle_protocol_error(bricklet_stack); log_debug("Message checksum error (count=%u)", bricklet_stack->error_count_message_checksum); return; } uint8_t last_sequence_number_seen_by_slave = (data_sequence_number & 0xF0) >> 4; if(last_sequence_number_seen_by_slave == bricklet_stack->current_sequence_number) { bricklet_stack->buffer_send_length = 0; bricklet_stack->wait_for_ack = false; } // If we already have one recv message in the temporary buffer, // we don't handle the newly received message and just throw it away. // The SPI master will send it again. if(bricklet_stack->buffer_recv_tmp_length == 0) { // If sequence number is new, we can handle the message. // Otherwise we only ACK the already handled message again. const uint8_t message_sequence_number = data_sequence_number & 0x0F; if((message_sequence_number != bricklet_stack->last_sequence_number_seen) || (message_sequence_number == 1)) { // For the special case that the sequence number is 1 (only used for the very first message) // we always send an answer, even if we haven't seen anything else in between. // Otherwise it is not possible to reset the Master Brick if no messages were exchanged before // the reset bricklet_stack->last_sequence_number_seen = message_sequence_number; // The handle message function will send an ACK for the message // if it can handle the message at the current moment. // Otherwise it will save the message and length for it it be send // later on. if(bricklet_stack_handle_message_from_bricklet(bricklet_stack, message, message_position)) { if(bricklet_stack_is_send_possible(bricklet_stack)) { bricklet_stack_send_ack(bricklet_stack); } else { bricklet_stack->ack_to_send = true; } } else { bricklet_stack->buffer_recv_tmp_length = message_position; memcpy(bricklet_stack->buffer_recv_tmp, message, message_position); } } else { if(bricklet_stack_is_send_possible(bricklet_stack)) { bricklet_stack_send_ack(bricklet_stack); } else { bricklet_stack->ack_to_send = true; } } } return; } } } }