// Example of user space C program to read a humidity and temperature
// sensor Sensirion SHT71 (http://www.acmesystems.it/?id=89)

#include "stdio.h"
#include "linux/gpio_syscalls.h"

// -----------------------------------------------------------------------
// SHT71 sensor define
// -----------------------------------------------------------------------

#define CLOCK_BIT         1<<25 // Clock line is OG25 (J7.13)
#define DATA_BIT          1<<24 // Data line is IOG24 (J7.21)

// Macro to set the data line direction
#define DATA_LINE_IN      gpiosetdir(PORTG,DIRIN,DATA_BIT)
#define DATA_LINE_OUT     gpiosetdir(PORTG,DIROUT,DATA_BIT)

#define DATA_LINE_LOW     gpiosetdir(PORTG,DIROUT,DATA_BIT);gpioclearbits(PORTG,DATA_BIT)
#define DATA_LINE_HIGH    gpiosetdir(PORTG,DIRIN,DATA_BIT)
#define DATA_LINE_READ    gpiogetbits(PORTG,DATA_BIT)?(1):(0)

#define CLOCK_LINE_LOW    gpioclearbits(PORTG,CLOCK_BIT)
#define CLOCK_LINE_HIGH   gpiosetbits(PORTG,CLOCK_BIT)

#define CMD_READ_TEMP     0x03
#define CMD_READ_HUM      0x05

#define MS_TIMER 10

// Very dirty software delay in us :-)

void usDelay(int us) {
  int i,a;
  int delayvar=10;
  
  for (a=0;a<us;a++) {
    for (i=0;i<33;i++) {
      delayvar*=2;        
      delayvar/=2;
    } 
  }
}   
// -----------------------------------------------------------------------
// Send the start sequence
// -----------------------------------------------------------------------
void SendStart(void) {
  DATA_LINE_OUT;

  CLOCK_LINE_HIGH;
  usDelay(1000);
  DATA_LINE_IN;
  DATA_LINE_LOW;
  CLOCK_LINE_LOW;
  CLOCK_LINE_HIGH;
  usDelay(1000);
  DATA_LINE_HIGH;
  CLOCK_LINE_LOW;

  DATA_LINE_IN;

}

// -----------------------------------------------------------------------
// Sensor reset
// -----------------------------------------------------------------------
void SendReset (void) {

  int i;

  for (i=0;i<12;i++) {
    CLOCK_LINE_HIGH;
    usDelay(1000);
    CLOCK_LINE_LOW;
  }

}

// -----------------------------------------------------------------------
// Send a byte to the sensor
// -----------------------------------------------------------------------
int SendByte(char byte) {

  char tempbyte;
  int i;
  unsigned long timer;

  DATA_LINE_OUT;
  tempbyte=byte;

  for (i=0x80;i>0;i/=2) {

    if (tempbyte & i)
      DATA_LINE_HIGH;
    else
      DATA_LINE_LOW;

    CLOCK_LINE_HIGH;
    usDelay(1000);
    CLOCK_LINE_LOW;

  }

  // Wait the ACK
  timer=MS_TIMER;

  DATA_LINE_IN;
  CLOCK_LINE_HIGH;
  while (DATA_LINE_READ) {

    if (MS_TIMER>timer+2000) {
      SendReset ();
      return 0;
      break;
    }
  }

  CLOCK_LINE_LOW;
  return 1;

}


// -----------------------------------------------------------------------
// Read a byte from the sensor
// withack
//   1 = send the ACK
//   0 = don't send the ACK
// -----------------------------------------------------------------------
char ReadByte(int withack) {

  char tempbyte;
  int i;

  tempbyte=0;
  DATA_LINE_IN;


  for (i=0x80;i>0;i/=2) {
    CLOCK_LINE_HIGH;
    usDelay(1000);

    if (DATA_LINE_READ)
      tempbyte |= i;

    CLOCK_LINE_LOW;
  }

  usDelay(5000);

  if (withack) {
    // Acknowledge del byte
    DATA_LINE_OUT;
    DATA_LINE_LOW;
    CLOCK_LINE_HIGH;
    usDelay(1000);
    CLOCK_LINE_LOW;
    DATA_LINE_IN;
  } else {
    // Senza acknowledge
    DATA_LINE_OUT;
    DATA_LINE_HIGH;
    CLOCK_LINE_HIGH;
    usDelay(1000);
    CLOCK_LINE_LOW;
    DATA_LINE_IN;
  }

  return tempbyte;

}

// -----------------------------------------------------------------------
// Read the temperature
// -----------------------------------------------------------------------
int ReadTemperature(void) {

  char Lsb,Msb,Chk;

  SendStart();

  if (!SendByte(CMD_READ_TEMP)) {
    printf ("ABORTITNG.....\n");
    return 0;
  }

  while (DATA_LINE_READ) ;
  Msb=ReadByte(1);
  Lsb=ReadByte(1);
  Chk=ReadByte(0);

  return ( (Msb<<8)+Lsb );

}

// -----------------------------------------------------------------------
// Read the humidity
// -----------------------------------------------------------------------
int ReadHumidity(void) {

  char Lsb,Msb,Chk;

  SendStart();

  if (!SendByte(CMD_READ_HUM)) {
    printf ("ABORTING.....\n");
    return 0;
  }
  while (DATA_LINE_READ) ;

  Msb=ReadByte(1);
  Lsb=ReadByte(1);
  Chk=ReadByte(0);

  return ( (Msb<<8)+Lsb );

}


// -----------------------------------------------------------------------
// main code
// -----------------------------------------------------------------------
int main(void) {
	float real_umidity;
	float real_temperature;

	int soh;
	int sot;

	soh=ReadHumidity();
	sot=ReadTemperature();

	real_umidity= -4 + 0.0405*soh + -2.8E-6;
	real_temperature = -39.66 + 0.01*sot;

	printf ("Umidity    : %.2f %%\n",real_umidity);
 	printf ("Temperature: %.2f °C\n",real_temperature);
}