///
/// @file main.c
/// @authors k. headley
/// @date 01 jan 2019

/// PIC firmware main module

/// @sa doxygen-examples.c for more examples of Doxygen markup


/////////////////////////
// Terms of use
/////////////////////////
/*
 Copyright Information

 Copyright 2002-2019 MBARI
 Monterey Bay Aquarium Research Institute, all rights reserved.

 Terms of Use

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version. You can access the GPLv3 license at
 http://www.gnu.org/licenses/gpl-3.0.html

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details
 (http://www.gnu.org/licenses/gpl-3.0.html)

 MBARI provides the documentation and software code "as is", with no warranty,
 express or implied, as to the software, title, non-infringement of third party
 rights, merchantability, or fitness for any particular purpose, the accuracy of
 the code, or the performance or results which you may obtain from its use. You
 assume the entire risk associated with use of the code, and you agree to be
 responsible for the entire cost of repair or servicing of the program with
 which you are using the code.

 In no event shall MBARI be liable for any damages, whether general, special,
 incidental or consequential damages, arising out of your use of the software,
 including, but not limited to, the loss or corruption of your data or damages
 of any kind resulting from use of the software, any prohibited use, or your
 inability to use the software. You agree to defend, indemnify and hold harmless
 MBARI and its officers, directors, and employees against any claim, loss,
 liability or expense, including attorneys' fees, resulting from loss of or
 damage to property or the injury to or death of any person arising out of the
 use of the software.

 The MBARI software is provided without obligation on the part of the
 Monterey Bay Aquarium Research Institute to assist in its use, correction,
 modification, or enhancement.

 MBARI assumes no responsibility or liability for any third party and/or
 commercial software required for the database or applications. Licensee agrees
 to obtain and maintain valid licenses for any additional third party software
 required.
 */

/////////////////////////
// Headers
/////////////////////////
#include <stdint.h>
#include "cwgsys.h"
#include "config.h"
#include "pic24.h"
#include "ioserial.h"
#include "ff.h"
#include "rtc.h"
#include "timers.h"
#include "iodisk.h"
#include "iodigital.h"
#include "ui.h"
#include "script.h"
#include "log.h"
#ifdef WITH_MICRON
#include "micron.h"
#endif
#ifdef WITH_PROTO
#include <string.h>
#include "proto.h"
#endif

/////////////////////////
// Macros
/////////////////////////

// These macros should only be defined for
// application main files rather than general C files

/// @def PRODUCT
/// @brief header software product name
#define PRODUCT "TBD"

/// @def COPYRIGHT
/// @brief header software copyright info
#define COPYRIGHT "Copyright 2002-2019 MBARI Monterey Bay Aquarium Research Institute, all rights reserved."
/// @def NOWARRANTY
/// @brief header software terms of use
#define NOWARRANTY  \
"This program is distributed in the hope that it will be useful,\n"\
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"\
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"\
"GNU General Public License for more details (http://www.gnu.org/licenses/gpl-3.0.html)\n"


/////////////////////////
// Declarations
/////////////////////////

/////////////////////////
// Imports
/////////////////////////

/////////////////////////
// Module Global Variables
/////////////////////////

/////////////////////////
// Function Definitions
/////////////////////////


/// @fn int main(void)
/// @brief Main entry point
/// @return none

int main(void)
{
    // read and reset RCON (reset status register)
    g_rcon=RCON;
    RCON &= ~(0xFFFF);

    // select alternate interrupt vector table
    // (AIVT, mapped to 0x1A00 by MCC, length varies with number of interrupts)
    INTCON2bits.AIVTEN = 1;

    unsigned char input;
    UINT16 cfgVal=0, i=0;
    // File system object
    FATFS fatFs;
    uint32_t next_event=SYS_MIN_SLEEP_MSEC;

    bool load_cfg=false;
    return_code_t rc=ERR_FAILURE;

    // MCC hardware init
    // must initialize clocks, pins, peripherals first
   SYSTEM_Initialize();

    // low-level initialization
    // extend/override MCC init
    pic24_init();

    // system memory resources, etc.
    sys_init();

    //Timers
    tkInit();

    // real-time clock
    rtcReset();

    // serial buffers
    serInit();

    // turn on console, host UARTS
    HOST_XCVR_ON();
    CONS_XCVR_ON();

    serPrintf(SER_CONS,"\r\nserial IO [OK]\r\n");

    // try to mount file system,
    // if found wait for 3 '!'s to see if using default config
#ifdef WITH_SDCARD_DETECT
    serPutString(SER_CONS, "\r\nChecking SDC...\r\n");
    if(doIsCardThere()){
#endif
        //try to mount file system
        cfgVal = f_mount(&fatFs,"",1);
        //if success, look for 3 '!'
        if (FR_OK == cfgVal) {
            sys_set_sdc_ok(true);
            tkDelayMs(3000);
            i=0;
            while (serGetByte(SER_CONS, &input)) {
                if ('!' == input) i++;
            }

            if (3 >= i){
                load_cfg=true;
           } else {
                serPutString(SER_CONS, "Interrupted: using default config\r\n");
           }
        } else{
            serPrintf(SER_CONS, "Unable to mount file system: using default config [%d]\r\n",cfgVal);
        }

#ifdef USE_SDCARD_DETECT
    }else{
        serPutString(SER_CONS, "\r\nNo SD Card present\r\n"
                     "Using default config and logging won't work\r\n");
    }
#endif

    serPrintf(SER_CONS,"sdc mount [%s]\r\n",(sys_sdc_ok()?"OK":"ERR"));

    // init log system
    rc = log_init();
    OUT_CTTY("log_init  [%s]\r\n",(rc==ERR_SUCCESS?"OK":"ERR"));
    if(rc!=ERR_SUCCESS){
        OUT_CTTY("log_init flags[%lX]\r\n",log_err_flags());
    }

    if(sys_sdc_ok()){
        // log boot message (if SDC present)
        log_syslog("sys reboot rcon[x%04X]",g_rcon);
        if(load_cfg){
            //if nothing stopped us, load cfg file
            serPutString(SER_CONS, "Loading config...");
            rc = config_load(NULL);
            OUT_CTTY("cfg load  [%s]\r\n",(rc==ERR_SUCCESS?"OK":"ERR"));
        }else{
            OUT_CTTY("cfg load [N]\r\n");
        }
    }else{
        WMSG("logs uninitialized\r\n");
        WMSG("config not loaded\r\n");
    }

#ifdef WITH_MICRON
    cron_instance_t *cron_instance=micron_get_instance(CRON_HND_DFL);
    micron_init(cron_instance);
    // disable cron by default (override in boot script)
    micron_set_enable(CRON_HND_DFL, false);
#endif

    // Run boot script
    // - setup and/or start scripts
    // - turn on IO, power bits
    // - configure debug
    // - override configuration
    OUT_CTTY("running boot script...\r\n");
    rc=script_bootstrap(SYS_BOOSTRAP_DFL);
    OUT_CTTY("bootstrap [%s]\r\n",(rc==ERR_SUCCESS?"OK":"ERR"));

    // show the sign-on banner and prompt
    sys_banner();

    serPrintf(SER_CONS,"\r\n");
    UI_PROMPT(SER_CONS);
    serPrintf(SER_HOST,"\r\n");
    UI_PROMPT(SER_HOST);

    //start timer for user time out
    uiStartTmr();

    char tmstr[32]={0};
    Time tms={0},*ptm=&tms;
    uint32_t cycles_since_sleep=0UL;
    // enter main loop
    // (should never exit)
    while (1) {

        if(tkReadClr(TFLAG_2HZ_0)){
            // toggle heartbeat LED at 2Hz
            doBlinkTog();
        }

        // update script state machine
        script_state_update();

#ifdef WITH_MICRON
        // update cron state machine
        micron_state_update(CRON_HND_DFL);
#endif

        //get & do Host command
        ui_host_update();
        //get & do user command
        ui_console_update();

        // get milliseconds until next event
        next_event = sys_next_event();
        cycles_since_sleep++;
        if (uiDidUITO() && (next_event >= SYS_MIN_SLEEP_MSEC )) {
            // sleep if there's time
            // and the UI is timed out
            if(MMOD_IS_EN(MOD_MAIN)){
                memset(ptm,0,sizeof(Time));
                memset(tmstr,0,32);
                rtc_mktime(ptm);
                TM2ISO8601(ptm,tmstr);
                MPRINT(MOD_MAIN,"\r\n%s - %s sleeping css, %lu, nextms, %lu, systk, %lu\r\n",__func__, tmstr,cycles_since_sleep,next_event,tkGetTicks());
                serTxWait(SER_CTTY);
            }
            tkDoIdle(next_event);
            if(MMOD_IS_EN(MOD_MAIN)){
                memset(ptm,0,sizeof(Time));
                memset(tmstr,0,32);
                rtc_mktime(ptm);
                TM2ISO8601(ptm,tmstr);
                MPRINT(MOD_MAIN,"\r\n%s - %s  awake systk, %lu\r\n",__func__,tmstr,tkGetTicks());
            }
            cycles_since_sleep=0;
        }

    }// main loop

    // SHOULD NEVER GET HERE
    return 0;
}
