/*
  Copyright (c) 2015 Arduino LLC.  All right reserved.
  Copyright (c) 2016 Sandeep Mistry All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include "Arduino.h"
#include "basic.h"

extern "C" {

bool pinDigitalRead[21] = {0};

void pinMode( uint32_t ulPin, uint32_t ulMode )
{
  switch ( ulMode )
  {
    case INPUT:

    break ;

    case INPUT_PULLUP:

    break ;

    case INPUT_PULLDOWN:

    break ;

    case OUTPUT:

    break ;

    default:
      // do nothing
    break ;
  }
}

// void pinMode( uint32_t ulPin, uint32_t ulMode )
// {
//   if (ulPin >= 21) {
//     return;
//   }

//   ulPin = g_ADigitalPinMap[ulPin];

//   // Set pin mode according to chapter '22.6.3 I/O Pin Configuration'
//   switch ( ulMode )
//   {
//     case INPUT:
//       // Set pin to input mode
//       NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input        << GPIO_PIN_CNF_DIR_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect    << GPIO_PIN_CNF_INPUT_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled    << GPIO_PIN_CNF_PULL_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
//     break ;

//     case INPUT_PULLUP:
//       // Set pin to input mode with pull-up resistor enabled
//       NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input        << GPIO_PIN_CNF_DIR_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect    << GPIO_PIN_CNF_INPUT_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup      << GPIO_PIN_CNF_PULL_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
//     break ;

//     case INPUT_PULLDOWN:
//       // Set pin to input mode with pull-down resistor enabled
//       NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input        << GPIO_PIN_CNF_DIR_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect    << GPIO_PIN_CNF_INPUT_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_PULL_Pulldown    << GPIO_PIN_CNF_PULL_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
//     break ;

//     case OUTPUT:
//       // Set pin to output mode
//       NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Output       << GPIO_PIN_CNF_DIR_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled    << GPIO_PIN_CNF_PULL_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
//                                | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
//     break ;

//     default:
//       // do nothing
//     break ;
//   }
// }

void digitalWrite( uint32_t ulPin, uint32_t ulVal )
{
  if (ulPin >= 21) {
    return;
  }

  ulPin = g_PinID[ulPin];
  MicroBitPin *pin = getMicroBitPin(ulPin);
  if (!pin) return;

  if(pinDigitalRead[ulPin]){
    pinDigitalRead[ulPin] = 0;
  }

  pin->setDigitalValue(ulVal);
}

int digitalRead( uint32_t ulPin )
{
  if (ulPin >= 21) {
    return 0;
  }

  ulPin = g_PinID[ulPin];
  MicroBitPin *pin = getMicroBitPin(ulPin);
  if (!pin) return 0;
  
  if(!pinDigitalRead[ulPin]){
    pin->getDigitalValue();
    pin->setPull(PullNone);
    pinDigitalRead[ulPin] = 1;
  }

  return pin->getDigitalValue();
}

void pinMode1( uint32_t ulPin, uint32_t ulMode )
{
  if (ulPin >= 21) {
    return;
  }

  ulPin = g_ADigitalPinMap[ulPin];

  // Set pin mode according to chapter '22.6.3 I/O Pin Configuration'
  switch ( ulMode )
  {
    case INPUT:
      // Set pin to input mode
      NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input        << GPIO_PIN_CNF_DIR_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect    << GPIO_PIN_CNF_INPUT_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled    << GPIO_PIN_CNF_PULL_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
    break ;

    case INPUT_PULLUP:
      // Set pin to input mode with pull-up resistor enabled
      NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input        << GPIO_PIN_CNF_DIR_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect    << GPIO_PIN_CNF_INPUT_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup      << GPIO_PIN_CNF_PULL_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
    break ;

    case INPUT_PULLDOWN:
      // Set pin to input mode with pull-down resistor enabled
      NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input        << GPIO_PIN_CNF_DIR_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect    << GPIO_PIN_CNF_INPUT_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_PULL_Pulldown    << GPIO_PIN_CNF_PULL_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
    break ;

    case OUTPUT:
      // Set pin to output mode
      NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Output       << GPIO_PIN_CNF_DIR_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled    << GPIO_PIN_CNF_PULL_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
    break ;

    default:
      // do nothing
    break ;
  }
}

}

// void digitalWrite( uint32_t ulPin, uint32_t ulVal )
// {

//   if (ulPin >= 21) {
//     return;
//   }

//   if(pinDigitalRead[ulPin]){
//     pinDigitalRead[ulPin] = 0;
//   }

//   ulPin = g_ADigitalPinMap[ulPin];

//   switch ( ulVal )
//   {
//     case LOW:
//       NRF_GPIO->OUTCLR = (1UL << ulPin);
//     break ;

//     default:
//       NRF_GPIO->OUTSET = (1UL << ulPin);
//     break ;
//   }

//   return ;
// }

// int digitalRead( uint32_t ulPin )
// {
//   if (ulPin >= 21) {
//     return 0;
//   }

//   ulPin = g_ADigitalPinMap[ulPin];

//   return ((NRF_GPIO->IN >> ulPin) & 1UL) ? HIGH : LOW ;
// }

void digitalWrite1( uint32_t ulPin, uint32_t ulVal )
{

  if (ulPin >= 21) {
    return;
  }

  if(pinDigitalRead[ulPin]){
    pinDigitalRead[ulPin] = 0;
  }

  ulPin = g_ADigitalPinMap[ulPin];

  switch ( ulVal )
  {
    case LOW:
      NRF_GPIO->OUTCLR = (1UL << ulPin);
    break ;

    default:
      NRF_GPIO->OUTSET = (1UL << ulPin);
    break ;
  }

  return ;
}

int digitalRead1( uint32_t ulPin )
{
  if (ulPin >= 21) {
    return 0;
  }

  ulPin = g_ADigitalPinMap[ulPin];

  return ((NRF_GPIO->IN >> ulPin) & 1UL) ? HIGH : LOW ;
}
