//*******************serial port API **********
#include <sys/ring_buffer.h>
#include "serial_api.h"
//********************************** BMS ********************
unsigned int bms_tx_get_from_queue(void)
{
	uint8_t *data_ptr;
	// Try to claim any available bytes in the FIFO
	bms_bytes_claimed = ring_buf_get_claim(&bms_tx_fifo, &data_ptr, CONFIG_BMS_UART_TX_BUF_SIZE);

	if(bms_bytes_claimed > 0) {
		// Start a UART transmission based on the number of available bytes
		uart_tx(bms_uart, data_ptr, bms_bytes_claimed, SYS_FOREVER_MS);
	}
	return bms_bytes_claimed;
}

void bms_uart_async_callback(const struct device *uart_dev, struct uart_event *evt, void *user_data)
{
	static struct bms_msg_queue_item bms_new_message;

	switch (evt->type) {
		case UART_TX_DONE:
			// Free up the written bytes in the TX FIFO
			ring_buf_get_finish(&bms_tx_fifo, bms_bytes_claimed);

			// If there is more data in the TX fifo, start the transmission
			if(bms_tx_get_from_queue() == 0) {
				// Or release the semaphore if the TX fifo is empty
				k_sem_give(&bms_tx_done);
                                bms_transmit_done = true;
			}
			break;
		
		case UART_RX_RDY:
			memcpy(bms_new_message.bytes, evt->data.rx.buf + evt->data.rx.offset, evt->data.rx.len);
			bms_new_message.length = evt->data.rx.len;
			if(k_msgq_put(&bms_rx_msgq, &bms_new_message, K_NO_WAIT) != 0){
				/*printk("Error: Uart1 RX message queue full!\n");*/
				
			}
			break;
		
		case UART_RX_BUF_REQUEST:
			uart_rx_buf_rsp(bms_uart, bms_buf_next, CONFIG_BMS_UART_BUF_SIZE);
			break;

		case UART_RX_BUF_RELEASED:
			bms_buf_next = evt->data.rx_buf.buf;
			break;

		case UART_RX_DISABLED:
			k_sem_give(&bms_rx_disabled);
			break;
		
		default:
			break;
	}
}

 void bms_uart_init(void)
{
        
	bms_uart = device_get_binding("UART_1");
	if (bms_uart == NULL) {
		printk("Failed to get UART1 binding\n");
		
		return;        
	}
	uart_callback_set(bms_uart, bms_uart_async_callback, NULL);
	uart_rx_enable(bms_uart, bms_double_buffer[0], CONFIG_BMS_UART_BUF_SIZE, BMS_UART_RX_TIMEOUT_MS);
}

// Function to send UART data, by writing it to a ring buffer (FIFO) in the application
// WARNING: This function is not thread safe! If you want to call this function from multiple threads a semaphore should be used
unsigned int bms_uart_send(const uint8_t * data_ptr, uint32_t data_len)
{
	while(1) {
		// Try to move the data into the TX ring buffer
		uint32_t written_to_buf = ring_buf_put(&bms_tx_fifo, data_ptr, data_len);
		data_len -= written_to_buf;
		
		// In case the UART TX is idle, start transmission
		if(k_sem_take(&bms_tx_done, K_NO_WAIT) == 0) {
			bms_tx_get_from_queue();
		}	
		
		// In case all the data was written, exit the loop
		if(data_len == 0) break;

		// In case some data is still to be written, sleep for some time and run the loop one more time
		k_msleep(10);
		data_ptr += written_to_buf;
	}

	return 0;
}
