// 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 <unistd.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

// -----------------------------------------------------------------------
// Send the start sequence
// -----------------------------------------------------------------------

void SendStart(void) {
  DATA_LINE_OUT;

  CLOCK_LINE_HIGH;
  usleep(1000);
  DATA_LINE_IN;
  DATA_LINE_LOW;
  CLOCK_LINE_LOW;
  CLOCK_LINE_HIGH;
  usleep(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;
    usleep(1000);
    CLOCK_LINE_LOW;
  }
}

// -----------------------------------------------------------------------
// Send a byte to the sensor
// -----------------------------------------------------------------------

int SendByte(char byte) {
  char tempbyte;
  int i;

  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;
    usleep(1000);
    CLOCK_LINE_LOW;
  }

  DATA_LINE_IN;
  CLOCK_LINE_HIGH;
  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;
    if (DATA_LINE_READ) tempbyte |= i;
    CLOCK_LINE_LOW;
  }

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

  return tempbyte;

}

// ----------------------
// Read the temperature
// ----------------------

int ReadTemperature(void) {
  unsigned char Lsb,Msb,Chk;

  SendStart();
  if (!SendByte(CMD_READ_TEMP)) 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) {
  unsigned char Lsb,Msb,Chk;

  SendStart();

  if (!SendByte(CMD_READ_HUM)) 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_humidity;
  float real_temperature;

  int soh;
  int sot;

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

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

  printf ("Humidity   : %.2f %%\n",real_humidity);
  printf ("Temperature: %.2f C\n",real_temperature);
}

