#include <stdio.h> #include "uart_buff.h" #include <stdlib.h> // function prototype declarations specific to the circular buffer void uart_buff_scan_packet(); void uart_buff_scan_packet_start(); void uart_buff_scan_packet_size(); size_t uart_buff_packet_size(); size_t uart_buff_calc_index(int); static volatile u8 buff[UART_MAX_BUFF_SIZE]; u8 packet_buff[UART_MAX_PACKET_SIZE]; static size_t start = 0; static volatile size_t end = 0; static size_t packet_data_length = 0; static u8 packet_ready = 0; // TODO: Delete these debugging variables static u32 packets_processed = 0; /** * Put a byte into the buffer. */ void uart_buff_add_u8(u8 c) { if (uart_buff_full()) { return; } buff[end] = c; end += 1; if (end >= UART_MAX_BUFF_SIZE) { end -= UART_MAX_BUFF_SIZE; } } /** * Scan for a packet, updating any necessary indices and flags. */ void uart_buff_scan_packet() { size_t scan_limit = uart_buff_size(); size_t scan_iteration = 0; while (!packet_ready && scan_iteration < scan_limit) { scan_iteration += 1; if (buff[start] != 0xBE) { start += 1; if (start >= UART_MAX_BUFF_SIZE) { start -= UART_MAX_BUFF_SIZE; } continue; } if (uart_buff_size() < UART_PACKET_HEADER_SIZE) { // Haven't received the "length" bytes yet. Check back later. break; } packet_data_length = (uart_buff_get_u8(6) << 8) | uart_buff_get_u8(5); if (uart_buff_packet_size() > UART_MAX_PACKET_SIZE) { // Packet size is too big. Abort this packet. start += 1; if (start >= UART_MAX_BUFF_SIZE) { start -= UART_MAX_BUFF_SIZE; } continue; } if (uart_buff_size() < uart_buff_packet_size()) { // Haven't received the whole packet. Check back later. break; } packet_ready = 1; } } /** * Return 1 if a packet is ready to processed, 0 otherwise. */ int uart_buff_packet_ready() { if (!packet_ready) { uart_buff_scan_packet(); } return packet_ready; } /** * Retrieve a 8-bit from the buffer according to the given offset with respect * to the start index of the current packet. */ u8 uart_buff_get_u8(size_t offset) { size_t index = start + offset; if (index >= UART_MAX_BUFF_SIZE) { index -= UART_MAX_BUFF_SIZE; } return buff[index]; } /** * Retrieve a 16-bit unsigned integer from the buffer according to the given * offset with respect to the start index of the current packet. */ u16 uart_buff_get_u16(size_t offset) { size_t index_1 = start + offset + 1; size_t index = start + offset; // Check common cases first if (index_1 < UART_MAX_BUFF_SIZE) { // in range, no need to correct indices } else if (index >= UART_MAX_BUFF_SIZE) { index_1 -= UART_MAX_BUFF_SIZE; index -= UART_MAX_BUFF_SIZE; } else { index_1 -= UART_MAX_BUFF_SIZE; } return buff[index_1] << 8 | buff[index]; } /** * Retrieve a 32-bit from the buffer according to the given offset with respect * to the start index of the current packet. */ u32 uart_buff_get_u32(size_t offset) { size_t index_3 = start + offset + 3; size_t index_2 = start + offset + 2; size_t index_1 = start + offset + 1; size_t index = start + offset; if (index_3 < UART_MAX_BUFF_SIZE) { // in range, no need to correct indices } else if (index >= UART_MAX_BUFF_SIZE) { index_3 -= UART_MAX_BUFF_SIZE; index_2 -= UART_MAX_BUFF_SIZE; index_1 -= UART_MAX_BUFF_SIZE; index -= UART_MAX_BUFF_SIZE; } else { index_3 = uart_buff_calc_index(index_3); index_2 = uart_buff_calc_index(index_2); index_1 = uart_buff_calc_index(index_1); index = uart_buff_calc_index(index); } return buff[index_3] << 24 | buff[index_2] << 16 | buff[index_1] << 8 | buff[index]; } /** * Retrieve a 8-bit unsigned integer from the buffer according to * the given offset with respect to the start of the data portion * of the current packet. * * This has undefined behavior if a packet is not ready. */ u8 uart_buff_data_get_u8(size_t offset) { size_t index = start + UART_PACKET_HEADER_SIZE + offset; if (index >= UART_MAX_BUFF_SIZE) { index -= UART_MAX_BUFF_SIZE; } return buff[index]; } /** * Retrieve a 16-bit unsigned integer from the buffer according to * the given offset with respect to the start of the data portion * of the current packet. * * This has undefined behavior if a packet is not ready. */ u16 uart_buff_data_get_u16(size_t offset) { size_t index_1 = start + UART_PACKET_HEADER_SIZE + offset + 1; size_t index = start + UART_PACKET_HEADER_SIZE + offset; // Check common cases first if (index_1 < UART_MAX_BUFF_SIZE) { // in range, no need to correct indices } else if (index >= UART_MAX_BUFF_SIZE) { index_1 -= UART_MAX_BUFF_SIZE; index -= UART_MAX_BUFF_SIZE; } else { index_1 -= UART_MAX_BUFF_SIZE; } return buff[index_1] << 8 | buff[index]; } /** * Retrieve a 32-bit unsigned integer from the buffer according to * the given offset with respect to the start of the data portion * of the current packet. * * This has undefined behavior if a packet is not ready. */ u32 uart_buff_data_get_u32(size_t offset) { size_t index_3 = start + UART_PACKET_HEADER_SIZE + offset + 3; size_t index_2 = start + UART_PACKET_HEADER_SIZE + offset + 2; size_t index_1 = start + UART_PACKET_HEADER_SIZE + offset + 1; size_t index = start + UART_PACKET_HEADER_SIZE + offset; if (index_3 < UART_MAX_BUFF_SIZE) { // in range, no need to correct indices } else if (index >= UART_MAX_BUFF_SIZE) { index_3 -= UART_MAX_BUFF_SIZE; index_2 -= UART_MAX_BUFF_SIZE; index_1 -= UART_MAX_BUFF_SIZE; index -= UART_MAX_BUFF_SIZE; } else { index_3 = uart_buff_calc_index(index_3); index_2 = uart_buff_calc_index(index_2); index_1 = uart_buff_calc_index(index_1); index = uart_buff_calc_index(index); } return buff[index_3] << 24 | buff[index_2] << 16 | buff[index_1] << 8 | buff[index]; } /** * Retrieve a 32-bit floating point number from the buffer according to the * given offset with respect to the start of the data portion of the current * packet. * * This has undefined behavior if a packet is not ready. */ float uart_buff_data_get_float(size_t offset) { size_t index_3 = start + UART_PACKET_HEADER_SIZE + offset + 3; size_t index_2 = start + UART_PACKET_HEADER_SIZE + offset + 2; size_t index_1 = start + UART_PACKET_HEADER_SIZE + offset + 1; size_t index = start + UART_PACKET_HEADER_SIZE + offset; if (index_3 < UART_MAX_BUFF_SIZE) { // in range, no need to correct indices } else if (index >= UART_MAX_BUFF_SIZE) { index_3 -= UART_MAX_BUFF_SIZE; index_2 -= UART_MAX_BUFF_SIZE; index_1 -= UART_MAX_BUFF_SIZE; index -= UART_MAX_BUFF_SIZE; } else { index_3 = uart_buff_calc_index(index_3); index_2 = uart_buff_calc_index(index_2); index_1 = uart_buff_calc_index(index_1); index = uart_buff_calc_index(index); } union { float f; int i; } x; x.i = buff[index_3] << 24 | buff[index_2] << 16 | buff[index_1] << 8 | buff[index]; return x.f; } /** * Move the start index of the buffer to the end of the current packet. * If a packet is not ready, this function does nothing. */ void uart_buff_consume_packet() { if (!packet_ready) { return; } start = uart_buff_calc_index(start + uart_buff_packet_size()); packet_ready = 0; packets_processed += 1; } /** * Return the current number of bytes held in the buffer. */ size_t uart_buff_size() { int size = end - start; if (size < 0) { size += UART_MAX_BUFF_SIZE; } return size; } /** * Return the length of the data portion of the current packet. */ size_t uart_buff_data_length() { return packet_data_length; } /** * Return the size of the current packet. */ inline size_t uart_buff_packet_size() { return UART_PACKET_HEADER_SIZE + packet_data_length + 1; } /** * Return 1 if the buffer is empty, 0 otherwise. */ int uart_buff_empty() { return start == end; } /** * Return 1 if the buffer is full, 0 otherwise. */ int uart_buff_full() { int effective_end = end + 1; if (effective_end >= UART_MAX_BUFF_SIZE) { effective_end -= UART_MAX_BUFF_SIZE; } return start == effective_end; } /** * Calculate the actual index from the given index, wrapping around * the edges of the circular buffer if necessary. */ size_t uart_buff_calc_index(int given_index) { int actual_index = given_index; if (actual_index >= UART_MAX_BUFF_SIZE) { actual_index -= UART_MAX_BUFF_SIZE; } return actual_index; } /** * Return a pointer to the start of the packet. */ u8 * uart_buff_get_raw(size_t *packet_size) { // Copy packet into temp buffer *packet_size = uart_buff_packet_size(); int i; for (i = 0; i < *packet_size; i += 1) { packet_buff[i] = uart_buff_get_u8(i); } return packet_buff; } /** * Print the buffer with a pretty ASCII art image. */ void uart_buff_print() { size_t packet_size = uart_buff_packet_size(); size_t data_start = uart_buff_calc_index(start + UART_PACKET_HEADER_SIZE); size_t data_end = uart_buff_calc_index(start + packet_size); int i; printf("buffer size = %zu\n", uart_buff_size()); puts("Buffer:"); puts(".--."); puts("| |"); puts("| v"); for (i = 0; i < UART_MAX_BUFF_SIZE; i += 1) { printf("| %02X", buff[i]); if (i == start) { printf("<-- start"); } if (packet_ready) { if (i == data_start) { printf("<-- data start"); } if (i == data_end) { printf("<-- data end"); } } if (i == end) { printf("<-- end"); } printf("\n"); } puts("| |"); puts("'--'"); } /** * Reset the state of the buffer. */ void uart_buff_reset() { start = 0; end = 0; int i; for (i = 0; i < UART_MAX_BUFF_SIZE; i += 1) { buff[i] = 0; } packet_ready = 0; } /** * Return the total number of packets processed. */ u32 uart_buff_packets_processed() { return packets_processed; }