Fork to see if I can get working

Dependencies:   BufferedSerial OneWire WinbondSPIFlash libxDot-dev-mbed5-deprecated

Fork of xDotBridge_update_test20180823 by Matt Briggs

xDotBridge/src/main.cpp

Committer:
mbriggs_vortex
Date:
2017-11-21
Revision:
92:1f86edb14cbe
Parent:
91:8196900df6fe
Child:
95:aa9908d459c2

File content as of revision 92:1f86edb14cbe:

#include "mbed.h"
#include <math.h>
#include "config.h"
#include "dot_util.h"
#include "RadioEvent.h"
#include "BufferedSerial.h"
#include "WinbondSPIFlash.h"
#include "UserInterface.h"
//#include <xdot_low_power.h>
#include "ChannelPlans.h"
#include "mDot.h"
#include "MyLog.h"
#include "SimpleRxSeqLog.h"

#include "BaseboardIO.h"
#include "CommProtocolPeerBrute.h"
#include "SerialTermMgr.h"

#define RX_SEQ_LOG 1

const float BridgeVersion = 1.98; // Bumped 2017/11/TODO

// 232 Pins
const PinName SER_TERM_TX = UART_TX;
const PinName SER_TERM_RX = UART_RX;

#ifndef __TEST__ // Exclude code for tests
Serial pc(USBTX, USBRX);
BufferedSerial *outPc;
InterruptIn uart1RxIntIn (SER_TERM_RX);

mDot* dot = NULL; // Used by dot-utils

volatile bool uartRxFlag;
volatile bool ccIntFlag;
volatile bool tamperIntFlag;
volatile bool pairBtnIntFlag;
void uart1RxCallback () {
    uartRxFlag = true;
}
void ccInIntCallback () {
    ccIntFlag = true;
}
void tamperIntCallback () {
    tamperIntFlag = true;
}
void pairBtnIntCallback () {
    pairBtnIntFlag = true;
}

int main() {
    CommProtocolPeerBrute *protocol = new CommProtocolPeerBrute();
    BaseboardIO *bbio = new BaseboardIO();
    WinbondSPIFlash *flash = new WinbondSPIFlash(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_NSS);
    SerialTermMgr serialTermMgr(bbio, flash, BridgeVersion);

    pc.baud(115200);
    CmdResult result;
    uartRxFlag = false;
    ccIntFlag = false;
    tamperIntFlag = false;
    pairBtnIntFlag = false;

    RadioEvent events;  // Custom event handler for automatically displaying RX data
#if RX_SEQ_LOG
    SimpleRxSeqLog rxSeqLog(0x0000);
    rxSeqLog.read();
#endif

    mts::MTSLog::setLogLevel(mts::MTSLog::TRACE_LEVEL);
    MyLog::setLogLevel(MyLog::DEBUG_LEVEL);

	// use US915 plan
    lora::ChannelPlan* plan = new lora::ChannelPlan_US915();
    // use EU868 plan
    // lora::ChannelPlan* plan = new lora::ChannelPlan_EU868();
    assert(plan);
    
    dot = mDot::getInstance(plan);

    // make sure library logging is turned on
    dot->setLogLevel(mts::MTSLog::WARNING_LEVEL);

    myLogInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION);
    myLogInfo("libxDot-mbed5 library ID: %s", dot->getId().c_str());
    myLogInfo("Vortex Wireless Bridge SW Version %0.2f", BridgeVersion);

    // attach the custom events handler
    dot->setEvents(&events);  // Little bonus event debug information

    // Finish radio init
    myLogInfo("= Protocol Init Starting                     =\r\n");
    protocol->init();
    if (result == cmdSuccess) {
        myLogInfo("= Protocol Init Finished Successfully    =\r\n");
    }
    else {
        myLogInfo("= Protocol Init Finished with Error      =\r\n");
    }
    protocol->printDotConfig();

    dot->setWakeMode(mDot::RTC_ALARM_OR_INTERRUPT);
    dot->setWakePin(GPIO0);
//    dot->setWakePin(UART_RX);

    display_config();  // Print configuration for now

    // display configuration
//    display_config();

    myLogInfo("= Baseboard Init Starting                     =\r\n");
    result = bbio->init();
    if (result == cmdSuccess) {
        myLogInfo("= Baseboard Init Finished Successfully    =\r\n");
    }
    else {
        myLogInfo("= Baseboard Init Finished with Error      =\r\n");
    }
    LedPatterns ledPatterns(bbio);

    uart1RxIntIn.rise(&uart1RxCallback);  // Rising does appear to work better than falling edge
    uart1RxIntIn.enable_irq();
    Callback<void()> ccInIntObj (&ccInIntCallback);
//    Callback<void()> tamperIntObj (&tamperIntCallback);
    Callback<void()> pairBtnIntObj (&pairBtnIntCallback);

    bbio->sampleUserSwitches();
    bbio->relayNormal(); // Always force relay in known state
    bbio->regCCInInt(ccInIntObj);
//    bbio->regTamperInt(tamperIntObj);
    bbio->regPairBtnInt(pairBtnIntObj);

    if (bbio->isTx()) {
        protocol->setTx(true);
    }
    else { // RX
        protocol->setTx(false);
    }

    // Start flash powered down
    flash->powerDown();

    unsigned int loopCnt = 0; // Just a quick temp variable to keep track of loopNums
    bool prevCCNormallyOpen;
    PairBtnState pairBtnState;
    uint32_t rxMsgCnt = 0;
    uint32_t maxSeenMsgSeqNum = 0;
    /**
     * Main Loop
     */
    while (true) {
//        myLogInfo("Start of loop time %d", us_ticker_read());
        ledPatterns.turnOff();
		bbio->serialRx(true); // FIXME find a better home
		bbio->serialTx(false); // FIXME only turn on during TX

        // Pair logic and switch sampling
        if (pairBtnIntFlag) {
            pairBtnState = PairBtnInterp::read(bbio);

            // Sample IO and update any configuration
            prevCCNormallyOpen = bbio->isCCNO();
            bbio->sampleUserSwitches();
            if (prevCCNormallyOpen != bbio->isCCNO()) { // Only activate the coil if the DIP SW has changed
                bbio->regCCInInt(ccInIntObj);
                bbio->relayNormal();
            }
            if (bbio->isTx()) {
                protocol->setTx(true);
            }
            else { // RX
                protocol->setTx(false);
            }
            if (protocol->isTx()) {
                if (pairBtnState == pairBtnMediumPress) {
                    protocol->configForPairingNetwork();
                    protocol->sendPairReq();
                    myLogInfo("Sent pair request.  Waiting %f secs for accept.", TX_ACCEPT_WAIT_TIME);
                    result = protocol->waitForAccept(TX_ACCEPT_WAIT_TIME);
                    if (result == cmdSuccess) {
                        myLogInfo("Got accept");
                        ledPatterns.turnOff();
                        wait(0.5);
                        ledPatterns.tripleBlink();
                    }
                    else {
                        myLogInfo("Did not receive accept");
                    }
                    protocol->configForSavedNetwork();
                    protocol->printDotConfig();
                    protocol->resetCounters();

                    // Clear test log
                    rxSeqLog.clear();
                    rxSeqLog.save();
                    myLogInfo("NVM Cleared Seq Log");
                }
            }
            if (protocol->isRx()) {
                if (pairBtnState == pairBtnMediumPress) {
                    protocol->configForPairingNetwork();
                    ledPatterns.turnOn();
                    myLogInfo("Waiting for pair request for %f seconds", RX_PAIR_WAIT_TIME);
                    result = protocol->waitForPairing(RX_PAIR_WAIT_TIME);
                    ledPatterns.turnOff();
                    if (result == cmdSuccess) {
                        myLogInfo("Got pair request and responded");
                        ledPatterns.tripleBlink();
                    }
                    else if (result == cmdTimeout) {
                        myLogInfo("Did not receive request");
                    }
                    else {
                        myLogInfo("Unknown pair error");
                    }
                    protocol->configForSavedNetwork();
                    protocol->printDotConfig();
                    protocol->resetCounters();

                    // Clear test log
                    rxSeqLog.clear();
                    rxSeqLog.save();
                    myLogInfo("NVM Cleared Seq Log");
                }
                else if (pairBtnState == pairBtnLongPress) {
                    myLogInfo("Clearing pair values and generating new ones.");
                    protocol->clearPair();
                    protocol->printDotConfig();
                    ledPatterns.tenBlinks();
                    protocol->resetCounters();
                }
            }
        }
        else {
            pairBtnState = pairBtnNoPress;
        }
        pairBtnIntFlag = false;

        // Serial Terminal
        if (uartRxFlag) {
            pc.printf("Got RX Int\r\n");
            uart1RxIntIn.disable_irq();
//            pc.printf("Got uart flag!!!\r\n");
            uartRxFlag = false;
            outPc = new BufferedSerial(SER_TERM_TX, SER_TERM_RX);
            outPc->baud(TERM_BAUD);
            serialTermMgr.regSerial(outPc);
            char c;
            if (outPc->readable()) {
                c =  outPc->getc(); // Throw away the first char
                pc.printf("Got %d, %c\r\n", c, c);
            }

            outPc->printf("Starting Terminal...\r\n");
            serialTermMgr.printScreen();
            time_t termLastAction = time(NULL);
            bool quit = false;
            while(!quit && (time(NULL) < (termLastAction + TERM_TIMEOUT))) {
                if (outPc->readable()) {
//                    pc.printf("Got %d\r\n", outPc->getc());
                    quit = serialTermMgr.input();
                    termLastAction = time(NULL);
                }
            }
            if (quit) {
                outPc->printf("Terminal quit resuming operation <press any key to reactivate>...\r\n");
            }
            else {
                outPc->printf("Terminal timeout resuming operation <press any key to reactivate>...\r\n");
            }
            wait(0.01); // Wait for end message to be shifted out
            serialTermMgr.regSerial(NULL);
            delete outPc;
            uart1RxIntIn.enable_irq();
        }
        wait(0.1);

        myLogInfo("Loop #%d. isTX %d, CCFlag %d, CCAlertState %d, TamperFlag %d, PairBtnState %d",
                loopCnt, protocol->isTx(), ccIntFlag, bbio->isCCInAlert(), tamperIntFlag, pairBtnState);
        // Alert code
		if (protocol->isTx()) {
            // TODO add tamper
		    if (ccIntFlag || // If contact closure in
		       bbio->isCCInAlert() || // If closure remains in effect
		       pairBtnState == pairBtnShortPress) {
                ccIntFlag = false;
                ledPatterns.turnOn();

                myLogInfo("Sending msg num: %d.", protocol->getSeqNum());
                protocol->sendAlert(0xBEEF); // TODO use this field to encode the alert type e.g. CCIN vs tamper
                ledPatterns.turnOff();
		    }

            ledPatterns.turnOff();
//            tamperIntFlag = false;
            if (pairBtnIntFlag) {// An Interrupt happened during transmission
                continue; // Go straight to pair handling
            }
            bbio->prepareSleep();
		    if (bbio->isCCInAlert()) { // Still in alert mode
		        // Sleep for 5 seconds to ensure that receiver does not miss a message sequence
                dot->sleep(5, mDot::RTC_ALARM_OR_INTERRUPT, false);  // Go to sleep and check in 5 secs if CCInAlert is asserted
		    }
		    else {
                dot->sleep(0, mDot::INTERRUPT, false);  // Go to sleep until interrupt event
//		        wait(0.5);
		    }
		    bbio->exitSleep();
		}

		if (protocol->isRx()) {
            ccIntFlag = false;
//            tamperIntFlag = false;
//            myLogInfo("Before listen time %d", us_ticker_read());
		    bool msgPending;
		    protocol->listen(msgPending);
		    if (msgPending) {
		        std::vector<uint8_t> txEui;
		        txEui.reserve(8);
		        uint16_t data;
		        uint32_t msgSeqNum;
		        protocol->recvAlert(txEui, data, msgSeqNum);
		        if (msgSeqNum > maxSeenMsgSeqNum)
		            maxSeenMsgSeqNum = msgSeqNum;
		        rxMsgCnt++; // for message
                myLogInfo("Got rxMsgCnt #%d,  with Seqnum: %d", rxMsgCnt, msgSeqNum);
                bbio->relayAlert();
                ledPatterns.turnOn();
                myLogInfo("Holding alert for %f secs", HoldTimeSetting::rotVal2Sec(bbio->rotarySwitch1()));
                // Hold time for alert
                // TODO maybe use sleep instead of wait
                wait(HoldTimeSetting::rotVal2Sec(bbio->rotarySwitch1()));
                ledPatterns.turnOff();
                bbio->relayNormal();
		    }
            if (pairBtnIntFlag) {// An Interrupt happened during reception
                continue; // Go straight to pair handling
            }
            //// TEMP LOGGING
#if RX_SEQ_LOG
            if ((loopCnt % 1000 == 0) &&
                rxMsgCnt > rxSeqLog.rxMsgCount()) {
                rxSeqLog.setLoopCount(loopCnt);
                rxSeqLog.setRxMsgCount(rxMsgCnt);
                rxSeqLog.setMaxSeenMsgSeqNum(maxSeenMsgSeqNum);
                rxSeqLog.save();
                myLogInfo("EEPROM Saved.");
            }
            myLogInfo("NVM Log: Loop Cnt: %d, RxMsgCnt %d, MaxSeenSeqNum %d",
                    rxSeqLog.loopCount(), rxSeqLog.rxMsgCount(), rxSeqLog.maxSeenMsgSeqNum());
#endif

            myLogInfo("Sleeping.  Time %d", us_ticker_read());
            bbio->prepareSleep();
            dot->sleep(2, mDot::RTC_ALARM_OR_INTERRUPT, false);  // Go to sleep until wake button
            bbio->exitSleep();
		}

		protocol->resetCounters();
        myLogInfo("\r\n================================");
        loopCnt++;
    }

    delete protocol;
    delete bbio;
    return 0;
}
#endif