#include <cstdio>
#include <cstring>

#include "main.h"
#include "usart.h"

#include "gsm_rx_thread.h"

static constexpr unsigned INPUT_BUF_SIZE = 256U;
static constexpr unsigned RING_SIZE = 10U;
static constexpr unsigned QUEUE_STACK_SIZE = 128U;

struct RingBuffer_t
{
	unsigned actual_size;
	char buf[INPUT_BUF_SIZE];
};


alignas(32) static char ibuf[INPUT_BUF_SIZE]									__attribute__((section(".RAM1")));
static RingBuffer_t ring[RING_SIZE]												__attribute__((section(".DTCM_RAM")));
alignas(ULONG)static uint8_t queue_stack[QUEUE_STACK_SIZE]						__attribute__((section(".DTCM_RAM")));

TX_QUEUE queue_ptr;
static unsigned ring_pos;

VOID gsmRxThread(ULONG initial_input)
{
	(void)initial_input;

	extern DMA_HandleTypeDef hdma_usart3_rx;

	static UINT queueIsCreated = tx_queue_create(&queue_ptr, (char*)"GSM RX Queue", 1 , queue_stack, 4U*RING_SIZE);
	if (queueIsCreated != TX_SUCCESS) printf("Cannot create GSM RX queue!\n");

	HAL_UARTEx_ReceiveToIdle_DMA(&huart3, (uint8_t*)ibuf, INPUT_BUF_SIZE);
	__HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);

	while(1)
	{
		if (queueIsCreated == TX_SUCCESS)
		{
			static RingBuffer_t* ptr = nullptr;
			UINT res = tx_queue_receive(&queue_ptr, &ptr, TX_WAIT_FOREVER);
			if (res == TX_SUCCESS)
			{
				if (ptr->actual_size > INPUT_BUF_SIZE) ptr->actual_size = INPUT_BUF_SIZE;
				printf("\tGot %02u bytes: [", ptr->actual_size);
				for (auto i = 0U; i < ptr->actual_size; i++)
				{
					printf("%c", ptr->buf[i] >= 0x20 ? ptr->buf[i]: '_');
					//tx_thread_sleep(1);
				}
				printf("]\n");
			}
			else tx_thread_sleep(1000);
		}
		else tx_thread_sleep(10000);
	}
}

//------------------------------------------------------------------------------

void gsmRxData(unsigned bytesNum)
{
	extern DMA_HandleTypeDef hdma_usart3_rx;
	//static char* dest = nullptr;
	//static char* source = nullptr;
	static unsigned i;

	/*printf("\tGot %u bytes!\n", bytesNum);
	printf("\t[");
	for (auto j = 0U; j < bytesNum; j++)
		printf("%c", ibuf[j] >= 0x20 ? ibuf[j]: '_');
	printf("]\n");*/
	//strncat(ibuf_local, ibuf, bytesNum);
	SCB_InvalidateDCache_by_Addr((uint32_t*)ibuf, INPUT_BUF_SIZE);
	i = ring_pos % RING_SIZE;
	//printf("%u\n", i);
	//dest = &ring[i].buf[0];
	//source = ibuf;
	//memcpy(dest, source, bytesNum);
	for (auto j = 0U; j < bytesNum; j++) ring[i].buf[j] = ibuf[j];
	ring[i].actual_size = bytesNum;
	RingBuffer_t* ptr = &ring[i];
	//printf("%p\n", (void*)ptr);
	tx_queue_send(&queue_ptr, &ptr, TX_NO_WAIT);
	ring_pos++;

	HAL_UARTEx_ReceiveToIdle_DMA(&huart3, (uint8_t*)ibuf, INPUT_BUF_SIZE);
	__HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
}