//------------------------------------------------------------------------------
//-- BluNode v4
//------------------------------------------------------------------------------
//
// Funciones:
//
//  1. Timer 0    : Primer advertising al colocar la pila
//  2. Timer 1    : Ventana de tiempo de espera (sleep)
//  3. Timer 2    : Ventana de envío de mensajes (advertising)
//  4. Btn1_Timer : Monitoreo de botón 1 pulsado
//
//------------------------------------------------------------------------------


/* Bibliotecas integradas en la aplicación */

#include "mbed.h"
#include "BLE.h"
#include "UARTService.h"

#include "nrf.h"
#include "nrf_temp.h"
#include "nrf_gpio.h"


#define NEED_CONSOLE_OUTPUT 1 /*  Set this if you need debug messages on the console;
* it will have an impact on code-size and power consumption. */

#if NEED_CONSOLE_OUTPUT
#define DEBUG(...) { printf(__VA_ARGS__); }
#else
#define DEBUG(...)
#endif


//------------------------------------------------------------------------------
//-- Funciones utilizadas
//------------------------------------------------------------------------------

/* Inicializadores */

void adc_channels_init(void);                                                   // Inicialización de los canales análogos (escala, rango, tipo, etc...)
void app_init();                                                                // Inicialización de la "aplicación"
void adv_init();                                                                // Inicialización de los parámetros de advertising
void btn_init();                                                                // Inicialización de eventos de botón

/* Utilitarios de advertising */

void adv_start();                                                               // Función de inicio de advertising
void adv_stop();                                                                // Función de detención del advertising
void adv_clear();                                                               // Función para borrar la data de "payload"
void adv_stop_and_clear();                                                      // Función paera detener y borrar los datos de "payload"
void adv_payload_set4adv(void);                                                 // Función para actualizar los valores de medición y carga datos en "payload"


/* Obtiene resultados de medición de los canales análogos */

uint16_t adc_channel_read(int adcChannel);                                      // Lectura del canal "adcChannel"
void adc_channels_read(void);                                                   // Lectura de todos los canales configurados en adc_channels[]
uint8_t soc_temperature_read(void);                                             // Lectura de temperatura interna del chip (SoC Temperature)


/* Procesos para ejecutar por eventos */

void time_monitor();                                                            // Proceso que se ejecuta en ventanas de tiempos para espera (sleep)
void adv_run();                                                                 // Proceso que ejecuta la activación de envío de advertising de resultados
void adv_run_first_time();                                                      // Proceso que ejecuta el envío de advertising inicial
void btn1_event_monitor();                                                      // Proceso que monitorea si se ha pulsado el botón
void btn1_pressed_time();                                                       // Proceso que monitorea si se mantiene el botón apretado
void start_advertising_helper();                                                // Helper que permite iniciar un ciclo de advertising

/* Funciones para pinDetect */

//void pin_key_pressed();

void button1_pressed();

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- Variables v3
//------------------------------------------------------------------------------

//PinDetect pin( BUTTON1 );                                                       // P0.17 en PCA10028 es el botón 1

//------------------------------------------------------------------------------
















//------------------------------------------------------------------------------
//-- Atributos y variables internas del programa
//------------------------------------------------------------------------------

UARTService *uartServicePtr;
BLE ble;




//DigitalOut activeLed(LED1, 1);
//DigitalOut connectLed(LED2, 0);

//DigitalIn     btn1(BUTTON1);                                                    // Variable que permite obtener el estado del botón 1 (pulsado/no pulsado)
//InterruptIn   btn1_press(BUTTON1);                                              // Variable que permite ejecutar una función dependiente del evento de "pulsar botón 1"


//@2017-03-09, By TIGG (Requested By RVR)
DigitalOut   out_activity_status(P0_21);
DigitalOut   out_adc_enabled(P0_22);                                            // Salida digital para activación de PS de circuito ADC de medición: Se activa antes de medir

DigitalIn     btn1(P0_17);                                                      // Variable que permite obtener el estado del botón 1 (pulsado/no pulsado)
InterruptIn   btn1_press(P0_17);                                                // Variable que permite ejecutar una función dependiente del evento de "pulsar botón 1"




//------------------------------------------------------------------------------
//-- Definitions - Parameters & Macros
//------------------------------------------------------------------------------

const static char     DEVICE_NAME[] = "BN_0330";


#define     BLUCORE_ADV_LENGHT          0x10    // 2 + 1 + 13
#define     BLUCORE_ADV_TYPE_01_LENGHT  0x10    // 2 + 1 + 13
#define     BLUCORE_ADV_PAYLOAD_OFFSET  0x03    // 3
#define     BLUCORE_ADV_PAYLOAD_LENGHT  0x0D    // 13

#define     BLUCORE_COMPANY_ID          0xC7AB
#define     BLUCORE_BLUNODE_TYPE_01     0x01


//@2017-03-09, By TIGG

#define     OUT_ON                      0
#define     OUT_OFF                     1









//------------------------------------------------------------------------------
//-- Definition - Structures
//------------------------------------------------------------------------------

//-- Tipo payload data para nodo tipo 01

union PayloadDataType01 {
    uint8_t raw[16];
    struct {
        uint16_t    CompanyId;
        uint8_t     Type;
        uint16_t    Counter;
        uint16_t    ADC1_Value;
        uint16_t    ADC2_Value;
        uint16_t    ADC3_Value;
        uint16_t    ADC4_Value;
        uint8_t     DataTail[2];
        uint8_t     SOC_Temperature;
    };
};




















//------------------------------------------------------------------------------
//-- Variables
//------------------------------------------------------------------------------


bool isConnected=false;

static int value0,value1,value2,value3; // stored voltage reading from ADC

char dataOu[30];

//------------------------------------------------------------------------------
// Timers
//------------------------------------------------------------------------------

Ticker  t0;                                                                     // Utilizado para broadcast de mensaje inicial
Ticker  t1;                                                                     // Utilizado para esperar n-veces antes de iniciar un broadcast
Ticker  t2;                                                                     // Utilizado para broadcast de mensaje programado
Ticker  t3;                                                                     // Utilizado para broadcast de mensaje a pedido
Ticker  t4;                                                                     // Utilizado para broadcast de mensaje de localización

Ticker btn1_timer;                                                              // Temporizador para monitoreo de tiempo de botón 1 pulsado

Ticker testTimer;                                                               // Temporizador de pruebas


//------------------------------------------------------------------------------
// Flags de control de flujo
//------------------------------------------------------------------------------

//@2017-03-22, By TIGG
// - Se agregan las variables de control de flujo

//: t0
bool t0_start_cmd;
bool t0_restart_cmd;
bool t0_stop_cmd;
bool t0_pause_cmd;

bool t0_running;
bool t0_paused;
int  t0_counter;
int  t0_max_count;
int  t0_timer_interval;

//: t1
bool t1_start_cmd;
bool t1_restart_cmd;
bool t1_stop_cmd;
bool t1_pause_cmd;

bool t1_running;
bool t1_paused;
int  t1_counter;
int  t1_max_count;
int  t1_timer_interval;

//: t2
bool t2_start_cmd;
bool t2_restart_cmd;
bool t2_stop_cmd;
bool t2_pause_cmd;

bool t2_running;
bool t2_paused;
int  t2_counter;
int  t2_max_count;
int  t2_timer_interval;

//: t3
bool t3_start_cmd;
bool t3_restart_cmd;
bool t3_stop_cmd;
bool t3_pause_cmd;

bool t3_running;
bool t3_paused;
int  t3_counter;
int  t3_max_count;
int  t3_timer_interval;

//: t4
bool t4_start_cmd;
bool t4_restart_cmd;
bool t4_stop_cmd;
bool t4_pause_cmd;

bool t4_running;
bool t4_paused;
int  t4_counter;
int  t4_max_count;
int  t4_timer_interval;






//------------------------------------------------------------------------------
//-- Agregados para v2
//------------------------------------------------------------------------------


//-- Utils

#define MSB_16(a) (((a) & 0xFF00) >> 8)
#define LSB_16(a) ((a) & 0x00FF)

//-- Variables


#define adc_channel_count 4

static int          adc_channels[adc_channel_count];
static uint16_t     adc_values[adc_channel_count];
static uint16_t     adc_log_values[adc_channel_count];


static uint8_t      soc_temp = 0;

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);


//------------------------------------------------------------------------------
//-- flags
//------------------------------------------------------------------------------


static bool adv_run_first_time_flag;
static bool monitor_stop_flag;
static bool adv_stop_flag;

static bool btn1_pressed_flag;
static bool btn1_held_flag;
static bool btn1_monitor_stop_flag;


//------------------------------------------------------------------------------




//------------------------------------------------------------------------------
//-- MAC ADDRESS
//------------------------------------------------------------------------------

const uint8_t bluNodeMACaddress[] = {0x01,0x00,0xFE,0xCA,0xAB,0xc7};






uint8_t payload[BLUCORE_ADV_LENGHT];


// Variables de control y notificación

static uint16_t adv_count = 0;


//-- Parámetros de tiempo

static int time_monitor_count         = 0;
static int time_monitor_max_count     = 10;                                     // 10 periodos de monitoreo (10 x 30 = 5 minutos

static int adv_time_interval          = 300;                                    // 1000 ms = 1 sec
static int adv_time_periods           = 10;              // 4 times
static int adv_run_count              = 0;

static int app_time_monitor_interval  = 30;                                     // 30 sec
static int app_adv_run_interval       = 1;                                      // 1 sec

static int app_btn1_pressed_time      = 3;                                      // Tiempo de monitoreo para determinar si se ha pulsado o mantenido por más de 3 segundos
static int btn1_pressed_count         = 0;

static int btn1_press_count           = 0;


//-- Partámetros de advertising

static int man_adv_run_count          = 0;
static int man_adv_time_interval      = 350;                                    // Advertising cada 350 ms
static int man_adv_time_periods       = 2;                                      // Conteo de advertising manual (2 veces x 1 seg = 2 seg)
static int man_adv_timer_time         = 1;                                      // Intervalo de conteo del temporizador de advertising manual (1 seg)

//@2017-03-22, By TIGG
//-- Parámetros de advertising para adv inicial

int app_t0_adv_time_interval; //          = 300;






















































//------------------------------------------------------------------------------
//-- Connection Call Back
//------------------------------------------------------------------------------

void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
{
    //DEBUG("Connected \n");

    //connectLed=1;
    isConnected=true;

}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- Disconnection Call Back
//------------------------------------------------------------------------------

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    //ble.startAdvertising();
    isConnected=false;
}

//------------------------------------------------------------------------------



int advActivePeriod;
int sleepActivePeriod;

//------------------------------------------------------------------------------
//-- onDataWritten
//------------------------------------------------------------------------------

void onDataWritten(const GattWriteCallbackParams *params)
{
    if ((uartServicePtr != NULL) && (params->handle == uartServicePtr->getTXCharacteristicHandle())) {


        if (strncmp("param1=",(const char *)params->data,7)==0) {
            sscanf((const char *)params->data,"param1=%i", &advActivePeriod);
            sprintf(dataOu,"Adver=%i sec\n",advActivePeriod);
            ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(),(const uint8_t *)dataOu , 20);

        } else if (strncmp("param2=",(const char *)params->data,7)==0) {
            sscanf((const char *)params->data,"param2=%i",&sleepActivePeriod);
            sprintf(dataOu,"Sleep=%i sec\n",sleepActivePeriod);

            ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(),(const uint8_t *)dataOu, 20);

        } else if (strncmp("status",(const char *)params->data,6)==0) {
            sprintf(dataOu,"adv_count=%i times\n",adv_count);
            ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(),(const uint8_t *)dataOu, 20);

        } else if (strncmp("fast",(const char *)params->data,4)==0) {
               //intervalTime = 1; 
               //restart        
        }else if (strncmp("slow",(const char *)params->data,4)==0) {
               //intervalTime = 5; 
               //restart        
        }


        else if (strncmp("scan",(const char *)params->data,4)==0) {
            ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(),(const uint8_t *)dataOu, 20);
            wait(5);

            value1 = (int) (adc_channel_read(2) & 0x00FFFF);
            sprintf(dataOu,"A1=%i \n",value1);

            ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(),(const uint8_t *)dataOu, 20);
            wait(5);
            value2 = (int) (adc_channel_read(3) & 0x00FFFF);
            sprintf(dataOu,"A2=%i \n",value2);
            DEBUG("%s",dataOu);
            ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(),(const uint8_t *)dataOu, 20);
            wait(5);
            //my_analogin_read_u16A3();
            value3 = (int) (adc_channel_read(4) & 0x00FFFF);
            sprintf(dataOu,"A3=%i \n",value3);
            DEBUG("%s",dataOu);
            ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(),(const uint8_t *)dataOu, 20);


        }
    }

}

//------------------------------------------------------------------------------


















//------------------------------------------------------------------------------
//--
//------------------------------------------------------------------------------

void advActiveFunc (void)
{
    //sleepCall.detach();
    //t1.attach(time_monitor, 10);

}

//------------------------------------------------------------------------------

void SleepFunc(void)
{
    //t.attach(my_analogin_read,1); //repeatedly read analog every second.
    //t.attach(adc_channels_read, 1);
    //t.attach(time_monitor, 10);
    //DEBUG("\nWAKE UP!!");
    //activeLed=1;
}


























































































uint8_t adv_type_mark;
uint8_t blu_node_type;

//------------------------------------------------------------------------------
//-- T0_FUNC
//------------------------------------------------------------------------------
//
// Primer advertising con la primera conexión a la batería (cold start)
//
//------------------------------------------------------------------------------


void t0_func()
{
    t0_counter++;

    if (t0_counter == 1) {
        t0_running = true;
        adv_type_mark = 0x80 & blu_node_type;
    }

    if (t0_counter > t0_max_count) {
        t0_stop_cmd = true;
    }

}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- T1_FUNC
//------------------------------------------------------------------------------
//
//
//------------------------------------------------------------------------------

void t1_func()
{

    t1_counter++;

    if (t1_counter > t1_max_count) {
        t1_running = true;

        start_advertising_helper();                                             // Función que inicializa los parámetros para ejecutar un advertising

    }
}

//------------------------------------------------------------------------------





void set_payload_data()
{
    //-- Company Id
    payload[0]      = MSB_16(BLUCORE_COMPANY_ID);
    payload[1]      = LSB_16(BLUCORE_COMPANY_ID);
    //-- Node Type
    payload[2]      = adv_type_mark; //BLUCORE_BLUNODE_TYPE_01;
    //-- Counter
    payload[3]      = MSB_16(adv_count);
    payload[4]      = LSB_16(adv_count);
    // ADC Channel 1
    payload[5]      = MSB_16(adc_values[0]);
    payload[6]      = LSB_16(adc_values[0]);
    // ADC Channel 2
    payload[7]      = MSB_16(adc_values[1]);
    payload[8]      = LSB_16(adc_values[1]);
    // ADC Channel 3
    payload[9]      = MSB_16(adc_values[2]),
                      payload[10]     = LSB_16(adc_values[2]);
    // ADC Channel 4
    payload[11]     = MSB_16(adc_values[3]),
                      payload[12]     = LSB_16(adc_values[3]);
    // 2 bytes spare
    payload[13]     = 0xFF;
    payload[14]     = LSB_16(btn1_press_count);
    // SOC Temperature
    payload[15]     = soc_temp; //((uint8_t) (( soc_temp & 0x000000FF) & 0xFF ));


}






































//------------------------------------------------------------------------------    ------>>>>  INICIO DE IMPLEMENTACION DE FUNCIONES Y PROCESOS
//: Inicio implementación de funciones y procesos                                   ------------------------------------------------------------------------------
//------>>>















//------------------------------------------------------------------------------
//-- Funciones mejoradas v2, v3
//------------------------------------------------------------------------------


//-- Inicializadores


//------------------------------------------------------------------------------
//-- Funciones de inicialización
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//-- App Init
//------------------------------------------------------------------------------
//
// Inicialización de la aplicación
//
//------------------------------------------------------------------------------

void app_init()
{
    nrf_temp_init();
    ble.init();
    adv_init();

    /**/


    adc_channels_init();
    // reset LED's
    led1 = 1;
    led2 = 1;
    led3 = 1;
    led4 = 1;

    adv_count = 0;
    monitor_stop_flag = false;
    adv_stop_flag = false;

    //@2017-03-22, By TIGG
    // - Inicializaciones por "default"

    t0_timer_interval = 1;
    t0_max_count = 10;
    app_t0_adv_time_interval = 300;

    blu_node_type = (uint8_t) BLUCORE_BLUNODE_TYPE_01;

    for (int i = 0; i < adc_channel_count; i++) {
        adc_values[i] = 0xFF;
    }


}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- advertising init
//------------------------------------------------------------------------------

void adv_init()
{

    /**/

    //ble.onDisconnection(disconnectionCallback);
    //ble.onDataWritten(onDataWritten);
    //ble.onConnection(connectionCallback);

    //-- Set MAC address (like UUID)

    ble.setAddress(Gap::ADDR_TYPE_PUBLIC, bluNodeMACaddress);


}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- Inicialización de canales ADC
//------------------------------------------------------------------------------
//  - Configure Resolution to 10 bits
//  - Configure ADC input selection and prescalar settings
//  - Internal reference voltage of 1.2V. Onethird prescaling -> 3.6V
//  - ADC reference selection to internal 1.2V VBG
//  - Select Pin to be used as ADC input pin -> Disable analog pins
//  - Select external reference pin -> No external reference (we use internal reference of 1.2V)
//------------------------------------------------------------------------------

void adc_channels_init(void)
{

    NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
    NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) |
                      (ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |
                      (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) |
                      (ADC_CONFIG_PSEL_AnalogInput0 << ADC_CONFIG_PSEL_Pos) |
                      (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);

}

//------------------------------------------------------------------------------







//-- Utilitarios de advertising


//------------------------------------------------------------------------------
//-- adv_start
//------------------------------------------------------------------------------

void adv_start()
{
    ble.startAdvertising();
}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- adv_stop
//------------------------------------------------------------------------------
//
// Detiene la emisión de advertising
//
//------------------------------------------------------------------------------

void adv_stop()
{
    ble.stopAdvertising();
}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- adv_clear
//------------------------------------------------------------------------------
//
// borra el contenido del paquete de datos
//
//------------------------------------------------------------------------------

void adv_clear()
{
    ble.clearAdvertisingPayload();
}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- adv_stop_and_clear
//------------------------------------------------------------------------------
//
// Detiene la emisión de advertising
// borra el contenido del paquete de datos
//
//------------------------------------------------------------------------------

void adv_stop_and_clear()
{
    ble.stopAdvertising();
    ble.clearAdvertisingPayload();
}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- adv_payload_set4adv
//------------------------------------------------------------------------------
// set del payload para envío de data después de la lectura de ADC
//------------------------------------------------------------------------------

void adv_payload_set4adv(void)
{
    //-- Company Id
    payload[0]      = MSB_16(BLUCORE_COMPANY_ID);
    payload[1]      = LSB_16(BLUCORE_COMPANY_ID);
    //-- Node Type
    payload[2]      = BLUCORE_BLUNODE_TYPE_01;
    //-- Counter
    payload[3]      = MSB_16(adv_count);
    payload[4]      = LSB_16(adv_count);
    // ADC Channel 1
    payload[5]      = MSB_16(adc_values[0]);
    payload[6]      = LSB_16(adc_values[0]);
    // ADC Channel 2
    payload[7]      = MSB_16(adc_values[1]);
    payload[8]      = LSB_16(adc_values[1]);
    // ADC Channel 3
    payload[9]      = MSB_16(adc_values[2]),
                      payload[10]     = LSB_16(adc_values[2]);
    // ADC Channel 4
    payload[11]     = MSB_16(adc_values[3]),
                      payload[12]     = LSB_16(adc_values[3]);
    // 2 bytes spare
    payload[13]     = 0xFF;
    payload[14]     = LSB_16(btn1_press_count);
    // SOC Temperature
    payload[15]     = soc_temp; //((uint8_t) (( soc_temp & 0x000000FF) & 0xFF ));


    //adv_stop();
    //adv_clear();
    adv_stop_and_clear();

    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));

    ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, payload, sizeof(payload));

    // Set advertising interval

    ble.setAdvertisingInterval(adv_time_interval);

    //ble.startAdvertising();
}

//------------------------------------------------------------------------------






//-- Obtiene resultados de medición de los canales análogos


//------------------------------------------------------------------------------
//-- lectura de valor canal ADC (1...8)
//------------------------------------------------------------------------------

uint16_t adc_channel_read(int adcChannel)
{
    uint16_t result = 0;

    if (adcChannel > 0 && adcChannel < 9) {

        NRF_ADC->CONFIG   &= ~ADC_CONFIG_PSEL_Msk;

        switch (adcChannel) {
            case 1:
                NRF_ADC->CONFIG   |= ADC_CONFIG_PSEL_AnalogInput0 << ADC_CONFIG_PSEL_Pos;
                break;
            case 2:
                NRF_ADC->CONFIG   |= ADC_CONFIG_PSEL_AnalogInput1 << ADC_CONFIG_PSEL_Pos;
                break;
            case 3:
                NRF_ADC->CONFIG   |= ADC_CONFIG_PSEL_AnalogInput2 << ADC_CONFIG_PSEL_Pos;
                break;
            case 4:
                NRF_ADC->CONFIG   |= ADC_CONFIG_PSEL_AnalogInput3 << ADC_CONFIG_PSEL_Pos;
                break;
            case 5:
                NRF_ADC->CONFIG   |= ADC_CONFIG_PSEL_AnalogInput4 << ADC_CONFIG_PSEL_Pos;
                break;
            case 6:
                NRF_ADC->CONFIG   |= ADC_CONFIG_PSEL_AnalogInput5 << ADC_CONFIG_PSEL_Pos;
                break;
            case 7:
                NRF_ADC->CONFIG   |= ADC_CONFIG_PSEL_AnalogInput6 << ADC_CONFIG_PSEL_Pos;
                break;
            case 8:
                NRF_ADC->CONFIG   |= ADC_CONFIG_PSEL_AnalogInput7 << ADC_CONFIG_PSEL_Pos;
                break;

            default:
                break;
        }

        NRF_ADC->TASKS_START = 1;

        while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) { }

        result = (uint16_t) ( NRF_ADC -> RESULT & 0x0000FFFF );

    }

    return (result);

}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- Lectura de temperatura interna del CPU
//------------------------------------------------------------------------------

uint8_t soc_temperature_read(void)
{
    uint8_t result = 0;
    static uint32_t temp;
    NRF_TEMP->TASKS_START = 1;
    while (NRF_TEMP->EVENTS_DATARDY == 0) {}
    NRF_TEMP->EVENTS_DATARDY = 0;
    temp = NRF_TEMP->TEMP ;
    result = (uint8_t) (( temp & 0x000000FF) & 0xFF );
    NRF_TEMP->TASKS_STOP = 1;

    return (result);

}

//------------------------------------------------------------------------------





//------------------------------------------------------------------------------
//-- Lectura de todos los canales ADC
//------------------------------------------------------------------------------

void adc_channels_read(void)
{
    // Señal de activación de alimentación del circuito de medición
    out_adc_enabled = OUT_ON;

    // Espera de 100 ms
    wait_ms(100);

    // Lectura en serie de los canales ADC

    if(!isConnected) {
        for (int i = 0; i < adc_channel_count; i++) {
            adc_values[i] = adc_channel_read(adc_channels[i]);
        }

        soc_temp = soc_temperature_read();
    }

    // Desactivación de la señal de alimentación del circuito de medición
    out_adc_enabled = OUT_OFF;

}

//------------------------------------------------------------------------------






//------------------------------------------------------------------------------
//-- Funciones para PinDetect
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//-- pin_key_pressed
//------------------------------------------------------------------------------
// Agregdado en v3
/*
void pin_key_pressed()
{
    /////DEBUG                                                                  // Flash de LED4 para indicar la detección de pulsar el botón 1
    led4 = 0;
    wait_ms(100);
    led4 = 1;
    /////
}
*/
//------------------------------------------------------------------------------


















//-- Procesos de base de tiempo y reacción a eventos


//------------------------------------------------------------------------------
//-- Funciones ejecutadas en base a eventos
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//-- button1_pressed
//------------------------------------------------------------------------------
//
// Esta función se ejecuta cuando se pulsa el botón 1
//
//------------------------------------------------------------------------------

void button1_pressed()
{
    // Desactiva los procesos

    adv_stop();

    t1.detach();
    t2.detach();

    btn1_press_count++;                                                         // Conteo de cuantas veces se ha pulsado el botón

    btn1_press.disable_irq();                                                   // Deshabilita el monitoreo del evento de botón
    btn1_pressed_flag = true;                                                   // Marca de botón pulsado

    /////DEBUG                                                                  // Flash de LED4 para indicar la detección de pulsar el botón 1
    led4 = OUT_ON;
    out_activity_status = OUT_ON;
    wait_ms(500);
    led4 = OUT_OFF;
    out_activity_status = OUT_OFF;
    wait_ms(500);
    out_activity_status = OUT_ON;
    wait_ms(500);
    led4 = OUT_OFF;
    out_activity_status = OUT_OFF;
    /////*/

    btn1_timer.attach(btn1_event_monitor, 1);                                          // Inicia temporizador para evaluar si el botón sigue pulsado después de 3 segundos


}

//------------------------------------------------------------------------------



//------------------------------------------------------------------------------
//-- Funciones ejecutadas en base de tiempo
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//-- T0: Advertising inicial (Agregado en v3)
//------------------------------------------------------------------------------

void adv_run_first_time()
{
    // Not implemented!!!
}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- T1: Time Monitor Function
//------------------------------------------------------------------------------
// Se ejecuta cada lapso de tiempo t1
//------------------------------------------------------------------------------

void time_monitor()
{
    time_monitor_count++;

    //led1 = OUT_ON;
    out_activity_status = OUT_ON;
    wait_ms(100);
    //led1 = OUT_OFF;
    out_activity_status = OUT_OFF;

    if (time_monitor_count > time_monitor_max_count) {
        /*
        // lectura del valor de los canales ADC
        adc_channels_read();
        // en esta versión se actualiza la data de "payload" del advertising
        // to-do: implementar lógica de comparación con valores anteriores
        //adv_stop_and_clear();                 // Detiene y borra "payload"
        adv_count++;                // incrementa el contador de paquetes de datos
        adv_payload_set4adv();
        monitor_stop_flag = true;   // flag de detención del proceso de time_monitor
        adv_run_first_time_flag = true;
        //adv_start();                // Inicia advertising con los datos cargados
        */
        time_monitor_count = 0;                                                 // Reset del contador de ciclos de ventana de monitoreo
        start_advertising_helper();                                             // Función que inicializa los parámetros para ejecutar un advertising
    }
}

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//-- start_advertising_helper
//------------------------------------------------------------------------------

void start_advertising_helper()
{
    // lectura del valor de los canales ADC
    adc_channels_read();
    // en esta versión se actualiza la data de "payload" del advertising
    // to-do: implementar lógica de comparación con valores anteriores
    adv_count++;                                                                // incrementa el contador de paquetes de datos
    adv_payload_set4adv();
    monitor_stop_flag = true;                                                   // flag de detención del proceso de time_monitor
    adv_run_first_time_flag = true;                                             // flag que permite iniciar el advertising desde la rutina de adv_run()
}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- T2: Advertising Run Function
//------------------------------------------------------------------------------
// Se ejecuta cada lapso de tiempo t2
//------------------------------------------------------------------------------

void adv_run()
{
    //led2 = OUT_ON;
    out_activity_status = OUT_ON;
    wait_ms(100);
    //led2 = OUT_OFF;
    out_activity_status = OUT_OFF;

    led4 = OUT_ON;
    wait_ms(100);
    led4 = OUT_OFF;



    if (adv_run_first_time_flag) {
        // reset de la variable de control

        adv_run_first_time_flag = false;

        // inicia el advertising
        // pre-req: Se ha cargado el payload antes de activar la función

        adv_start();



    }
    /**/

    adv_run_count++;

    if (adv_run_count > adv_time_periods) {
        // detención del proceso de envio de advertising

        //adv_stop_and_clear();
        adv_stop();                                                             // detención de advertising
        adv_stop_flag = true;                                                   // indicación de detención del proceso de advertising
    }
}

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//-- btn1_event_monitor
//------------------------------------------------------------------------------
// Función que permite realizar el monitoreo del estado del botón 1
//------------------------------------------------------------------------------

void btn1_event_monitor()
{

    ///// DEBUG
    //led3 = 0;
    out_activity_status = OUT_ON;
    wait_ms(100);
    //led3 = 1;
    out_activity_status = OUT_OFF;
    /////

    btn1_pressed_count++;

    ///// DEBUG
    //led4 = btn1.read();
    /////

    if (btn1_pressed_count > app_btn1_pressed_time) {
        if (btn1.read() == 0) {
            btn1_held_flag = true;
        }
        btn1_monitor_stop_flag = true;
    }

}

/*
void btn1_debug()
{
    btn1_pressed_count++;
    led3 = btn1.read();
}
*/
//------------------------------------------------------------------------------





//:Fin de funciones y procesos                                                      ------------------------------------------------------------------------------
//------------------------------------------------------------------------------    <<<<------  FIN DE IMPLEMENTACION DE FUNCIONES Y PROCESOS







































































//------------------------------------------------------------------------------    ------>>>>  INICIO DE LA APLICACION
//: Inicio de la aplicación                                                         ------------------------------------------------------------------------------
//------>>>





//------------------------------------------------------------------------------
//-- Main: BluNode v4 (1.4.0)
//------------------------------------------------------------------------------

int main(void)
{
    //-- Inicialización de la aplicación

    app_init();

    // Inicia el temporizador 0 (Advertising inicial)

    t0_start_cmd = true;



    // t0.attach(adv_first_time, 10);

    // Inicia el conteo de tiempo de espera, hay que ajustar el tiempo de
    // revisión de condiciones para esperar el tiempo definido antes del adv


    t1.attach(time_monitor, app_time_monitor_interval);



    // Activa UART

    UARTService uartService(ble);
    uartServicePtr = &uartService;

    ble.onDisconnection(disconnectionCallback);
    ble.onDataWritten(onDataWritten);
    ble.onConnection(connectionCallback);





    // Active eventos del botón

    //button1Press.fall(&advActiveFunc);

    btn1_press.fall(&button1_pressed);

    //testTimer.attach(btn1_event_monitor,1);

    // Funciones v3 para detección de botón 1 (P0.17)

    //pin.mode( PullDown );
    //pin.attach_asserted(&pin_key_pressed);
    //pin.setSampleFrequency(10000);

    ///// DEBUG
    out_adc_enabled = 0;
    wait_ms(500);
    out_adc_enabled = 1;
    wait_ms(500);
    out_adc_enabled = 0;
    wait_ms(500);
    out_adc_enabled = 1;
    wait_ms(500);
    out_adc_enabled = 0;
    wait_ms(500);
    out_adc_enabled = 1;
    wait_ms(500);
    out_adc_enabled = 0;
    wait_ms(500);
    out_adc_enabled = 1;
    wait_ms(500);
    out_adc_enabled = 0;
    wait_ms(500);
    out_adc_enabled = 1;
    wait_ms(500);
    /////

    /* Infinite Loop*/

    while(true) {


        //: t0 Control
        if (t0_start_cmd) {
            t0_start_cmd = false;
            t0_counter = 0;
            t0.attach(t0_func, t0_timer_interval);
        }

        if (t0_stop_cmd) {
            t0_stop_cmd = false;
            t0.detach();
            t0_running = false;

            t1_start_cmd = true;
        }







        // Espera por un evento del stack BLE (Temporizadores, botones, etc...)

        ble.waitForEvent();





        // Control de proceso time_monitor






        if (monitor_stop_flag) {
            // detiene ejecución del proceso "time_monitor"
            t1.detach();
            // reset de variables de control
            monitor_stop_flag = false;

            // Se traslada el "reset" del contador a la función de monitoreo
            // para poder detener manualmente sin perder la cuenta
            //time_monitor_count = 0;

            // Solo para debug
            //led3 = !led3;
            // activa proceso de advertising

            t2.attach(adv_run, app_adv_run_interval);

            out_adc_enabled = OUT_ON;
            wait_ms(500);
            out_adc_enabled = OUT_OFF;


        }

        // Control de proceso advertising

        if (adv_stop_flag) {
            // detiene ejecución del proceso "adv_run"
            t2.detach();                                                        // detiene el timer del proceso de advertising
            // reset de variables de control
            adv_stop_flag = false;
            adv_run_count = 0;
            // solo para debug
            //led4 = !led4;
            // activa proceso de time_monitor
            t1.attach(time_monitor, app_time_monitor_interval);                 // inicia el timer del proceso de espera
        }

        // Control de proceso de monitoreo de botón 1

        if (btn1_monitor_stop_flag) {
            // detiene jecución del proceso btn1_pressed_time
            btn1_timer.detach();
            // reset de variables de control
            btn1_monitor_stop_flag = false;
            btn1_pressed_count = 0;

            // Detiene cualquier otro proceso
            // Se traslada a la función que detecta el botón
            // De todas maneras se interrumpe la comunicación

            //t1.detach();
            //t2.detach();

            if (btn1_pressed_flag && !btn1_held_flag) {
                /* Implementar one-touch button */
                led3 = OUT_ON;
                led4 = OUT_OFF;

                wait_ms(100);
                adv_run_count = 0;
                adv_stop_flag = false;
                start_advertising_helper();

                led3 = OUT_OFF;
                led4 = OUT_OFF;
            }

            if (btn1_pressed_flag && btn1_held_flag) {
                /* Implementar held-touch button */
                led4 = OUT_ON;
                led3 = OUT_OFF;

                wait_ms(100);
                adv_run_count = 0;
                adv_stop_flag = false;
                start_advertising_helper();

                led3 = OUT_OFF;
                led4 = OUT_OFF;
            }

            btn1_pressed_flag = false;
            btn1_held_flag = false;

            btn1_press.enable_irq();                                            // Activa la detección de botón
        }




    }
}

//------------------------------------------------------------------------------


//<<<------
//:Fin de Aplicación                                                                ------------------------------------------------------------------------------
//------------------------------------------------------------------------------    <<<<------  FIN DE LA APLICACION




