v1.19 Release

Dependencies:   nRF51822

Source/main.cpp

Committer:
sgetz7908
Date:
2019-03-25
Revision:
25:42163d650266
Parent:
24:761c30334cf4
Child:
26:a577c4b69fe0

File content as of revision 25:42163d650266:

//**********************************************************************
//
// SmartCap2 Main
//
// SPG 2/22/2019
//
// Copyright (c) 2019 Polygenesis
//
//**********************************************************************
/// @file main.cpp

#include <events/mbed_events.h>
#include <mbed.h>
#include <ctype.h>
#include "main.h"
#include "hw.h"
#include "ble/BLE.h"
#include "ble/Gap.h"
#include "BLE_Stuff.h"
#include "ble/services/UARTService.h"
#include "infoService.h"
#include "log.h"
#include "nrf_soc.h"
#include "mem.h"

void process_state(void);
void start_periodic_tick(uint32_t sec);

EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);

#if TEST_ON_NRF51_DK==0
    // real board
    //int reg_mode = 1;
    InterruptIn is_package_open(LIGHT_SENSE, PullNone); // will be pulled hi when package_is_open (only if package_open_sense_enable = 1)
    DigitalOut package_open_sense_enable(LIGHT_SENSE_ENABLE, 0);
    
    DigitalOut cap_sense_led(CAP_SENSE_LED, 0);
    DigitalOut vdd_enable(VDD_ENABLE, 0);
    
    DigitalOut led(LED, 0); // LED for debugging purposes
    
    #if UART_DEBUGGING
        #define debug(STR) BLE_UART_xmit(STR); BLE_UART_xmit("\n");
    #else
        #define debug(...) 
    #endif
#else
    // simulate on nRF51-DK
    DigitalIn capon(BUTTON1, PullUp);
    //DigitalIn reg_mode(BUTTON3, PullUp);
    InterruptIn is_package_open(BUTTON2, PullUp); // will be pulled hi when package_is_open
    DigitalOut package_open_sense_enable(LED3, 0);
    
    DigitalOut cap_sense_led(LED2, 0);
    DigitalOut vdd_enable(LED4, 0);
    
    DigitalOut led(LED1, 0); // LED for debugging purposes
    #if UART_DEBUGGING
        Serial pc(USBTX, USBRX); // tx, rx
        #define debug(STR) pc.printf(STR)
    #else
        #define debug(...) 
    #endif
#endif

LowPowerTicker periodic_ticker; // this handle the RTC

float tick_rate = FAST_TICK_SEC;

bool package_open_detected = false;
bool is_cap_off = false; // 0=cap on, 1=cap off
uint32_t cap_off_time;

uint16_t off_reading;
uint16_t on_reading;

typedef  enum {
    INIT,
    POST, 
    TEST_MODE, 
    SHIP_MODE_WAIT_DARK,
    SHIP_MODE_WAIT_LIGHT,
    SHIP_MODE_CHECK_CAP,
    SHIP_MODE_WAIT_CAP_OFF,
    IN_USE_SETUP,
    WAIT_CAP_OFF, 
    WAIT_CAP_ON,
    OTHER
} state_t;

state_t state = INIT;

/// Light detected interrupt
void light_interrupt(void)
{ // dark to light transition
    package_open_detected = true;
    start_periodic_tick(FAST_TICK_SEC);
}
    
/// Test to see if Cap is off or on
void test_cap(void)
{
#if TEST_ON_NRF51_DK == 0   
    vdd_enable = 1; // enable analog power
    wait(0.00075);
    off_reading = adc_read(ADC_CHAN_CAP_SENSE,2);
    cap_sense_led = 1; // enable led
    wait(0.00075);
    on_reading = adc_read(ADC_CHAN_CAP_SENSE,2);
    // turn everything off
    cap_sense_led = 0;
    vdd_enable = 0;
    
    if(on_reading > off_reading+CAP_THRESHOLD)
#else 
    if(capon)
#endif 
    {
        is_cap_off = 0;
        #if ENABLE_LED        
            led = 0;
        #endif        
    }
    else
    {
        is_cap_off = 1;
        #if ENABLE_LED        
            led = 1;
        #endif        
    }
}

void periodic_tick_task(void)
{
    test_cap();
    process_state();
}

/// this interrupt is run every PERIODIC_TICK_SEC seconds
void periodic_tick()
{
    update_rtc(tick_rate); // keep rtc updated
    eventQueue.call(periodic_tick_task); // starts as non-interrupt task so we can use wait();
}

void start_periodic_tick(uint32_t sec)
{
    tick_rate = sec;
    periodic_ticker.detach();
    periodic_ticker.attach(&periodic_tick ,sec);
}

void stop_periodic_tick(void)
{
    periodic_ticker.detach();
}

/// call here to flash the LED n times.
// n=0 to flash forever
void flash_led(int n, float sec)
{
    if(n==0)
    { // flash forever
        while(1)
        {
            led = 1;
            wait(sec);
            led = 0;
            wait(sec);
        }
    }
    else
    { // flash n times
        while(n--)
        {
            led = 1;
            wait(sec);
            led = 0;
            wait(sec);
        }
    }
}


state_t last_state = OTHER;

/// Main state machine
/// Called whenever a sensor changes
void process_state(void)
{
    do
    {
        #if UART_DEBUGGING==1    
            if(last_state != state)
            {
                debug(uli2a(state));
                debug("\n");    
            }
        #endif
        last_state = state;
        
        switch(state)
        {
            case INIT:
                log_add(EVENT_POWER, 0, 0, 0); // log event 
                set_radio(true);
                start_periodic_tick(FAST_TICK_SEC);
                #if SKIP_SHIP_MODE
                    state = IN_USE_SETUP;
                #else
                    state = POST;
                #endif
                break;
                
            case POST:
                // check CRC ?
                
                // Check Misc.
                
                //if(error) flash_led(0,0.1); // flash forever to indicate error

                if(NV_TESTING_REQUIRED) 
                {
                    flash_led(1, 1.0);
                    package_open_sense_enable = 1;
                    start_periodic_tick(FAST_TICK_SEC);
                    state = TEST_MODE;
                }
                else 
                {
                    state = IN_USE_SETUP;
                }
               
                break;
                
            case TEST_MODE:
                test_cap();
                led = is_cap_off;
                if(!NV_TESTING_REQUIRED && is_package_open)
                { // testing passed
                    set_radio(false); // already done when NV_TESTING_REQUIRED was cleared.
                    led = 0;
                    state = SHIP_MODE_WAIT_DARK;
                }
                break;
                
            case SHIP_MODE_WAIT_DARK: // Wait for light sensor to see darkness
                flash_led(1,0.1);
                if(!is_package_open)
                { // its dark
                    state = SHIP_MODE_WAIT_LIGHT;
                }
            break;           
            
            case SHIP_MODE_WAIT_LIGHT: 
                // set up and enable the Light Sense Interrupt
                // go to lowest power state
                
                debug("Going SHIP MODE\n");
                is_package_open.disable_irq();
                stop_periodic_tick();
                led = 0;
                package_open_detected = false;
                is_package_open.mode(PullNone);
                is_package_open.rise(&light_interrupt);
                is_package_open.enable_irq();
                state = SHIP_MODE_CHECK_CAP;

            break;
            
            case SHIP_MODE_CHECK_CAP:
                
                if(package_open_detected)
                {
                    debug("Awake\n");
                    flash_led(10,0.25);
                    test_cap();
                    if(is_cap_off)
                    {
                        state = SHIP_MODE_WAIT_DARK;
                    }
                    else
                    {
                        state = SHIP_MODE_WAIT_CAP_OFF;
                    }
                }
                break;
                
            case SHIP_MODE_WAIT_CAP_OFF:
                if(!is_package_open) 
                {
                    state = SHIP_MODE_WAIT_LIGHT;
                }
                else
                { 
                    test_cap();
                    if(is_cap_off)
                    {
                        package_open_sense_enable = 0;
                        log_add(EVENT_WAKE_FROM_SHIP, 0, 0, 0);
                        state = IN_USE_SETUP;
                    }
                }
                break;
                
            case IN_USE_SETUP:
                flash_led(3, .25);
                start_periodic_tick(PERIODIC_TICK_SEC);
                debug("In Use\n");             
                state = WAIT_CAP_OFF;
            break;
            
            case WAIT_CAP_OFF: // cap is on, waiting for cap to be removed
            if(is_cap_off)
            { // cap just taken off   
                // save cap off time
                cap_off_time = read_clock();
                debug("Cap Off \n");            
                state = WAIT_CAP_ON;
            }
    
            break;
            
            case WAIT_CAP_ON: // cap currently off, waiting for cap to be put on
            
            if(!is_cap_off)
            { // cap just put on  
                // log time cap was off
                uint32_t cap_off_dur = read_clock()-cap_off_time;
                if(cap_off_dur>65535) cap_off_dur = 65535;
                log_add(EVENT_CAP_ON, cap_off_dur & 0xff, (cap_off_dur >> 8)&0xff, 0); // log event
                set_radio(true);
                state = WAIT_CAP_OFF;
            }
            break;
            
            default: // illegal state
                state = INIT;
            break;
        }
    } while(state != last_state);
}

/// process commands sent to the SmartCap over Bluetooth UART
void process_cmd(char * cmd)
{
    switch(tolower(cmd[0])) {
        case 'r': // Get records
            log_show();
            //batt_voltage = read_battery_voltage();
            //updateBattValue(batt_voltage); 
            break;

        case 's': // status
            switch(tolower(cmd[1])) {
                case 0: // old, check battery voltage
                    batt_voltage = read_battery_voltage();
                    BLE_UART_xmit("Bat=");
                    BLE_UART_xmit(batt_voltage);
                    BLE_UART_xmit("\n");
                    break;
                    
                case 'x': // checksum
                    BLE_UART_xmit("sx=");
                    BLE_UART_xmit(0);
                    BLE_UART_xmit("\n");
                    break;
                              
                case 'c': // cap sensor analog readings
                    BLE_UART_xmit("sc=");
                    test_cap();
                    BLE_UART_xmit(on_reading);
                    BLE_UART_xmit(",");
                    BLE_UART_xmit(off_reading);
                    BLE_UART_xmit("\n");
                    break;
                    
                case 's': // sensors as binary, with bits '00000tcp', t=(1=TESTING REQUIRED), c=(1 is cap off), p=(1 is light sensed)
                    //int val = 0;
                    BLE_UART_xmit("ss=00000");
                    if(NV_TESTING_REQUIRED) BLE_UART_xmit("1"); else BLE_UART_xmit("0");
                    int save = package_open_sense_enable;
                    package_open_sense_enable = 1;
                    test_cap();
                    if(is_cap_off) BLE_UART_xmit("1"); else BLE_UART_xmit("0");
                    if(is_package_open) BLE_UART_xmit("1"); else BLE_UART_xmit("0");
                    package_open_sense_enable = save;
                    BLE_UART_xmit("\n");
                    break;
            }
            break;
        case 'p': // test passed
            if(tolower(cmd[1])=='z')
            {
                log_add(EVENT_TEST_PASS, 0, 0, 0);
                nv_clear(NV_TESTING_REQUIRED_ADDR);
            }
            #if 0
            else if(tolower(cmd[1])=='e')
            {
                set_radio(false);
                wait(1.0);
                log_erase();
            }
            #endif
            break;
            
        case 't': // get time
            BLE_UART_xmit(read_clock());
            BLE_UART_xmit("\n");
            break;

        case 'c': // set time
            {
                int i = 1;
                uint32_t num = 0;
    
                while(cmd[i]>='0' && cmd[i]<='9') {
                    num = num*10 + cmd[i++]-'0';
                }
    
                if(i>1) {
                    set_time_offset(num);
                    BLE_UART_xmit("*Time Set\n");
                }
            }
            break;
             
        case 'v': // version
            BLE_UART_xmit("v=");
            BLE_UART_xmit(FW_VERSION);
            BLE_UART_xmit("\n");
            break;
                 
        default:
            BLE_UART_xmit("S=Status\n");
            break;
    }
    cmd[0] = 0;
}

//*****************************************************************************

int main(void)
{                                                 
    // blink LED to indicate power applied
    //flash_led(1,1.0);

    if(Init_BLE_Stuff()) // init and start advertising    
    {
        flash_led(0, 0.05); // indicate a ble init error
    }
    
    eventQueue.call(process_state);

    eventQueue.dispatch_forever(); // run all tasks in the event queue (non-interrupt routines)
    return 0;
}