//////////////////////////////////////////////////////////////////
//
// App:			DIO
// Author:		Milan Korinek
// Version:		1.0
// Notice:		Functions for digital I/O card ports (PA - PD)
//////////////////////////////////////////////////////////////////

#include "DIO_Ports.h"

const uint32_t DIO_PORTS_IO_LIST [] =  {	DIO_PA0_GPIO, DIO_PA1_GPIO, DIO_PA2_GPIO, DIO_PA3_GPIO, DIO_PA4_GPIO, DIO_PA5_GPIO, DIO_PA6_GPIO, DIO_PA7_GPIO,
											DIO_PB0_GPIO, DIO_PB1_GPIO, DIO_PB2_GPIO, DIO_PB3_GPIO, DIO_PB4_GPIO, DIO_PB5_GPIO, DIO_PB6_GPIO, DIO_PB7_GPIO,
											DIO_PC0_GPIO, DIO_PC1_GPIO, DIO_PC2_GPIO, DIO_PC3_GPIO, DIO_PC4_GPIO, DIO_PC5_GPIO, DIO_PC6_GPIO, DIO_PC7_GPIO,
											DIO_PD0_GPIO, DIO_PD1_GPIO, DIO_PD2_GPIO, DIO_PD3_GPIO, DIO_PD4_GPIO, DIO_PD5_GPIO, DIO_PD6_GPIO, DIO_PD7_GPIO
									   };


void DIO_configure_ports(_In_ DIO_PortConfig_t ports_config[DIO_MAX_PORTS])
{
	int i;
	
	for(i = 0; i < DIO_MAX_PORTS; i++) {
		DIO_configure_port(i, ports_config[i]);
	}
}
										
void DIO_configure_port(_In_ uint32_t port, _In_ DIO_PortConfig_t port_config)
{
	int i;
	uint32_t portFlags;
	uint32_t offset;

	portFlags = (port_config.PortDirection == DIO_E_PORTDIR_OUTPUT) ? PIO_OUTPUT_0 : PIO_INPUT;
	portFlags |= DIO_FLAGS;
	offset = port * DIO_CHANNELS_ON_PORT;
	
	for (i = 0; i < DIO_CHANNELS_ON_PORT; i++) {
		gpio_configure_pin(DIO_PORTS_IO_LIST[offset + i], portFlags);
	}
	
	DIO_set_outputs_port(port, port_config.OutputDefault);
}

void DIO_set_outputs_ports(_In_ DIO_PortConfig_t port_config[DIO_MAX_PORTS], _In_ uint8_t masks[DIO_MAX_PORTS])
{
	int i;
	
	for(i = 0; i < DIO_MAX_PORTS; i++) {
		if (port_config[i].PortDirection != DIO_E_PORTDIR_OUTPUT) continue;	// skip input ports
		DIO_set_outputs_port(i, masks[i]);
	}
}

void DIO_set_outputs_port(_In_ uint32_t port, _In_ uint8_t mask)
{
	int i;
	uint32_t offset;
	
	offset = port * DIO_CHANNELS_ON_PORT;
	
	for (i = 0; i < DIO_CHANNELS_ON_PORT; i++) {
		 ((mask >> i) & 0x01) ? 
			gpio_set_pin_high(DIO_PORTS_IO_LIST[offset + i]) : 
			gpio_set_pin_low(DIO_PORTS_IO_LIST[offset + i]);
	}
}

void DIO_set_output_channel(_In_ uint32_t channel, _In_ BOOL enable)
{
	enable ? gpio_set_pin_high(DIO_PORTS_IO_LIST[channel]) :
			 gpio_set_pin_low(DIO_PORTS_IO_LIST[channel]);
}

void DIO_get_inputs_ports(_Out_ uint8_t masks[DIO_MAX_PORTS])
{
	int i;
	
	for(i = 0; i < DIO_MAX_PORTS; i++) {
		masks[i] = DIO_get_inputs_port(i);
	}
}

uint8_t DIO_get_inputs_port(_In_ uint32_t port)
{
	int i;
	uint32_t offset;
	uint8_t mask;
	
	// from port[7] to port[0]
	offset = (DIO_CHANNELS_ON_PORT - 1) + port * DIO_CHANNELS_ON_PORT;
	mask = 0;
	
	for (i = 0; i < DIO_CHANNELS_ON_PORT; i++) {
		mask = (mask << 1) | (gpio_pin_is_high(DIO_PORTS_IO_LIST[offset - i]));  
	}
	return mask;
}

BOOL DIO_get_input_channel(_In_ uint32_t channel)
{
	return gpio_pin_is_high(DIO_PORTS_IO_LIST[channel]);
}