text: /*
   * Author: Jon Trulson <jtrulson@ics.com>
   * Copyright (c) 2016 Intel Corporation
   *
   * Permission is hereby granted, free of charge, to any person obtaining
   * a copy of this software and associated documentation files (the
   * "Software"), to deal in the Software without restriction, including
   * without limitation the rights to use, copy, modify, merge, publish,
   * distribute, sublicense, and/or sell copies of the Software, and to
   * permit persons to whom the Software is furnished to do so, subject to
   * the following conditions:
   *
   * The above copyright notice and this permission notice shall be
   * included in all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
   * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
   * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   */
  
  #pragma once
  
  #include "uart_ow.h"
  #include "types.hpp"
  #include <stdexcept>
  #include <cstring>
  
  namespace mraa
  {
  
  /**
   * @brief API for UART One Wire
   *
   * This file defines the UartOW (UART to Dallas 1-wire) interface for libmraa
   *
   * @snippet UartOW.cpp Interesting
   */
  class UartOW
  {
    public:
      /**
       * UartOW Constructor, takes a pin number which will map directly to the
       * linux uart number, this 'enables' the uart, nothing more
       *
       * @throws std::invalid_argument in case of error
       * @param uart the index of the uart to use
       */
      UartOW(int uart)
      {
          m_uart = mraa_uart_ow_init(uart);
  
          if (m_uart == NULL) {
              throw std::invalid_argument("Error initialising UART_OW");
          }
      }
  
      /**
       * UartOW Constructor, takes a string to the path of the serial
       * interface that is needed.
       *
       * @throws std::invalid_argument in case of error
       * @param path the file path for the UART to use
       */
      UartOW(std::string path)
      {
          m_uart = mraa_uart_ow_init_raw(path.c_str());
  
          if (m_uart == NULL) {
              throw std::invalid_argument("Error initialising UART");
          }
      }
  
      /**
       * Uart destructor
       */
      ~UartOW()
      {
          mraa_uart_ow_stop(m_uart);
      }
  
      /**
       * Get string with tty device path within Linux
       * For example. Could point to "/dev/ttyS0"
       *
       * @return char pointer of device path
       */
      std::string
      getDevicePath()
      {
          std::string ret_val(mraa_uart_ow_get_dev_path(m_uart));
          return ret_val;
      }
  
      /**
       * Read a byte from the 1-wire bus
       *
       * @throws std::invalid_argument in case of error
       * @return the byte read
       */
      uint8_t
      readByte()
      {
          int res = mraa_uart_ow_read_byte(m_uart);
          if (res == -1) {
              throw std::invalid_argument("Unknown UART_OW error");
          }
          return (uint8_t) res;
      }
  
      /**
       * Write a byte to a 1-wire bus
       *
       * @param byte the byte to write to the bus
       *
       * @throws std::invalid_argument in case of error
       * @return the byte read back during the time slot
       */
      uint8_t
      writeByte(uint8_t byte)
      {
          int res = mraa_uart_ow_write_byte(m_uart, byte);
          if (res == -1) {
              throw std::invalid_argument("Unknown UART_OW error");
          }
          return (uint8_t) res;
      }
  
      /**
       * Write a bit to a 1-wire bus and read a bit corresponding to the
       * time slot back.  This is possible due to the way we wired the TX
       * and RX together with a diode, forming a loopback.
       *
       * @param bit the bit to write to the bus
       * @throws std::invalid_argument in case of error
       * @return the bit read back during the time slot
       */
      bool
      writeBit(bool bit)
      {
          int res = mraa_uart_ow_bit(m_uart, (bit) ? 1 : 0);
          if (res == -1) {
              throw std::invalid_argument("Unknown UART_OW error");
          }
          return ((res) ? true : false);
      }
  
      /**
       * Send a reset pulse to the 1-wire bus and test for device presence
       *
       * @return one of the mraa::Result values
       */
      mraa::Result
      reset()
      {
          return (mraa::Result) mraa_uart_ow_reset(m_uart);
      }
  
      /**
       * Begin a rom code search of the 1-wire bus.  This function
       * implements the 1-wire search algorithm.  See the uart_ow.c example
       * for an idea on how to use this function to identify all devices
       * present on the bus.
       *
       * @param start true to start a search from scratch, false to
       * continue a previously started search
       * @param id the 8-byte rom code id of the current matched device when a
       * device is found
       * @return one of the mraa::Result values
       */
      mraa::Result
      search(bool start, uint8_t* id)
      {
          return (mraa::Result) mraa_uart_ow_rom_search(m_uart, (start) ? 1 : 0, id);
      }
  
      /**
       * Begin a rom code search of the 1-wire bus.  This function
       * implements the 1-wire search algorithm.  See the UartOW.cpp
       * example for an idea on how to use this function to identify all
       * devices present on the bus.
       *
       * @param start true to start a search from scratch, false to
       * continue a previously started search
       * @return an empty string if no [more] devices are found, or a
       * string containing the 8-byte romcode of a detected device.
       */
      std::string
      search(bool start)
      {
          uint8_t id[MRAA_UART_OW_ROMCODE_SIZE];
          mraa_result_t rv;
  
          rv = mraa_uart_ow_rom_search(m_uart, (start) ? 1 : 0, id);
  
          if (rv == MRAA_SUCCESS) {
              // we found one
              std::string idStr((char*) id, MRAA_UART_OW_ROMCODE_SIZE);
              return idStr;
          } else {
              // failure, or end of search
              return "";
          }
      }
  
      /**
       * Send a command byte to a device on the 1-wire bus
       *
       * @param command the command byte to send
       * @param id the rom code id of the device to receive the command,
       * NULL for all devices on the bus
       * @return one of the mraa::Result values
       */
      mraa::Result
      command(uint8_t command, uint8_t* id)
      {
          return (mraa::Result) mraa_uart_ow_command(m_uart, command, id);
      }
  
      /**
       * Send a command byte to a device on the 1-wire bus, supplying
       * the id as a std::string
       *
       * @param command the command byte to send
       * @param id std::string representing the code id of the device to
       * receive the command, or an empty string for all devices on the
       * bus.  This string should be 8 bytes in size.
       * @return one of the mraa::Result values
       */
      mraa::Result
      command(uint8_t command, std::string id)
      {
          if (id.empty() == 0)
              return (mraa::Result) mraa_uart_ow_command(m_uart, command, NULL);
          else {
              if (id.size() != 8) {
                  // Only 8 byte romcodes are legal.
                  throw std::invalid_argument(std::string(__FUNCTION__) +
                                              ": id must be 8 bytes only");
              }
              return (mraa::Result) mraa_uart_ow_command(m_uart, command, (uint8_t*) id.c_str());
          }
      }
  
      /**
       * Perform a Dallas 1-wire compliant CRC8 computation on a buffer
       *
       * @param buffer the buffer containing the data
       * @param length the length of the buffer
       * @return the computed CRC
       */
      uint8_t
      crc8(uint8_t* buffer, uint16_t length)
      {
          return mraa_uart_ow_crc8(buffer, length);
      }
  
      /**
       * Perform a Dallas 1-wire compliant CRC8 computation on a
       * std::string based buffer
       *
       * @param buffer std::string buffer containing the data
       * @return the computed CRC
       */
      uint8_t
      crc8(std::string buffer)
      {
          return mraa_uart_ow_crc8((uint8_t*) buffer.c_str(), buffer.size());
      }
  
    private:
      mraa_uart_ow_context m_uart;
  };
  }
  