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);
}
示例#2
0
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;
}
示例#4
0
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;
			}
		}
	}
示例#6
0
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();
}
示例#7
0
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;
}
示例#8
0
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;
			}
		}
	}
}