#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

#define INOUTS_EXPAND_AS_GPIO_GET(id, ...) 		\
		inputs[id - DIN1] = gpio_get(id);

#define OUTPUTS_EXPAND_AS_GPIO_SET(id, ...) 		\
		gpio_set(id, outputs[id - DOUT1]);

#define UPDATE_INPUTS() \
	DI_TABLE(INOUTS_EXPAND_AS_GPIO_GET) \

#define APPLY_OUTPUTS() \
	RELAYS(OUTPUTS_EXPAND_AS_GPIO_SET)


uint8_t  inputs[INPUTS_TOTAL_COUNT], outputs[OUTPUTS_TOTAL_COUNT];
/* data actuality mutexes */
static SemaphoreHandle_t outputs_mutex, inputs_mutex;

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

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

void d_inouts_task(void *arg) {
	inputs_mutex  = xSemaphoreCreateMutex();
	outputs_mutex = xSemaphoreCreateMutex();
	while(true) {
		if (xSemaphoreTake(inputs_mutex, 100)) {
			UPDATE_INPUTS();
			xSemaphoreGive(inputs_mutex);
		}
		if (xSemaphoreTake(outputs_mutex, 100)) {
			APPLY_OUTPUTS();
			xSemaphoreGive(outputs_mutex);
		}
		vTaskDelay(50);
	}
}

/* 
 * 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;
}


/* 
 * 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;
}

/* passed */
void d_inouts_test(void *arg) {
	uint8_t tmp[INPUTS_TOTAL_COUNT] = {0};
	while (true) {
		if (get_inputs(tmp))
			set_outputs(tmp);
		vTaskDelay(50);
	}
}
	
