text: /* This is mbedtls boilerplate for library configuration */
  #if !defined(MBEDTLS_CONFIG_FILE)
  #include "mbedtls/esp_config.h"
  #else
  #include MBEDTLS_CONFIG_FILE
  #endif
  
  /* System Includes */
  #include "stdio.h"
  #include "stdlib.h"
  #include <string.h>
  
  
  /* From mbedtls */
  #include "mbedtls/platform.h"
  #include "mbedtls/net_sockets.h"
  #include "mbedtls/esp_debug.h"
  #include "mbedtls/ssl.h"
  #include "mbedtls/entropy.h"
  #include "mbedtls/ctr_drbg.h"
  #include "mbedtls/error.h"
  #include "mbedtls/certs.h"
  #include "mbedtls/pk.h"
  #include "mbedtls/entropy.h"
  #include "mbedtls/ctr_drbg.h"
  #include "mbedtls/ecdh.h"
  
  /* From Cryptoauthlib */
  #include "cryptoauthlib.h"
  #include "atcacert/atcacert_client.h"
  #include "mbedtls/atca_mbedtls_wrap.h"
  
  
  
  #include "atcacert/atcacert_def.h"
  
  
  /* Local Includes */
  #include "cert_chain.h"
  
  
  /* ESP32 specific */
  #include "driver/gpio.h"
  #include "driver/i2c.h"
  #include "esp_err.h"
  #include "esp_log.h"
  #include "freertos/FreeRTOS.h"
  #include "freertos/task.h"
  #include "freertos/event_groups.h"
  #include "esp_wifi.h"
  #include "esp_event_loop.h"
  #include "esp_system.h"
  #include "nvs_flash.h"
  
  #include "lwip/err.h"
  #include "lwip/sockets.h"
  #include "lwip/sys.h"
  #include "lwip/netdb.h"
  #include "lwip/dns.h"
  
  #include "sdkconfig.h" // generated by "make menuconfig"
  
  #include "mbedtls_config.h"
  
  
  
  //for heap calculating
  #include "esp_heap_caps.h"
  
  
  //for debug 
  #include "mbedtls/debug.h"
  
  
  #define SDA_PIN2 GPIO_NUM_18
  #define SCL_PIN2 GPIO_NUM_19
  
  #define TAG_ECC608 "ECC608"
  
  #define I2C_MASTER_ACK 0
  #define I2C_MASTER_NACK 1
  
  
  /* The examples use simple WiFi configuration that you can set via
     'make menuconfig'.
     If you'd rather not, just change the below entries to strings with
     the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
  */
  #define EXAMPLE_WIFI_SSID ""
  #define EXAMPLE_WIFI_PASS ""
  
  /* FreeRTOS event group to signal when we are connected & ready to make a request */
  static EventGroupHandle_t wifi_event_group;
  
  /* The event group allows multiple bits for each event,
     but we only care about one event - are we connected
     to the AP with an IP? */
  const int CONNECTED_BIT = BIT0;
  
  int atca_mbedtls_ecdh_slot_cb(void)
  {
      return 0xFFFF;
  }
  
  int atca_mbedtls_ecdh_ioprot_cb(uint8_t secret[32])
  {
      uint8_t iokeyrandom[32] = {};
  
      if (ATCA_SUCCESS != atcab_random(iokeyrandom))
      {
          printf("Failed to generate IO Prot Key");
          return 1;
      }
  
      if (ATCA_SUCCESS != atcab_write_zone(ATCA_ZONE_DATA, 4, 0, 0, iokeyrandom, ATCA_BLOCK_SIZE))
      {
          printf("Failed to write IO Prot Key");
          return 1;
      }
      memcpy(secret, iokeyrandom, ATCA_BLOCK_SIZE);
  
      return 0;
  }
  
  
  const unsigned char rootcacert[]={
  "-----BEGIN CERTIFICATE-----\n"
  "-----END CERTIFICATE-----\n"
  };
  
  void i2c_master_init()
  {
  	i2c_config_t i2c_config = {
  		.mode = I2C_MODE_MASTER,
  		.sda_io_num = SDA_PIN2,
  		.scl_io_num = SCL_PIN2,
  		.sda_pullup_en = GPIO_PULLUP_DISABLE,
  		.scl_pullup_en = GPIO_PULLUP_DISABLE,
  		.master.clk_speed = 100000
  		};
  			
  	i2c_param_config(I2C_NUM_0 , &i2c_config);
  	i2c_driver_install(I2C_NUM_0 , I2C_MODE_MASTER, 0, 0, 0);
  
  
  }
  
  
  static esp_err_t event_handler(void *ctx, system_event_t *event)
  {
      switch(event->event_id) {
      case SYSTEM_EVENT_STA_START:
          esp_wifi_connect();
          break;
      case SYSTEM_EVENT_STA_GOT_IP:
          xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
          break;
      case SYSTEM_EVENT_STA_DISCONNECTED:
          /* This is a workaround as ESP32 WiFi libs don't currently
             auto-reassociate. */
          esp_wifi_connect();
          xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
          break;
      default:
          break;
      }
      return ESP_OK;
  }
  
  static void initialise_wifi(void)
  {
      tcpip_adapter_init();
      wifi_event_group = xEventGroupCreate();
      ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
      wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
      ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
      ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
      wifi_config_t wifi_config = {
          .sta = {
              .ssid = EXAMPLE_WIFI_SSID,
              .password = EXAMPLE_WIFI_PASS,
          },
      };
      ESP_LOGI(TAG_ECC608, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
      ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
      ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
      ESP_ERROR_CHECK( esp_wifi_start() );
  }
  
  
  static void my_debug(void *ctx, int level,
      const char *file, int line,
      const char *str)
  {
      ((void)level);
  
      printf("%s:%04d: %s", file, line, str);
  }
  
  int atca_connect(const char * endpoint, const char * port, ATCAIfaceCfg *cfg)
  {
      int ret;
      mbedtls_net_context server_fd;
      const char *pers = "ssl_client1";
  
      mbedtls_entropy_context entropy;
      mbedtls_ctr_drbg_context ctr_drbg;
      mbedtls_ssl_context ssl;
      mbedtls_ssl_config conf;
      mbedtls_x509_crt cacert;
      mbedtls_pk_context pkey;
      mbedtls_x509_crt cert;
      ATCA_STATUS status;
  
  	 /* Start a session with the device */
  	 if (ATCA_SUCCESS != (status = atcab_init(cfg)))
  	 {
  	     printf("Failed to init: %d\r\n", status);
  	 }
  
      /*
      * 0. Initialize the RNG and the session data
      */
      mbedtls_net_init(&server_fd);
      mbedtls_ssl_init(&ssl);
      mbedtls_ssl_config_init(&conf);
      mbedtls_x509_crt_init(&cacert);
      mbedtls_x509_crt_init(&cert);
      mbedtls_ctr_drbg_init(&ctr_drbg);
  
      printf("\n  . Seeding the random number generator...");
      fflush(stdout);
  
      mbedtls_entropy_init(&entropy);
      if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
          (const unsigned char *)pers,
          strlen(pers))) != 0)
      {
          printf(" failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret);
          goto exit;
      }
  
      printf(" ok\n");
  
      /* Set Up Defaults */
      printf("  . Setting up the SSL/TLS structure...");
      fflush(stdout);
  
      if ((ret = mbedtls_ssl_config_defaults(&conf,
          MBEDTLS_SSL_IS_CLIENT,
          MBEDTLS_SSL_TRANSPORT_STREAM,
          MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
      {
          printf(" failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
          goto exit;
      }
  
      printf(" ok\n");
  
      if ((ret = mbedtls_x509_crt_parse(&cacert, rootcacert , sizeof(rootcacert) )) != 0 )
      {
          printf(" failed\n  ! mbedtls_x509_crt_parse returned %d\n\n", ret);
          goto exit;       
      }
  
  
  
      /* Convert to an mbedtls key */
      if (0 != atca_mbedtls_pk_init(&pkey, 0))
      {
          printf("Failed to parse key from device\n");
          goto exit;
      }
  
      /* Extract the device certificate and convert to mbedtls cert */
      if (0 != atca_mbedtls_cert_add(&cert, &g_cert_def_2_device))
      {
          printf("Failed to parse cert from device\n");
          goto exit;
      }
  
      status = atcab_release();
  	 if (ATCA_SUCCESS != (status = atcab_init(cfg)))
  	 {
  	     printf("Failed to init: %d\r\n", status);
  	 }
  
  
  
      /* Extract the signer certificate, convert, then attach to the chain */
      if (0 != atca_mbedtls_cert_add(&cert, &g_cert_def_1_signer))
      {
          printf("Failed to parse cert from device\n");
          goto exit;
      }
  
  
      /* Attach the certificate chain and private key to the SSL/TLS context */
      printf("  . Set up the client credentials.");
      fflush(stdout);
      if(0 != (ret = mbedtls_ssl_conf_own_cert(
              &conf, &cert, &pkey)))
      {
          printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\r\n", ret);
          goto exit;
      }
      printf(" ok\n");
  
      mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
      mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
      mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
      mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
  
      /* Set up the "ssl" session */
      if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
      {
          printf(" failed\n  ! mbedtls_ssl_setup returned %d\n\n", ret);
          goto exit;
      }
  
      if ((ret = mbedtls_ssl_set_hostname(&ssl, endpoint)) != 0)
      {
          printf(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
          goto exit;
      }
  
  
  
          /* Wait for the callback to set the CONNECTED_BIT in the
             event group.
          */
          xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
                              false, true, portMAX_DELAY);
          ESP_LOGI(TAG_ECC608, "Connected to AP");
  
  
  
  
      /* Start the connection */
      printf("  . Connecting to tcp/%s/%s...", endpoint, port);
      fflush(stdout);
  
      if ((ret = mbedtls_net_connect(&server_fd, endpoint, port, MBEDTLS_NET_PROTO_TCP)) != 0)
      {
          printf(" failed\n  ! mbedtls_net_connect returned %d\n\n", ret);
          goto exit;
      }
  
      printf(" ok\n");
  
  
  //debug
              mbedtls_debug_set_threshold(4);
              mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
  
  
      /* Attach the open handle to the ssl context */
      mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
  
      /* Start the tls handshake (opens the socket itself) */
      printf("  . Performing the SSL/TLS handshake...");
      fflush(stdout);
  
      while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
      {
          if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
          {
              printf(" failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret);
              goto exit;
          }
      }
      printf(" ok\n");
  
  
      printf("TLS Session Established and a Socket is ready for an Application\n");
      /* @TODO: Insert application here to interact with the now open TLS socket */
  
  
  
      /*
       * Write the GET request
       */
  
      int len;
      unsigned char buf[1024];
      char getrequest[100] = {};
  
      sprintf(getrequest, "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", endpoint);
  
  
      printf( "  > Write to server:" );
      fflush( stdout );
  
      len = sprintf( (char *) buf, getrequest );
  
      while( ( ret = mbedtls_ssl_write( &ssl, buf, len ) ) <= 0 )
      {
          if( ret != 0 )
          {
              printf( " failed\n  ! write returned %d\n\n", ret );
              goto exit;
          }
      }
  
      len = ret;
      printf( " %d bytes written\n\n%s", len, (char *) buf );
  
      /*
       * Read the HTTP response
       */
      printf( "  < Read from server:" );
      fflush( stdout );
      do
      {
          len = sizeof( buf ) - 1;
          memset( buf, 0, sizeof( buf ) );
          ret = mbedtls_ssl_read( &ssl, buf, len );
  
          if( ret <= 0 )
          {
              printf( "failed\n  ! ssl_read returned %d\n\n", ret );
              break;
          }
  
          len = ret;
          printf( " %d bytes read\n\n%s", len, (char *) buf );
      }
      while( 1 );
  
   
  
  
  
  // finish
      mbedtls_ssl_close_notify(&ssl);
  
  exit:
  
    printf("Free Heap Size 8bit = %d\r\n", heap_caps_get_free_size(MALLOC_CAP_8BIT));
    printf("Free Heap Size 32bit = %d\r\n", heap_caps_get_free_size(MALLOC_CAP_32BIT));
  
      mbedtls_net_free(&server_fd);
  
      mbedtls_x509_crt_free(&cacert);
      mbedtls_ssl_free(&ssl);
      mbedtls_ssl_config_free(&conf);
      mbedtls_ctr_drbg_free(&ctr_drbg);
      mbedtls_entropy_free(&entropy);
  
      return ret;
  }
  
  #if defined(_WIN32) || defined(__linux__) || defined(__unix__)
  
  int main(int argc, char *argv[])
  {
      if (argc < 2)
      {
          printf("\nUsage: %s <server> <port>\n", argv[0]);
          return -1;
      }
      else
      {
          return atca_connect(argv[1], argv[2]);
      }
  }
  
  #endif
  
  
  
  void maintask(void *ignore)
  {
  
          ATCAIfaceCfg cfg = {
                  .iface_type             = ATCA_I2C_IFACE,
                  .devtype                = ATECC608A,
                  .atcai2c.slave_address  = 0XC0,
                  .atcai2c.bus            = 1,
                  .atcai2c.baud           = 100000,
                  .wake_delay             = 1500,
                  .rx_retries             = 20
          };
  
      ATCA_STATUS status = atcab_init(&cfg);
  
      if (status != ATCA_SUCCESS) {
          ESP_LOGE(TAG_ECC608, "atcab_init() failed with ret=0x%08d\r\n", status);
      }
  	
  
      uint8_t rand_out[RANDOM_NUM_SIZE];
      status = atcab_random(rand_out);
  
      if (status != ATCA_SUCCESS) {
          ESP_LOGE(TAG_ECC608, "atcab_random() failed with ret=0x%08d\r\n", status);
      }
  
      uint8_t serial[ATCA_SERIAL_NUM_SIZE];
      status = atcab_read_serial_number(serial);
  
      if (status != ATCA_SUCCESS) {
  	ESP_LOGE(TAG_ECC608, "atcab_read_serial_number() failed with ret=0x%08d/r/n", status);
      }
  
      
      uint8_t revision[INFO_SIZE];
      status = atcab_info(revision);
  
      if (status != ATCA_SUCCESS) {
  	ESP_LOGE(TAG_ECC608, "atcab_read_serial_number() failed with ret=0x%08d/r/n", status);
      }
  
  
      uint8_t config_data[ATCA_ECC_CONFIG_SIZE];
      status = atcab_read_config_zone(config_data);
  
      if (status != ATCA_SUCCESS) {
  	ESP_LOGE(TAG_ECC608, "atcab_read_config_zone() failed with ret=0x%08d/r/n", status);
      }
  	
      	printf("Random Number:\n");
  
      for (int i = 0; i < 4; i++){
          for(int j = 0; j < 8; j++){
  	     printf("%02x ", rand_out[i * 8 + j]);
          }
  	printf("\n");	
      }
  
  	printf("Serial Number:\n");
  
  	for ( int i =0; i< 9; i++){
  	    printf("%02x ", serial[i]);
          }
  	   printf("\n");
  
  	printf("Revision Number:\n");
  
  	for ( int i =0; i< 4; i++){
  	    printf("%02x ", revision[i]);
          }
          printf("\n");	
  
  	printf("Config Zone data:\n");
  
          for (int i = 0; i < 16; i++){
             for(int j = 0; j < 8; j++){
  	     printf("%02x ", config_data[i * 8 + j]);
             }
  	   printf("\n");
          }
  
  status = atca_connect("" , "", &cfg);
  
    printf("Free Heap Size 8bit = %d\r\n", heap_caps_get_free_size(MALLOC_CAP_8BIT));
    printf("Free Heap Size 32bit = %d\r\n", heap_caps_get_free_size(MALLOC_CAP_32BIT));
  
  
  	vTaskDelete(NULL);
  }
  
  
  
  void app_main(void)
  {
  
      printf("Free Heap Size 8bit = %d\r\n", heap_caps_get_free_size(MALLOC_CAP_8BIT));
      printf("Free Heap Size 32bit = %d\r\n", heap_caps_get_free_size(MALLOC_CAP_32BIT));    
  	i2c_master_init();
      ESP_ERROR_CHECK( nvs_flash_init() );
      initialise_wifi();
  	xTaskCreate(&maintask, "maintask",  32768, NULL, 6, NULL);
  }
  