text: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *  http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  
  #include <assert.h>
  #include <string.h>
  #include <stdio.h>
  #include <errno.h>
  #include "sysinit/sysinit.h"
  #include "bsp/bsp.h"
  #include "os/os.h"
  #include "bsp/bsp.h"
  #include "hal/hal_gpio.h"
  #include "console/console.h"
  #include "hal/hal_system.h"
  #include "config/config.h"
  #include "split/split.h"
  #include "hal/hal_i2c.h"
  
  /* BLE */
  #include "nimble/ble.h"
  #include "host/ble_hs.h"
  #include "services/gap/ble_svc_gap.h"
  
  #include "bleprph.h"
  #include "main.h"
  
  /** Log data. */
  struct log bleprph_log;
  
  static int bleprph_gap_event(struct ble_gap_event *event, void *arg);
  
  veml6075_dev_t uv_sensor;
  
  void sensor_transmit(void *i2c_dev,
                       uint8_t addr,
                       uint8_t *tx,
                       size_t tx_bytes,
                       uint8_t *rx,
                       size_t rx_bytes)
  {
      struct hal_i2c_master_data rxdata = {.address = addr, .len = rx_bytes, .buffer = rx};
      struct hal_i2c_master_data txdata = {.address = addr, .len = tx_bytes, .buffer = tx};
  
      int rc = 0;
  
      if (rx_bytes == 0) {
          rc = hal_i2c_master_write((int)i2c_dev, &txdata, OS_TICKS_PER_SEC, 1);
      } else {
          rc = hal_i2c_master_write((int)i2c_dev, &txdata, OS_TICKS_PER_SEC, 0);
          assert(rc == 0);
          rc = hal_i2c_master_read((int)i2c_dev, &rxdata, OS_TICKS_PER_SEC, 1);
      }
  
      assert(rc == 0);
  }
  
  /**
   * Logs information about a connection to the console.
   */
  static void
  bleprph_print_conn_desc(struct ble_gap_conn_desc *desc)
  {
      BLEPRPH_LOG(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
                  desc->conn_handle, desc->our_ota_addr.type);
      BLEPRPH_LOG(INFO, " our_id_addr_type=%d our_id_addr=",
                  desc->our_id_addr.type);
      BLEPRPH_LOG(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
                  desc->peer_ota_addr.type);
      BLEPRPH_LOG(INFO, " peer_id_addr_type=%d peer_id_addr=",
                  desc->peer_id_addr.type);
      BLEPRPH_LOG(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
                        "encrypted=%d authenticated=%d bonded=%d\n",
                  desc->conn_itvl, desc->conn_latency,
                  desc->supervision_timeout,
                  desc->sec_state.encrypted,
                  desc->sec_state.authenticated,
                  desc->sec_state.bonded);
  }
  
  /**
   * Enables advertising with the following parameters:
   *     o General discoverable mode.
   *     o Undirected connectable mode.
   */
  static void
  bleprph_advertise(void)
  {
      struct ble_gap_adv_params adv_params;
      struct ble_hs_adv_fields fields;
      const char *name;
      int rc;
  
      /**
       *  Set the advertisement data included in our advertisements:
       *     o Flags (indicates advertisement type and other general info).
       *     o Advertising tx power.
       *     o Device name.
       *     o 16-bit service UUIDs (alert notifications).
       */
  
      memset(&fields, 0, sizeof fields);
  
      /* Advertise two flags:
       *     o Discoverability in forthcoming advertisement (general)
       *     o BLE-only (BR/EDR unsupported).
       */
      fields.flags = BLE_HS_ADV_F_DISC_GEN |
                     BLE_HS_ADV_F_BREDR_UNSUP;
  
      /* Indicate that the TX power level field should be included; have the
       * stack fill this value automatically.  This is done by assiging the
       * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
       */
      fields.tx_pwr_lvl_is_present = 1;
      fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
  
      name = ble_svc_gap_device_name();
      fields.name = (uint8_t *)name;
      fields.name_len = strlen(name);
      fields.name_is_complete = 1;
  
      fields.uuids16 = (ble_uuid16_t[]) {
          BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
      };
      fields.num_uuids16 = 1;
      fields.uuids16_is_complete = 1;
  
      rc = ble_gap_adv_set_fields(&fields);
      if (rc != 0) {
          BLEPRPH_LOG(ERROR, "error setting advertisement data; rc=%d\n", rc);
          return;
      }
  
      /* Begin advertising. */
      memset(&adv_params, 0, sizeof adv_params);
      adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
      adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
      rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
                             &adv_params, bleprph_gap_event, NULL);
      if (rc != 0) {
          BLEPRPH_LOG(ERROR, "error enabling advertisement; rc=%d\n", rc);
          return;
      }
  }
  
  /**
   * The nimble host executes this callback when a GAP event occurs.  The
   * application associates a GAP event callback with each connection that forms.
   * bleprph uses the same callback for all connections.
   *
   * @param event                 The type of event being signalled.
   * @param ctxt                  Various information pertaining to the event.
   * @param arg                   Application-specified argument; unuesd by
   *                                  bleprph.
   *
   * @return                      0 if the application successfully handled the
   *                                  event; nonzero on failure.  The semantics
   *                                  of the return code is specific to the
   *                                  particular GAP event being signalled.
   */
  static int
  bleprph_gap_event(struct ble_gap_event *event, void *arg)
  {
      struct ble_gap_conn_desc desc;
      int rc;
  
      switch (event->type) {
          case BLE_GAP_EVENT_CONNECT:
              /* A new connection was established or a connection attempt failed. */
              BLEPRPH_LOG(INFO, "connection %s; status=%d ",
                          event->connect.status == 0 ? "established" : "failed",
                          event->connect.status);
              if (event->connect.status == 0) {
                  rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
                  assert(rc == 0);
                  bleprph_print_conn_desc(&desc);
              }
              BLEPRPH_LOG(INFO, "\n");
  
              if (event->connect.status != 0) {
                  /* Connection failed; resume advertising. */
                  bleprph_advertise();
              }
              return 0;
  
          case BLE_GAP_EVENT_DISCONNECT:
              BLEPRPH_LOG(INFO, "disconnect; reason=%d ", event->disconnect.reason);
              bleprph_print_conn_desc(&event->disconnect.conn);
              BLEPRPH_LOG(INFO, "\n");
  
              /* Connection terminated; resume advertising. */
              bleprph_advertise();
              return 0;
  
          case BLE_GAP_EVENT_CONN_UPDATE:
              /* The central has updated the connection parameters. */
              BLEPRPH_LOG(INFO, "connection updated; status=%d ",
                          event->conn_update.status);
              rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
              assert(rc == 0);
              bleprph_print_conn_desc(&desc);
              BLEPRPH_LOG(INFO, "\n");
              return 0;
  
          case BLE_GAP_EVENT_ENC_CHANGE:
              /* Encryption has been enabled or disabled for this connection. */
              BLEPRPH_LOG(INFO, "encryption change event; status=%d ",
                          event->enc_change.status);
              rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
              assert(rc == 0);
              bleprph_print_conn_desc(&desc);
              BLEPRPH_LOG(INFO, "\n");
              return 0;
  
          case BLE_GAP_EVENT_SUBSCRIBE:
              BLEPRPH_LOG(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
                                "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
                          event->subscribe.conn_handle,
                          event->subscribe.attr_handle,
                          event->subscribe.reason,
                          event->subscribe.prev_notify,
                          event->subscribe.cur_notify,
                          event->subscribe.prev_indicate,
                          event->subscribe.cur_indicate);
              return 0;
  
          case BLE_GAP_EVENT_MTU:
              BLEPRPH_LOG(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
                          event->mtu.conn_handle,
                          event->mtu.channel_id,
                          event->mtu.value);
              return 0;
      }
  
      return 0;
  }
  
  static void
  bleprph_on_reset(int reason)
  {
      BLEPRPH_LOG(ERROR, "Resetting state; reason=%d\n", reason);
  }
  
  static void
  bleprph_on_sync(void)
  {
      /* Begin advertising. */
      bleprph_advertise();
  }
  
  #define BLINK_PRIO (254)
  struct os_task blink_task;
  os_stack_t blink_stack[256];
  
  static void blink_task_handler(void *p)
  {
      (void) p;
  
      while (true) {
          os_time_delay(0.1 * OS_TICKS_PER_SEC);
          hal_gpio_toggle(LED_BLINK_PIN);
      }
  }
  
  /**
   * main
   *
   * The main task for the project. This function initializes the packages,
   * then starts serving events from default event queue.
   *
   * @return int NOTE: this function should never return!
   */
  int
  main(void)
  {
      int rc;
  
      /* Set initial BLE device address. */
      memcpy(g_dev_addr, (uint8_t[6]) {0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}, 6);
  
      /* Initialize OS */
      sysinit();
  
      /* Initialize the bleprph log. */
      log_register("bleprph", &bleprph_log, &log_console_handler, NULL,
                   LOG_SYSLEVEL);
  
      /* Initialize the NimBLE host configuration. */
      log_register("ble_hs", &ble_hs_log, &log_console_handler, NULL,
                   LOG_SYSLEVEL);
      ble_hs_cfg.reset_cb = bleprph_on_reset;
      ble_hs_cfg.sync_cb = bleprph_on_sync;
  
      rc = gatt_svr_init();
      assert(rc == 0);
  
      /* Set the default device name. */
      rc = ble_svc_gap_device_name_set("ilanga");
      assert(rc == 0);
  
      conf_load();
  
      veml6075_init(&uv_sensor, sensor_transmit, (void *)0);
      veml6075_configure(&uv_sensor, VEML6075_TRIGGER_AUTO, VEML6075_EXPOSURE_400MS, false);
      hal_gpio_init_out(LED_BLINK_PIN, 1);
  
      os_task_init(&blink_task, "blink", blink_task_handler, NULL,
                   BLINK_PRIO, OS_WAIT_FOREVER, blink_stack,
                   sizeof(blink_stack) / sizeof(blink_stack[0]));
  
  
  
      /*
       * As the last thing, process events from default event queue.
       */
      while (1) {
          os_eventq_run(os_eventq_dflt_get());
      }
      return 0;
  }
  