#include <stdint.h>
  #include <stdio.h>
  #include <avr/io.h>
  #include <avr/pgmspace.h>
  #include <inttypes.h>
  #include <avr/interrupt.h>
  #include <avr/pgmspace.h>
  #include <avr/sleep.h>
  #include <avr/wdt.h>
  #include <string.h>
  #include <avr/power.h>
  
  // DHT11 sensor settings
  
  #define DHT_PIN PB4
  
  #define DHT_ERR_OK (0)
  #define DHT_ERR_TIMEOUT (-1)
  
  #define DHT_PIN_INPUT() (DDRB &= ~_BV(DHT_PIN))
  #define DHT_PIN_OUTPUT() (DDRB |= _BV(DHT_PIN))
  #define DHT_PIN_LOW() (PORTB &= ~_BV(DHT_PIN))
  #define DHT_PIN_HIGH() (PORTB |= _BV(DHT_PIN))
  #define DHT_PIN_READ() (PINB & _BV(DHT_PIN))
  #define DHT_TIMEOUT (10)
  
  
  static void dht_init(void);
  int8_t dht_read(uint8_t *temperature, uint8_t *humidity);
  
  // TM1637 Macros
  #define TM1637_DIO_HIGH() (PORTB |= _BV(TM1637_DIO_PIN))
  #define TM1637_DIO_LOW() (PORTB &= ~_BV(TM1637_DIO_PIN))
  #define TM1637_DIO_OUTPUT() (DDRB |= _BV(TM1637_DIO_PIN))
  #define TM1637_DIO_INPUT() (DDRB &= ~_BV(TM1637_DIO_PIN))
  #define TM1637_DIO_READ() (((PINB & _BV(TM1637_DIO_PIN)) > 0) ? 1 : 0)
  #define TM1637_CLK_HIGH() (PORTB |= _BV(TM1637_CLK_PIN))
  #define TM1637_CLK_LOW() (PORTB &= ~_BV(TM1637_CLK_PIN))
  
  
  // TM1637 Main Settings
  #define TM1637_DIO_PIN  PB0
  #define TM1637_CLK_PIN  PB1
  #define TM1637_BRIGHTNESS_MAX (7)
  #define TM1637_POSITION_MAX (4)
  
  // TM1637 commands
  #define TM1637_CMD_SET_DATA 0x40
  #define TM1637_CMD_SET_ADDR 0xC0
  #define TM1637_CMD_SET_DSIPLAY  0x80
  
  // TM1637 data settings (use bitwise OR to contruct complete command)
  #define TM1637_SET_DATA_WRITE 0x00 // write data to the display register
  #define TM1637_SET_DATA_READ  0x02 // read the key scan data
  #define TM1637_SET_DATA_A_ADDR  0x00 // automatic address increment
  #define TM1637_SET_DATA_F_ADDR  0x04 // fixed address
  #define TM1637_SET_DATA_M_NORM  0x00 // normal mode
  #define TM1637_SET_DATA_M_TEST  0x10 // test mode
  
  // TM1637 display control command set (use bitwise OR to consruct complete command)
  #define TM1637_SET_DISPLAY_OFF  0x00 // off
  #define TM1637_SET_DISPLAY_ON 0x08 // on
  
  static void TM1637_send_config(const uint8_t enable, const uint8_t brightness);
  static void TM1637_send_command(const uint8_t value);
  static void TM1637_start(void);
  static void TM1637_stop(void);
  static uint8_t TM1637_write_byte(uint8_t value);
  
  static uint8_t _config = TM1637_SET_DISPLAY_ON | TM1637_BRIGHTNESS_MAX;
  static uint8_t _segments = 0xff;
  
  
  
  
  /**
  * Initialize TM1637 display driver.
  * Clock pin (TM1637_CLK_PIN) and data pin (TM1637_DIO_PIN)
  * are defined at the top of this file.
  */
  void TM1637_init(const uint8_t enable, const uint8_t brightness);
  
  /**
  * Turn display on/off.
  * value: 1 - on, 0 - off
  */
  void TM1637_enable(const uint8_t value);
  
  /**
  * Set display brightness.
  * Min value: 0
  * Max value: 7
  */
  void TM1637_set_brightness(const uint8_t value);
  
  /**
  * Display raw segments at position (0x00..0x03)
  *
  * bits:
  * -- 0 --
  * | |
  * 5 1
  * | |
  * -- 6 --
  * | |
  * 4 2
  * | |
  * -- 3 --
  *
  * Example segment configurations:
  * - for character 'H', segments=0b01110110
  * - for character '-', segments=0b01000000
  * - etc.
  */
  void TM1637_display_segments(const uint8_t position, const uint8_t segments);
  
  /**
  * Display digit ('0'..'9') at position (0x00..0x03)
  */
  void TM1637_display_digit(const uint8_t position, const uint8_t digit);
  
  /**
  * Display colon on/off.
  * value: 1 - on, 0 - off
  */
  void TM1637_display_colon(const uint8_t value);
  
  /**
  * Clear all segments (including colon).
  */
  void TM1637_clear(void);
  
  
  PROGMEM const uint8_t _digit2segments[] =
  {
  0x3F, // 0
  0x06, // 1
  0x5B, // 2
  0x4F, // 3
  0x66, // 4
  0x6D, // 5
  0x7D, // 6
  0x07, // 7
  0x7F, // 8
  0x6F // 9
  };
  
  // -------------------------------------------------------------------------------------------------------
  // ---------------------------------------- DELAY library CODE ------------------------------------------
  // -------------------------------------------------------------------------------------------------------
  
  
  void delay1sec(void)
  {
  // Generated by delay loop calculator
  // at http://www.bretmulvey.com/avrdelay.html
  //
  // Delay 1 000 000 cycles
  // 1s at 1 MHz
  
  asm volatile (
  " ldi r18, 6" "\n"
  " ldi r19, 19"  "\n"
  " ldi r20, 174" "\n"
  "1: dec r20"  "\n"
  " brne 1b"  "\n"
  " dec r19"  "\n"
  " brne 1b"  "\n"
  " dec r18"  "\n"
  " brne 1b"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  };
  
  // -------------------------------------------------------------------------------------------------------
  // ---------------------------------------- DHT11 library CODE ------------------------------------------
  // -------------------------------------------------------------------------------------------------------
  
  
  void
  dht_init(void)
  {
  
  DHT_PIN_INPUT();
  DHT_PIN_HIGH();
  }
  
  static int8_t
  dht_await_state(uint8_t state)
  {
  uint8_t counter = 0;
  while ((!DHT_PIN_READ() == state) && (++counter < DHT_TIMEOUT))
  { // delay single 1 us
  asm volatile (
  " nop"  "\n"
  );
  };
  return counter;
  }
  
  int8_t
  dht_read(uint8_t *temperature, uint8_t *humidity)
  {
  uint8_t i, j, data[5] = {0, 0, 0, 0, 0};
  
  /* send start sequence */
  DHT_PIN_OUTPUT();
  DHT_PIN_LOW();
  
  // Generated by delay loop calculator
  // at http://www.bretmulvey.com/avrdelay.html
  //
  // Delay 20 000 cycles
  // 20ms at 1 MHz
  
  asm volatile (
  " ldi r18, 26"  "\n"
  " ldi r19, 249" "\n"
  "1: dec r19"  "\n"
  " brne 1b"  "\n"
  " dec r18"  "\n"
  " brne 1b"  "\n"
  );
  
  DHT_PIN_INPUT();
  DHT_PIN_HIGH();
  
  /* read response sequence */
  if (dht_await_state(0) < 0 || dht_await_state(1) < 0 || dht_await_state(0) < 0) {
  return DHT_ERR_TIMEOUT;
  }
  
  /* read data */
  for (i = 0; i < 5; ++i) {
  for (j = 0; j < 8; ++j) {
  data[i] <<= 1;
  data[i] |= !!(dht_await_state(1) > 0 && dht_await_state(0) > 1);
  }
  }
  
  *temperature = data[2];
  *humidity = data[0];
  
  return DHT_ERR_OK;
  }
  
  
  // -------------------------------------------------------------------------------------------------------
  // ---------------------------------------- TM1637 library CODE ------------------------------------------
  // -------------------------------------------------------------------------------------------------------
  
  
  void
  TM1637_init(const uint8_t enable, const uint8_t brightness)
  {
  
  DDRB |= (_BV(TM1637_DIO_PIN)|_BV(TM1637_CLK_PIN));
  PORTB &= ~(_BV(TM1637_DIO_PIN)|_BV(TM1637_CLK_PIN));
  TM1637_send_config(enable, brightness);
  }
  
  void
  TM1637_enable(const uint8_t value)
  {
  
  TM1637_send_config(value, _config & TM1637_BRIGHTNESS_MAX);
  }
  
  void
  TM1637_set_brightness(const uint8_t value)
  {
  
  TM1637_send_config(_config & TM1637_SET_DISPLAY_ON,
  value & TM1637_BRIGHTNESS_MAX);
  }
  
  void
  TM1637_display_segments(const uint8_t position, const uint8_t segments)
  {
  
  TM1637_send_command(TM1637_CMD_SET_DATA | TM1637_SET_DATA_F_ADDR);
  TM1637_start();
  TM1637_write_byte(TM1637_CMD_SET_ADDR | (position & (TM1637_POSITION_MAX - 1)));
  TM1637_write_byte(segments);
  TM1637_stop();
  }
  
  void
  TM1637_display_digit(const uint8_t position, const uint8_t digit)
  {
  uint8_t segments = (digit < 10 ? pgm_read_byte_near((uint8_t *)&_digit2segments + digit) : 0x00);
  
  if (position == 0x01) {
  segments = segments | (_segments & 0x80);
  _segments = segments;
  }
  
  TM1637_display_segments(position, segments);
  }
  
  void
  TM1637_display_colon(const uint8_t value)
  {
  if (value) {
  _segments |= 0x80;
  } else {
  _segments &= ~0x80;
  }
  TM1637_display_segments(0x01, _segments);
  }
  
  void
  TM1637_clear(void)
  {
  uint8_t i;
  
  for (i = 0; i < TM1637_POSITION_MAX; ++i) {
  TM1637_display_segments(i, 0x00);
  }
  }
  
  void
  TM1637_send_config(const uint8_t enable, const uint8_t brightness)
  {
  
  _config = (enable ? TM1637_SET_DISPLAY_ON : TM1637_SET_DISPLAY_OFF) |
  (brightness > TM1637_BRIGHTNESS_MAX ? TM1637_BRIGHTNESS_MAX : brightness);
  
  TM1637_send_command(TM1637_CMD_SET_DSIPLAY | _config);
  }
  
  void
  TM1637_send_command(const uint8_t value)
  {
  
  TM1637_start();
  TM1637_write_byte(value);
  TM1637_stop();
  }
  
  void
  TM1637_start(void)
  {
  
  TM1637_DIO_HIGH();
  TM1637_CLK_HIGH();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  TM1637_DIO_LOW();
  }
  
  void
  TM1637_stop(void)
  {
  
  TM1637_CLK_LOW();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  TM1637_DIO_LOW();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  TM1637_CLK_HIGH();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  TM1637_DIO_HIGH();
  }
  
  uint8_t
  TM1637_write_byte(uint8_t value)
  {
  uint8_t i, ack;
  
  for (i = 0; i < 8; ++i, value >>= 1) {
  TM1637_CLK_LOW();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  if (value & 0x01) {
  TM1637_DIO_HIGH();
  } else {
  TM1637_DIO_LOW();
  }
  
  TM1637_CLK_HIGH();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  }
  
  TM1637_CLK_LOW();
  TM1637_DIO_INPUT();
  TM1637_DIO_HIGH();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  ack = TM1637_DIO_READ();
  if (ack) {
  TM1637_DIO_OUTPUT();
  TM1637_DIO_LOW();
  }
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  TM1637_CLK_HIGH();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  TM1637_CLK_LOW();
  // Delay 5 cycles, 5us at 1 MHz
  asm volatile (
  " lpm"  "\n"
  " rjmp 1f"  "\n"
  "1:"  "\n"
  );
  TM1637_DIO_OUTPUT();
  
  return ack;
  }
  
  
  
  // -------------------------------------------------------------------------------------------------------
  // -------------------------------------------------- MAIN CODE ------------------------------------------
  // -------------------------------------------------------------------------------------------------------
  
  
  int main(void)
  {
  uint8_t temperature, humidity, firstdig, seconddig;
  
  
  // delay 1 for startup
  delay1sec();
  
  /* setup */
  TM1637_init(1/*enable*/, 5/*brightness*/);
  
  /// display zeros at start - self check
  TM1637_display_digit(0, 0);
  TM1637_display_digit(1, 0);
  TM1637_display_digit(2, 0);
  TM1637_display_digit(3, 0);
  
  // delay 1 for diagnostic
  delay1sec();
  
  
  /* setup */
  dht_init();
  
  
  /* Beginning of neverending loop */
  while (1) {
  
  // read value from DHT11 sensor
  dht_read(&temperature, &humidity);
  
  
  // display TEMPERATURE first
  
  // display Celsius grade sign on third position
  TM1637_display_segments(2, 99);
  
  // display C letter on last position
  TM1637_display_segments(3, 57);
  
  //przeliczenie cyfr na wszystkich pozycjach
  firstdig = temperature / 10;
  seconddig = temperature % 10;
  
  // display 2 temperature digits
  TM1637_display_digit(0, firstdig);
  TM1637_display_digit(1, seconddig);
  
  // delay 1 second before next display
  delay1sec();
 
  
  // display HUMIDITY second
  
  // display P letter on third position
  TM1637_display_segments(2, 92);
  
  // display H on last position
  TM1637_display_segments(3, 118);
  
  //przeliczenie cyfr na wszystkich pozycjach
  firstdig = humidity / 10;
  seconddig = humidity % 10;
  
  // display 2 temperature digits
  TM1637_display_digit(0, firstdig);
  TM1637_display_digit(1, seconddig);
  
  // delay 1 second before next display
  delay1sec();
  
  
  
  };
  /* End of neverending loop */
  
  }
  
  