text: /*
   * Copyright (c) 2015, Zolertia
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   *
   * 3. Neither the name of the copyright holder nor the names of its
   *    contributors may be used to endorse or promote products derived
   *    from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  /*---------------------------------------------------------------------------*/
  /**
   * \addtogroup zoul
   * @{
   *
   * \defgroup zoul-cc1200 Zoul CC1200 arch
   *
   * CC1200 Zoul arch specifics
   * @{
   *
   * \file
   * CC1200 Zoul arch specifics
   */
  /*---------------------------------------------------------------------------*/
  #include "contiki.h"
  #include "contiki-net.h"
  #include "dev/leds.h"
  #include "reg.h"
  #include "spi-arch.h"
  #include "dev/ioc.h"
  #include "dev/sys-ctrl.h"
  #include "dev/spi.h"
  #include "dev/ssi.h"
  #include "dev/gpio.h"
  #include "cc1200-conf.h"
  #include <stdio.h>
  /*---------------------------------------------------------------------------*/
  #define CC1200_SPI_CLK_PORT_BASE   GPIO_PORT_TO_BASE(SPI0_CLK_PORT)
  #define CC1200_SPI_CLK_PIN_MASK    GPIO_PIN_MASK(SPI0_CLK_PIN)
  #define CC1200_SPI_MOSI_PORT_BASE  GPIO_PORT_TO_BASE(SPI0_TX_PORT)
  #define CC1200_SPI_MOSI_PIN_MASK   GPIO_PIN_MASK(SPI0_TX_PIN)
  #define CC1200_SPI_MISO_PORT_BASE  GPIO_PORT_TO_BASE(SPI0_RX_PORT)
  #define CC1200_SPI_MISO_PIN_MASK   GPIO_PIN_MASK(SPI0_RX_PIN)
  #define CC1200_SPI_CSN_PORT_BASE   GPIO_PORT_TO_BASE(CC1200_SPI_CSN_PORT)
  #define CC1200_SPI_CSN_PIN_MASK    GPIO_PIN_MASK(CC1200_SPI_CSN_PIN)
  #define CC1200_GDO0_PORT_BASE      GPIO_PORT_TO_BASE(CC1200_GDO0_PORT)
  #define CC1200_GDO0_PIN_MASK       GPIO_PIN_MASK(CC1200_GDO0_PIN)
  #define CC1200_GDO2_PORT_BASE      GPIO_PORT_TO_BASE(CC1200_GDO2_PORT)
  #define CC1200_GDO2_PIN_MASK       GPIO_PIN_MASK(CC1200_GDO2_PIN)
  #define CC1200_RESET_PORT_BASE     GPIO_PORT_TO_BASE(CC1200_RESET_PORT)
  #define CC1200_RESET_PIN_MASK      GPIO_PIN_MASK(CC1200_RESET_PIN)
  /*---------------------------------------------------------------------------*/
  #ifndef DEBUG_CC1200_ARCH
  #define DEBUG_CC1200_ARCH 0
  #endif
  /*---------------------------------------------------------------------------*/
  #if DEBUG_CC1200_ARCH > 0
  #define PRINTF(...) printf(__VA_ARGS__)
  #define BUSYWAIT_UNTIL(cond, max_time)                                  \
    do {                                                                  \
      rtimer_clock_t t0;                                                  \
      t0 = RTIMER_NOW();                                                  \
      while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) {} \
      if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time)))) { \
        printf("ARCH: Timeout exceeded in line %d!\n", __LINE__); \
      } \
    } while(0)
  #else
  #define PRINTF(...)
  #define BUSYWAIT_UNTIL(cond, max_time) while(!cond)
  #endif
  /*---------------------------------------------------------------------------*/
  extern int cc1200_rx_interrupt(void);
  /*---------------------------------------------------------------------------*/
  void
  cc1200_int_handler(uint8_t port, uint8_t pin)
  {
    /* To keep the gpio_register_callback happy */
    cc1200_rx_interrupt();
  }
  /*---------------------------------------------------------------------------*/
  void
  cc1200_arch_spi_select(void)
  {
    /* Set CSn to low (0) */
    GPIO_CLR_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK);
    /* The MISO pin should go low before chip is fully enabled. */
    BUSYWAIT_UNTIL(
      GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK) == 0,
      RTIMER_SECOND / 100);
  }
  /*---------------------------------------------------------------------------*/
  void
  cc1200_arch_spi_deselect(void)
  {
    /* Set CSn to high (1) */
    GPIO_SET_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK);
  }
  /*---------------------------------------------------------------------------*/
  int
  cc1200_arch_spi_rw_byte(uint8_t c)
  {
    SPI_WAITFORTx_BEFORE();
    SPIX_BUF(CC1200_SPI_INSTANCE) = c;
    SPIX_WAITFOREOTx(CC1200_SPI_INSTANCE);
    SPIX_WAITFOREORx(CC1200_SPI_INSTANCE);
    c = SPIX_BUF(CC1200_SPI_INSTANCE);
  
    return c;
  }
  /*---------------------------------------------------------------------------*/
  int
  cc1200_arch_spi_rw(uint8_t *inbuf, const uint8_t *write_buf, uint16_t len)
  {
    int i;
    uint8_t c;
  
    if((inbuf == NULL && write_buf == NULL) || len <= 0) {
      return 1;
    } else if(inbuf == NULL) {
      for(i = 0; i < len; i++) {
        SPI_WAITFORTx_BEFORE();
        SPIX_BUF(CC1200_SPI_INSTANCE) = write_buf[i];
        SPIX_WAITFOREOTx(CC1200_SPI_INSTANCE);
        SPIX_WAITFOREORx(CC1200_SPI_INSTANCE);
        c = SPIX_BUF(CC1200_SPI_INSTANCE);
        /* read and discard to avoid "variable set but not used" warning */
        (void)c;
      }
    } else if(write_buf == NULL) {
      for(i = 0; i < len; i++) {
        SPI_WAITFORTx_BEFORE();
        SPIX_BUF(CC1200_SPI_INSTANCE) = 0;
        SPIX_WAITFOREOTx(CC1200_SPI_INSTANCE);
        SPIX_WAITFOREORx(CC1200_SPI_INSTANCE);
        inbuf[i] = SPIX_BUF(CC1200_SPI_INSTANCE);
      }
    } else {
      for(i = 0; i < len; i++) {
        SPI_WAITFORTx_BEFORE();
        SPIX_BUF(CC1200_SPI_INSTANCE) = write_buf[i];
        SPIX_WAITFOREOTx(CC1200_SPI_INSTANCE);
        SPIX_WAITFOREORx(CC1200_SPI_INSTANCE);
        inbuf[i] = SPIX_BUF(CC1200_SPI_INSTANCE);
      }
    }
    return 0;
  }
  /*---------------------------------------------------------------------------*/
  void
  cc1200_arch_gpio0_setup_irq(int rising)
  {
  
    GPIO_SOFTWARE_CONTROL(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
    GPIO_SET_INPUT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
    GPIO_DETECT_EDGE(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
    GPIO_TRIGGER_SINGLE_EDGE(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
  
    if(rising) {
      GPIO_DETECT_RISING(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
    } else {
      GPIO_DETECT_FALLING(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
    }
  
    GPIO_ENABLE_INTERRUPT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
    ioc_set_over(CC1200_GDO0_PORT, CC1200_GDO0_PIN, IOC_OVERRIDE_PUE);
    NVIC_EnableIRQ(CC1200_GPIOx_VECTOR);
    gpio_register_callback(cc1200_int_handler, CC1200_GDO0_PORT,
                           CC1200_GDO0_PIN);
  }
  /*---------------------------------------------------------------------------*/
  #if CC1200_USE_GPIO2
  void
  cc1200_arch_gpio2_setup_irq(int rising)
  {
    GPIO_SOFTWARE_CONTROL(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
    GPIO_SET_INPUT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
    GPIO_DETECT_EDGE(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
    GPIO_TRIGGER_SINGLE_EDGE(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
  
    if(rising) {
      GPIO_DETECT_RISING(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
    } else {
      GPIO_DETECT_FALLING(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
    }
  
    GPIO_ENABLE_INTERRUPT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
    ioc_set_over(CC1200_GDO2_PORT, CC1200_GDO2_PIN, IOC_OVERRIDE_PUE);
    NVIC_EnableIRQ(CC1200_GPIOx_VECTOR);
    gpio_register_callback(cc1200_int_handler, CC1200_GDO2_PORT,
                           CC1200_GDO2_PIN);
  }
  #endif /* CC1200_USE_GPIO2 */
  /*---------------------------------------------------------------------------*/
  void
  cc1200_arch_gpio0_enable_irq(void)
  {
    GPIO_ENABLE_INTERRUPT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
    ioc_set_over(CC1200_GDO0_PORT, CC1200_GDO0_PIN, IOC_OVERRIDE_PUE);
    NVIC_EnableIRQ(CC1200_GPIOx_VECTOR);
  }
  /*---------------------------------------------------------------------------*/
  void
  cc1200_arch_gpio0_disable_irq(void)
  {
    GPIO_DISABLE_INTERRUPT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
  }
  /*---------------------------------------------------------------------------*/
  #if CC1200_USE_GPIO2
  void
  cc1200_arch_gpio2_enable_irq(void)
  {
    GPIO_ENABLE_INTERRUPT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
    ioc_set_over(CC1200_GDO2_PORT, CC1200_GDO2_PIN, IOC_OVERRIDE_PUE);
    NVIC_EnableIRQ(CC1200_GPIOx_VECTOR);
  }
  #endif /* CC1200_USE_GPIO2 */
  /*---------------------------------------------------------------------------*/
  #if CC1200_USE_GPIO2
  void
  cc1200_arch_gpio2_disable_irq(void)
  {
    GPIO_DISABLE_INTERRUPT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
  }
  #endif /* CC1200_USE_GPIO2 */
  /*---------------------------------------------------------------------------*/
  int
  cc1200_arch_gpio0_read_pin(void)
  {
    return (GPIO_READ_PIN(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK) ? 1 : 0);
  }
  /*---------------------------------------------------------------------------*/
  #if CC1200_USE_GPIO2
  int
  cc1200_arch_gpio2_read_pin(void)
  {
    return (GPIO_READ_PIN(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK) ? 1 : 0);
  }
  #endif /* CC1200_USE_GPIO2 */
  /*---------------------------------------------------------------------------*/
  int
  cc1200_arch_gpio3_read_pin(void)
  {
    return 0x00;
  }
  /*---------------------------------------------------------------------------*/
  void
  cc1200_arch_init(void)
  {
  #if CC1200_USE_RESET
    /* First leave RESET high */
    GPIO_SOFTWARE_CONTROL(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK);
    GPIO_SET_OUTPUT(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK);
    ioc_set_over(CC1200_RESET_PORT, CC1200_RESET_PIN, IOC_OVERRIDE_OE);
    GPIO_SET_PIN(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK);
  #endif /* CC1200_USE_RESET */
  
    /* Initialize CSn, enable CSn and then wait for MISO to go low*/
    spix_cs_init(CC1200_SPI_CSN_PORT, CC1200_SPI_CSN_PIN);
  
    /* Initialize SPI */
    spix_init(CC1200_SPI_INSTANCE);
  
    /* Configure GPIOx */
    GPIO_SOFTWARE_CONTROL(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
    GPIO_SET_INPUT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
  #if CC1200_USE_GPIO2
    GPIO_SOFTWARE_CONTROL(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
    GPIO_SET_INPUT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
  #endif /* CC1200_USE_GPIO2 */
  
    /* Leave CSn as default */
    cc1200_arch_spi_deselect();
  
    /* Ensure MISO is high */
    BUSYWAIT_UNTIL(
      GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK),
      RTIMER_SECOND / 10);
  }
  /*---------------------------------------------------------------------------*/
  /**
   * @}
   * @}
   */
  