#include "d_inouts.h"
#include "gpio.h"

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

#ifdef PRINTF_STDLIB
#include <stdio.h>
#endif
#ifdef PRINTF_CUSTOM
#include "tinystdio.h"
#endif
#ifdef DINS_ENABLE
#define INOUTS_EXPAND_AS_GPIO_GET(id, ...) 		\
		inputs[id - DIN1] = gpio_get(id);

#define UPDATE_INPUTS() \
	DI_TABLE(INOUTS_EXPAND_AS_GPIO_GET) \

uint8_t  inputs[INPUTS_TOTAL_COUNT];
/* data actuality mutexes */
static SemaphoreHandle_t inputs_mutex;

uint8_t get_state_din_outs(gpio_t pin) {
	uint8_t res = 0;
	res = gpio_get(pin);
	return res;
}

/* 
 * get state of discrete inputs;
 ** parameters
 * 	inputs_p - a pointer to array of size INPUTS_TOTAL_COUNT in which inputs 
 * 	states must be stored;
 ** return value:
 * 	true if inputs states read successfully
 *
 ** example:
 * uint8_t inputs_state[INPUTS_TOTAL_COUNT]
 * ...
 * 	if (get_inputs(inputs_state))
 *		... do smth ...
 *	else
 *		... do smth ...
 */
bool get_inputs(uint8_t *inputs_p) {
	bool res = 0;
	if (xSemaphoreTake(inputs_mutex, 100)) {
			memcpy(inputs_p, inputs, INPUTS_TOTAL_COUNT);
			res = 1;
			xSemaphoreGive(inputs_mutex);
	}
	return res;
}
#endif
#ifdef DOUTS_ENABLE
#define OUTPUTS_EXPAND_AS_GPIO_SET(id, ...) 		\
		gpio_set(id, outputs[id - DOUT1]);

#define APPLY_OUTPUTS() \
	RELAYS(OUTPUTS_EXPAND_AS_GPIO_SET)

uint8_t  outputs[OUTPUTS_TOTAL_COUNT];
/* data actuality mutexes */
static SemaphoreHandle_t outputs_mutex;

void set_state_douts(gpio_t pin, uint8_t value)
{
	gpio_set(pin, value);
}

/* 
 * set outputs to a given state;
 ** parameters:
 * 	outputs_p - a pointer to array of size OUTPUTS_TOTAL_COUNT from which outputs
 * 	states should be read;
 ** return value:
 * 	true if outputs applied successfully
 ** example:
 * uint8_t outputs_state[OUTPUTS_TOTAL_COUNT]
 * ...
 * 	if (set_outputs(outputs_state))
 * 		... do smth ...
 * 	else
 * 		... do smth ...
 */

bool set_outputs(uint8_t *outputs_p) {
	bool res = 0;
	if (xSemaphoreTake(outputs_mutex, 100)) {
			memcpy(outputs, outputs_p, OUTPUTS_TOTAL_COUNT);
			res = 1;
			xSemaphoreGive(outputs_mutex);
	}
	return res;
}
#endif
#ifdef DINS_ENABLE | DOUTS_ENABLE
void d_inouts_task(void *arg) {
#ifdef DINS_ENABLE
	inputs_mutex  = xSemaphoreCreateMutex();
#endif
#ifdef DOUTS_ENABLE
	outputs_mutex = xSemaphoreCreateMutex();
#endif
	while(true) {
#ifdef DINS_ENABLE
		if (xSemaphoreTake(inputs_mutex, 100)) {
			UPDATE_INPUTS();
			xSemaphoreGive(inputs_mutex);
		}
#endif
#ifdef DOUTS_ENABLE
		if (xSemaphoreTake(outputs_mutex, 100)) {
			APPLY_OUTPUTS();
			xSemaphoreGive(outputs_mutex);
		}
#endif
		vTaskDelay(50);
	}
}
#endif

#if defined HARDWARE_BT6703
char sn_bt_6702[] = 
"7030102\
7030105\
7030093\
7030103\
7030109\
7030091\
7030106\
7030099\
7030089\
7030114\
7030110\
7030111\
7030085\
7030112\
7030069\
7030090\
7030113\
7030092\
7030097\
7030100\
7030108\
7030115\
7030116\
7030101\
7030117\
7030120\
7030118\
7030086\
7030104\
7030119\
7030009\
7030030\
7030051\
7030019\
7030035\
7030065\
7030029\
7030094\
7030075\
7030040\
7030046\
7030006\
7030052\
7030068\
7030045\
7030059\
7030026\
7030084\
7030063\
7030080\
7030032\
7030077\
7030072\
7030011\
7030096\
7030018\
7030034\
7030047\
7030060\
7030039\
7030082\
7030001\
7030013\
7030098\
7030024\
7030073\
7030004\
7030025\
7030062\
7030010\
7030016\
7030053\
7030057\
7030066\
7030021\
7030022\
7030050\
7030079\
7030064\
7030043\
7030054\
7030038\
7030070\
7030081\
7030015\
7030061\
7030074\
7030044\
7030027\
7030087\
7030056\
7030095\
7030014\
7030012\
7030083\
7030048\
7030107\
7030017\
7030031\
7030007\
7030033\
7030088\
7030042\
7030076\
7030023\
7030008\
7030058\
7030003\
7030020\
7030049\
7030041\
7030002\
7030037\
7030055\
7030036\
7030071\
7030067\
7030078\
7030028\
7030005\
";

#include "parameters.h"

void check_outputs_config (void)
{
	char *equivalent = NULL;
	char str[16];
	uint8_t len = 0;

	memset(str, 0, sizeof(str));
	GetSerialNumberStr(str, &len);
	equivalent = strstr(sn_bt_6702, str);
	if (equivalent != 0) {
	 	gpio_pins[DOUT1].pin = 4;
		gpio_pins[DOUT2].pin = 5;
	 	gpio_hw_config_pin(gpio_pins[DOUT1].port, gpio_pins[DOUT1].pin, GPIO_MODE_OUT_CFG |
							((gpio_pins[DOUT1].flags & GPIO_OD) ? 
								GPIO_TYPE_OD_CFG : GPIO_TYPE_PP_CFG) |
							GPIO_SPEED_HIGH_CFG);
		gpio_set(DOUT1, gpio_pins[DOUT1].flags & GPIO_SET);
	 	gpio_hw_config_pin(gpio_pins[DOUT2].port, gpio_pins[DOUT2].pin, GPIO_MODE_OUT_CFG |
							((gpio_pins[DOUT2].flags & GPIO_OD) ? 
								GPIO_TYPE_OD_CFG : GPIO_TYPE_PP_CFG) |
							GPIO_SPEED_HIGH_CFG);
		gpio_set(DOUT2, gpio_pins[DOUT2].flags & GPIO_SET);
	}
}
#endif

