#include <cstdio>

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

#include "gsm_thread.h"
#include "utils.h"


static constexpr GPIO_PinState GSM_POWER_LO_LEVEL = GPIO_PIN_SET;
static constexpr GPIO_PinState GSM_POWER_HI_LEVEL = GPIO_PIN_RESET;

static constexpr GPIO_PinState GSM_STATUS_MODULE_IS_ON = GPIO_PIN_SET;
static constexpr GPIO_PinState GSM_STATUS_MODULE_IS_OFF = GPIO_PIN_RESET;


static constexpr unsigned PWR_PULSE_DELAY_MS = 50U;								// See datasheet for A7672X
static constexpr ULONG PWR_STATUS_DELAY_MS = 10000U;							// See datasheet for A7672X (Typ. 7s)

static const char* const TAG = "GSM";
static uint16_t delay_ms = 5000U;

static const char* const PREFIX = "AT";
static const char* const PLUS = "+";
static const char* const EQUAL = "=";
static const char* const QUESTION = "?";
static const char* const CR = "\r";
static const char* const FMT = "%s\n";

static const char* const SIGNAL_QUALITY = "CSQ";

static Gsm_req_resp_t rr[] = {
							  {}
							  };

static constexpr unsigned INPUT_BUF_SIZE = 512U;
static constexpr unsigned OUTPUT_BUF_SIZE = 64U;
static char ibuf[INPUT_BUF_SIZE]	  __attribute__((section(".RAM1")));
static char input_buf[INPUT_BUF_SIZE] __attribute__((section(".RAM1")));
static char obuf[OUTPUT_BUF_SIZE]	  __attribute__((section(".RAM1")));
static unsigned input_buf_num;

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

void TurnGSMModuleOn(void);

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

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

	TurnGSMModuleOn();

	HAL_UARTEx_ReceiveToIdle_DMA(&huart3, (uint8_t*)ibuf, INPUT_BUF_SIZE);

	while(1)
	{
		tx_thread_sleep(delay_ms);

		sprintf(obuf, "%s%s", "AT+CSQ", CR);
		HAL_UART_Transmit_DMA(&huart3, (uint8_t*)obuf, strlen(obuf));


		if (input_buf_num)
		{
			printf("\n");
			for (auto i = 0U; i < input_buf_num; i++) printf("%c", ibuf[i]);
			printf("\n");
			input_buf_num = 0;
		}

		printThreadStackInfo(TAG);
	}
}

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

void gsmUnitSentData(unsigned BytesNum)
{
	// Putting data into queue
	memcpy(input_buf, ibuf, BytesNum);
	input_buf_num = BytesNum;
}

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

void TurnGSMModuleOn(void)
{
	// Activating power for GSM-unit
	HAL_GPIO_WritePin(POWER_4V_EN_GPIO_Port, POWER_4V_EN_Pin, GPIO_PIN_SET);

	// 4V power supply stabilization time
	tx_thread_sleep(1000U);

	// Checking whether STATUS pin for some reason is already set
	if (HAL_GPIO_ReadPin(GSM_STATUS_GPIO_Port, GSM_STATUS_Pin) == GSM_STATUS_MODULE_IS_OFF)
	{
		printf("GSM-module is OFF\n");

		constexpr int ATTEMPTS = 5;
		if ([]	  // Lambda checks if we exited after all attempts or earlier
			{
        		for (auto i = 1; i <= ATTEMPTS; i++)
        		{
        			printf("Trying to turn GSM-module ON...\n");

        			HAL_GPIO_WritePin(GSM_PWR_GPIO_Port, GSM_PWR_Pin, GSM_POWER_LO_LEVEL);
        			tx_thread_sleep(PWR_PULSE_DELAY_MS);
        			HAL_GPIO_WritePin(GSM_PWR_GPIO_Port, GSM_PWR_Pin, GSM_POWER_HI_LEVEL);

        			if ([]	  // Lambda checks if we exited after delay or before it
        				{
        					auto current_time = tx_time_get();
        					while (tx_time_get() - current_time < PWR_STATUS_DELAY_MS)
        					{
        						tx_thread_sleep(100U);
        						if (HAL_GPIO_ReadPin(GSM_STATUS_GPIO_Port, GSM_STATUS_Pin) == GSM_STATUS_MODULE_IS_ON)
        						{
        							printf("GSM-module is ON. Start-up time is approx. %lums\n", tx_time_get() - current_time);
        							return true;
        						}
        					}

        					return false;
        				}())
        			{
        				printf("GSM-module is turned ON! (Attempt %d from %d)\n", i, ATTEMPTS);
        				return true;
        			}
        			else printf("GSM-module is NOT turned ON! (Attempt %d from %d)\n", i, ATTEMPTS);
				}

				return false;
			}())
		{
			printf("GSM-module was successfullly turned ON\n");
		}
		else
		{
			printf("GSM-module cannot be turned ON\n");

			// Dectivating power for GSM-unit
			HAL_GPIO_WritePin(POWER_4V_EN_GPIO_Port, POWER_4V_EN_Pin, GPIO_PIN_SET);

			/*

			Inform other threads!!!

			*/
		}
	}
	else printf("GSM-module is already ON\n");
}

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