package jGPIO.SPI;

import anywheresoftware.b4a.keywords.Bit;
import jGPIO.DigitalInput.DigitalInput;
import jGPIO.DigitalOutput.DigitalOutput;

public class SPI_BitBang{

	private DigitalOutput spi_clk = null;
	@SuppressWarnings("unused")
	private DigitalInput spi_di = null;
	private DigitalOutput spi_do = null;
	private DigitalOutput spi_cs = null;
	
	private boolean is_opened = false;
	
	
/**
 * 
 * @param pin_di : pin for digital input
 * @param pin_do : pin for digital output
 * @param pin_cs : pin for clock output
 * @param pin_clk : pin for chip select output
 */
	public SPI_BitBang(int pin_di, int pin_do, int pin_cs, int pin_clk) {
		is_opened = false;
		
		
		// CS selalu high (active low)
		if (pin_cs>0) spi_cs = new DigitalOutput(pin_cs, true);
		// DataInput selalu high waktu awal
		if (pin_di>0) spi_di = new DigitalInput(pin_di);
		// Data Output selalu high waktu awal
		if (pin_do>0) spi_do = new DigitalOutput(pin_do,true);
		if (pin_clk>0) spi_clk = new DigitalOutput(pin_clk, false);
		is_opened = true;
	}
	
	public boolean setCS(boolean is_enabled) {
		if (is_opened) {
			if (is_enabled)
				spi_cs.SetLow();
			else
				spi_cs.SetHigh();
			
			
			return true;
		}
		return false;
	}
	
	/**
	 * Write 8 bits value
	 * @param value : value
	 * @return true if success
	 */
	public boolean Write8(int value) {
		if (is_opened) {
			
			int tmp = Bit.And(value, 0xFF);
			
			
			for(int ii=0;ii<8;ii++) {
				if (Bit.And(tmp, 0x80)==0) {
					spi_do.SetLow();
					
				} else {
					spi_do.SetHigh();
					
				}
				tmp = Bit.And(Bit.ShiftLeft(tmp, 1), 0xFF);
				ActivateClock();
			}
			
			return true;
		}
		return false;
	}
	
	
	
	/**
	 * Write 16 bits value
	 * @param value
	 * @return true if success
	 */
	public boolean Write16(int value) {
		if (is_opened) {
			
			int tmp = Bit.And(value, 0xFFFF);
			
			for(int ii=0;ii<16;ii++) {
				// mulai dari MSB 
				if (Bit.And(tmp, 0x8000)==0) {
					spi_do.SetLow();
					
				} else {
					spi_do.SetHigh();
					
				}
				
				tmp = Bit.And(Bit.ShiftLeft(tmp, 1), 0xFFFF);
				ActivateClock();
				
			}
			
			
			return true;
		}
		
		return false;
	}
	
	public boolean IsOpened() {
		return is_opened;
	}
	
	private void ActivateClock() {
		
		spi_clk.SetHigh();	
		spi_clk.SetLow();
	}
	
	public void Close() {
		is_opened = false;
		if (spi_do instanceof DigitalOutput) {
			spi_do.Release();
			spi_do = null;
		}
		if (spi_clk instanceof DigitalOutput) {
			spi_clk.Release();
			spi_clk = null;
		}
		if (spi_cs instanceof DigitalOutput) {
			spi_cs.Release();
			spi_cs = null;
		}
	}
}
