/**
  ******************************************************************************
  * File Name          : app_bluenrg_ms.c
  * Description        : Source file
  *
  ******************************************************************************
  *
  * COPYRIGHT 2021 STMicroelectronics
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include <automation.h>
#include "app_bluenrg_ms.h"

#include "hci_tl.h"
#include "sample_service.h"
#include "bluenrg_utils.h"
#include "bluenrg_gatt_server.h"
#include "bluenrg_gap_aci.h"
#include "bluenrg_gatt_aci.h"
#include "bluenrg_hal_aci.h"

/* USER CODE BEGIN Includes */
#include "cmsis_os.h"
#include "task.h"

#include "signals.h"
#include "utils.h"
/* USER CODE END Includes */

/* Private defines -----------------------------------------------------------*/

#define BDADDR_SIZE 6

/* Private macros ------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
static volatile uint8_t user_button_init_state = 1;
volatile uint8_t user_button_pressed = 0;
static volatile uint8_t errorToDisplay;

extern volatile uint8_t set_connectable;
extern volatile int     connected;
extern volatile uint8_t notification_tx_enabled, notification_fsm_enabled;

extern osTimerId ErrorDisplayTimerHandle;
extern osMutexId errorListMutexHandle;

/* USER CODE BEGIN PV */
FiniteStateMachine last_finiteStateMachine = { IDLE };
extern FiniteStateMachine finiteStateMachine;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
static void User_Process(void);

/* USER CODE BEGIN PFP */
void HAL_Delay(volatile uint32_t millis)
{
  /* replace HAL library blocking delay function
   * with FreeRTOS thread aware equivalent */
  osDelay(millis);
}


/* USER CODE END PFP */

void ErrorDisplayCallback( void const * arg )
{
	static bool stopSending = false;
	/* Check if any error to display */
	if( !connected )
		return;
    osStatus status = osMutexWait(errorListMutexHandle, 5000);
    if (status == osOK)
    {
		uint8_t maxErr = isAnyError();
		if( maxErr > 0 )
		{
			stopSending = false;
			sendBLEerror( findErrorById( errorToDisplay++ ) );
			if( errorToDisplay >= maxErr )
				errorToDisplay = 0;
		}
		else if( !stopSending )
		{
			sendBLEerror( 0 );
			stopSending = true;
		}
    	osMutexRelease(errorListMutexHandle);
    }
}

void MX_BlueNRG_MS_Init(void)
{
  /* USER CODE BEGIN SV */

  /* USER CODE END SV */

  /* USER CODE BEGIN BlueNRG_MS_Init_PreTreatment */

  /* USER CODE END BlueNRG_MS_Init_PreTreatment */

  /* Initialize the peripherals and the BLE Stack */
  uint8_t SERVER_BDADDR[] = {0xaa, 0x00, 0x00, 0xE1, 0x80, 0xaa};
  uint8_t bdaddr[BDADDR_SIZE];
  uint16_t service_handle, dev_name_char_handle, appearance_char_handle;

  uint8_t  hwVersion;
  uint16_t fwVersion;
  int ret;

  /* Get the User Button initial state */
  user_button_init_state = (uint32_t)(HAL_GPIO_ReadPin(USR_BTN_GPIO_Port, USR_BTN_Pin) == GPIO_PIN_RESET);

  // Wait for others threads start
  HAL_Delay(2000);
  hci_init(user_notify, NULL);

  /* get the BlueNRG HW and FW versions */
  getBlueNRGVersion(&hwVersion, &fwVersion);

  /*
   * Reset BlueNRG again otherwise we won't
   * be able to change its MAC address.
   * aci_hal_write_config_data() must be the first
   * command after reset otherwise it will fail.
   */
  hci_reset();

  HAL_Delay(100);

  APP_LOG(TS_OFF, VLEVEL_M, "BLE HWver %d, FWver %d\r\n", hwVersion, fwVersion);

  BLUENRG_memcpy(bdaddr, SERVER_BDADDR, sizeof(SERVER_BDADDR));

  ret = aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET,
                                  CONFIG_DATA_PUBADDR_LEN,
                                  bdaddr);
  if (ret) {
	  APP_LOG(TS_OFF, VLEVEL_M, "Setting BD_ADDR failed 0x%02x.\r\n", ret);
  }

  ret = aci_gatt_init();
  if (ret) {
	  APP_LOG(TS_OFF, VLEVEL_M, "GATT_Init failed.\r\n");
  }

  // GAP peripheral role setting
  ret = aci_gap_init_IDB05A1(GAP_PERIPHERAL_ROLE_IDB05A1, 0, 0x07, &service_handle, &dev_name_char_handle, &appearance_char_handle);

  if (ret != BLE_STATUS_SUCCESS) {
	  APP_LOG(TS_OFF, VLEVEL_M, "GAP_Init failed.\r\n");
  }

  ret = aci_gap_set_auth_requirement(MITM_PROTECTION_REQUIRED,
                                     OOB_AUTH_DATA_ABSENT,
                                     NULL,
                                     7,
                                     16,
                                     USE_FIXED_PIN_FOR_PAIRING,
                                     123456,
                                     BONDING);

  if (ret == BLE_STATUS_SUCCESS) {
	  APP_LOG(TS_OFF, VLEVEL_M, "BLE Stack Initialized.\r\n");
  }

  APP_LOG(TS_OFF, VLEVEL_M, "SERVER: BLE Stack Initialized\r\n");
    ret = Add_Sample_Service();

    if (ret == BLE_STATUS_SUCCESS)
    {
    	APP_LOG(TS_OFF, VLEVEL_M, "Service added successfully.\r\n");
    }
    else
    {
    	APP_LOG(TS_OFF, VLEVEL_M, "Error while adding service.\r\n");
    }

  /* Set output power level */
  ret = aci_hal_set_tx_power_level(1,6);

  /* USER CODE BEGIN BlueNRG_MS_Init_PostTreatment */
	errorToDisplay = 0;
	osStatus status = osTimerStart( ErrorDisplayTimerHandle, 2000 );
	if( status != osOK )
		APP_LOG(TS_OFF, VLEVEL_M, "Error starting error display timer\r\n");

  /* USER CODE END BlueNRG_MS_Init_PostTreatment */
}

/*
 * BlueNRG-MS background task
 */
void MX_BlueNRG_MS_Process(void)
{
  /* USER CODE BEGIN BlueNRG_MS_Process_PreTreatment */

  /* USER CODE END BlueNRG_MS_Process_PreTreatment */

  User_Process();
  hci_user_evt_proc();

  /* USER CODE BEGIN BlueNRG_MS_Process_PostTreatment */

  /* USER CODE END BlueNRG_MS_Process_PostTreatment */
}

/**
 * @brief  Configure the device as Client or Server and manage the communication
 *         between a client and a server.
 *
 * @param  None
 * @retval None
 */
static void User_Process(void)
{
  if (set_connectable)
  {
    /* Establish connection with remote device */
    Make_Connection();
    set_connectable = FALSE;
    user_button_init_state = (uint32_t)(HAL_GPIO_ReadPin(USR_BTN_GPIO_Port, USR_BTN_Pin) == GPIO_PIN_RESET);
  }

  if( connected && (last_finiteStateMachine.stm != finiteStateMachine.stm) )
  {
	  updateFSM( finiteStateMachine );
	  if( last_finiteStateMachine.stm == APERIODIC && finiteStateMachine.stm == PERIODIC )
    	  clearErrorList();
	  //if( last_finiteStateMachine == E_STOP && finiteStateMachine == APERIODIC )
	  if( finiteStateMachine.stm != ESTOP )
		  deleteErrorByNo( 0x112 );
	  last_finiteStateMachine = finiteStateMachine;
  }
  /* Check if the User Button has been pushed */
  if (user_button_pressed)
  {
    /* Debouncing */
    HAL_Delay(50);
    /* Wait until the User Button is released */
    while ((HAL_GPIO_ReadPin(USR_BTN_GPIO_Port, USR_BTN_Pin) == GPIO_PIN_RESET) == !user_button_init_state);
    /* Debouncing */
    HAL_Delay(50);

   	finiteStateMachine.stm = ESTOP;
   	addErrorToList( 0x112 );

    /* Reset the User Button flag */
    user_button_pressed = 0;
  }
}

static void Ble_processFrame()
{
	MX_BlueNRG_MS_Process();
	osDelay( 5 );
}

static void Ble_processMsg(MSG_STRUCT *p_msg)
{
	if( p_msg->opcode == CAN_ECHO || p_msg->opcode == OP_OUTPUT_ONCHANGE ) {
		sendData( (uint8_t *)&(p_msg->data[2]), p_msg->lParam[0] );
	}
	else {
		readATcommand( strlen(p_msg->data), (uint8_t *)p_msg->data );
	}
}

void vBleTask( void *pvParameters )
{
/* Remove warning for unused parameter */
    (void)pvParameters ;
	osMessageQId myQueueId = getQueueId(BLE_COMM);
	osEvent event;


    MX_BlueNRG_MS_Init();

	while(1)
	{
		event = osMessageGet( myQueueId,  100 );
		if (event.status == osEventMessage)
		{
			MSG_STRUCT* p_recvMsg = event.value.p;

			Ble_processMsg(p_recvMsg);
			freeMemoryPoolMessage(p_recvMsg);
		}
		else if (event.status == osEventTimeout) {
			Ble_processFrame();
		}
	}
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
