Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: nRF51822
Source/main.cpp
- Committer:
- sgetz7908
- Date:
- 2020-03-20
- Revision:
- 42:213f9b0cabe4
- Parent:
- 41:80f618bb53a4
- Child:
- 46:b85be1ccf179
File content as of revision 42:213f9b0cabe4:
//**********************************************************************
//
// 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"
#include "CCITTcrc16.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 log_enable = true; // turn off event logging when false (engineering function) – DEW
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,
EOL_WAIT_CAP_OFF,
EOL_WAIT_CAP_ON,
EOL_WAIT_LIGHT,
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);
wait(0.0035); // increase wait time to allow full settling - FTD 11/21/2019
off_reading = adc_read(ADC_CHAN_CAP_SENSE,2);
cap_sense_led = 1; // enable led
wait(0.00075);
//wait(0.001); // increase wait time to allow full settling - FTD 11/21/2019
on_reading = adc_read(ADC_CHAN_CAP_SENSE,2);
// turn everything off
cap_sense_led = 0;
vdd_enable = 0;
if(off_reading<CAP_MAX_OFF_READING)
{ // reading only valid if above is true
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;
int last_cap;
/// 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
start_periodic_tick(FAST_TICK_SEC);
#if SKIP_SHIP_MODE
// package_open_sense_enable = 1;
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);
last_cap = 99;
set_radio(true, 0); // advertise forever until stopped
state = TEST_MODE;
}
else
{
state = IN_USE_SETUP;
}
break;
case TEST_MODE:
test_cap();
led = is_cap_off;
if(last_cap != is_cap_off)
{
last_cap = is_cap_off;
BLE_UART_xmit("*Cap ");
if(last_cap) BLE_UART_xmit("Off"); else BLE_UART_xmit("On");
BLE_UART_xmit("\n");
}
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(PullDown);
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(3,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;
set_rtc(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");
if(NV_NOT_IN_USE) nv_clear(NV_NOT_IN_USE_ADDR);
state = WAIT_CAP_OFF;
break;
case WAIT_CAP_OFF: // cap is on, waiting for cap to be removed
if(read_clock()>((uint32_t)EOL_TIMEOUT_DAYS*24*60*60))
{ // EOL detected due to maximum time
if(NV_NOT_EOL) nv_clear(NV_NOT_EOL_ADDR);
}
if(!NV_NOT_EOL)
{ // EOL flagged
if(log_code_count(EVENT_EOL)==0) log_add(EVENT_EOL, 0, 0, 0); // log event
start_periodic_tick(EOL_TICK_SEC); // just tick less often
state = EOL_WAIT_CAP_OFF;
}
else 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
if(log_code_count(EVENT_CAP_ON)>= EOL_MAX_USES)
{ // EOL detected due to maximum uses
if(NV_NOT_EOL) nv_clear(NV_NOT_EOL_ADDR);
}
set_radio(true);
state = WAIT_CAP_OFF;
}
break;
case EOL_WAIT_CAP_OFF: // Cap is on
if(is_cap_off)
{ // cap just taken off
debug("EOL Cap Off \n");
state = EOL_WAIT_CAP_ON;
}
//else if(!is_package_open)
//{ // its dark
// start_periodic_tick(EOL_TICK_SEC); // just tick less often
// state = EOL_WAIT_LIGHT;
//}
break;
case EOL_WAIT_CAP_ON: // Cap is off
if(!is_cap_off)
{ // cap just put on
debug("EOL Cap On \n");
set_radio(true);
state = EOL_WAIT_CAP_OFF;
}
break;
/*
case EOL_WAIT_LIGHT: // EOL and its dark, save power
// set up and enable the Light Sense Interrupt
// go to lowest power state
debug("Going to EOL dark mode\n");
led = 0;
if(is_package_open)
{
start_periodic_tick(PERIODIC_TICK_SEC);
state = EOL_WAIT_CAP_OFF;
}
break;
*/
default: // illegal state
state = INIT;
break;
}
} while(state != last_state);
}
void dataWasRead(void)
{
flash_led(1, 0.04);
}
/// 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 'd': // disable event logging with cap sensor toggle - DEW
log_enable = false;
BLE_UART_xmit("Log DISABLED\n");
break;
case 'e': // (default) enable event logging with cap sensor toggle - DEW
log_enable = true;
BLE_UART_xmit("Log ENABLED\n");
break;
case 'f': // show current state of logging enable function - DEW
if(log_enable) BLE_UART_xmit("Log ENABLED\n");
else BLE_UART_xmit("Log DISABLED\n");
break;
case 0: // old, check battery voltage
case 'b': // new, 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 'm': // CRC of Softdevice and App (Not including NV storage for logs and flags)
{
uint16_t crc = crc16((const unsigned char*)CRC_START_ADDR, (uint32_t)(CRC_END_ADDR - CRC_START_ADDR + 1) );
BLE_UART_xmit("sm=");
BLE_UART_xmit(char2hex(crc, 4));
BLE_UART_xmit("\n");
}
break;
case 's': // sensors as binary, with bits '000eutcp', e=(0=EOL), u=(0=in use), t=(1=TESTING REQUIRED), c=(1 is cap off), p=(1 is light sensed)
//int val = 0;
BLE_UART_xmit("*ss=000");
if(NV_NOT_EOL) BLE_UART_xmit("1"); else BLE_UART_xmit("0");
if(NV_NOT_IN_USE) BLE_UART_xmit("1"); else BLE_UART_xmit("0");
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");
wait(LIGHT_SENSE_PWRON_DELAY);
if(is_package_open) BLE_UART_xmit("1"); else BLE_UART_xmit("0");
package_open_sense_enable = save;
BLE_UART_xmit("\n");
break;
case 'l': // read light sensor analog reading via ADC. Circuit enabled before doing reading.
BLE_UART_xmit("sl=");
int save2 = package_open_sense_enable;
package_open_sense_enable = 1;
wait(LIGHT_SENSE_PWRON_DELAY);
BLE_UART_xmit(adc_read(ADC_CHAN_LIGHT_SENSE,2));
package_open_sense_enable = save2;
BLE_UART_xmit("\n");
break;
}
break;
case 'p': // test passed
if(tolower(cmd[1])=='z')
{
log_add(EVENT_TEST_PASS, 0, 0, 0);
if(NV_TESTING_REQUIRED) nv_clear(NV_TESTING_REQUIRED_ADDR);
}
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;
}