#include <stdio.h>
#include <unistd.h>
#include <assert.h>

#include "../hubolib.h"
#include "../hubocfg.h" // Required for changing default I2C device.

using namespace HuboLib;

/*
Compile and link: 
	g++ DigitalOutput2.cpp -L../ -lhubo -lpthread -lrt -o DigitalOutput2.out
Run:
	sudo ./DigitalOutput2.out
Purpose:
	The setting of digital outputs is done with a slight delay.
	Use Readback_DO_Channels() to check what the hardware outputs are really set to.
	Thus double check the values as requested by calls to Set_DO_Channel() and Set_DO_Channels().
*/

int main(void)
{
	// If required - set the I2C device to work with. The Raspberry Pi uses "/dev/i2c-1" which is default, the Banana Pi uses "/dev/i2c-0"
	#ifdef BPI
	    g_I2CConfig.m_sI2CDevice = "/dev/i2c-0";
	#endif

	// Initialize the library once in your program.
	if (!Initialize())
	{
		printf ("Error: Initialize\n");
		return 1;
	}
	
	// Reset all channels.
	printf ("Clearing all channels, then setting channels 1, 2 and 3.\n");
	Set_DO_Channels(0x00);
	usleep(1000000);
	Set_DO_Channels(0x07);

	// Read back the digital output values as requested by the Set_DO_Channel(s) function. 
	// We'd expect a 0x07 as the three lower channels are set.
	unsigned char digitalOutputs = 0;
	Get_DO_Channels(digitalOutputs);
	assert (digitalOutputs == 0x07);
	
	// But infact - the outputs might not yet be set to 0x07 in the hardware 
	// but still show 0x00 for a while.
	unsigned char currentDigitalOutputs = 0;
	do 
	{
		Readback_DO_Channels(currentDigitalOutputs);
		printf ("Hardware outputs are 0x%02X\n", currentDigitalOutputs);
	} while (currentDigitalOutputs != digitalOutputs);
	
	// The answer to this is that setting digital outputs is an asynchronous operation.
	// A value set by a call to Set_DO_Channel() or Set_DO_Channels() gets buffered and transmitted
	// in the next cycle time slot. Until then the hardware might still be showing the former state 
	// of the outputs. 
	// So if you really need to stop your execution until the outputs are set then use 
	// Readback_DO_Channels() to double check until the hardware has switched to the required state.
	
	// Free library resources.
	Uninitialize();
	
	return 0;
}
